LOG4J2-1349 simplified: collapsed abstract with concrete thread context map classes
Project: http://git-wip-us.apache.org/repos/asf/logging-log4j2/repo Commit: http://git-wip-us.apache.org/repos/asf/logging-log4j2/commit/4b166868 Tree: http://git-wip-us.apache.org/repos/asf/logging-log4j2/tree/4b166868 Diff: http://git-wip-us.apache.org/repos/asf/logging-log4j2/diff/4b166868 Branch: refs/heads/LOG4J2-1349-gcfree-threadcontext Commit: 4b1668684d92a41f26e185d942bd33550c4c5464 Parents: 65a551e Author: rpopma <[email protected]> Authored: Wed Aug 31 21:50:25 2016 +0900 Committer: rpopma <[email protected]> Committed: Wed Aug 31 21:50:25 2016 +0900 ---------------------------------------------------------------------- ...AbstractCopyOnWriteMutableThreadContext.java | 191 ------------------ ...AbstractGarbageFreeMutableThreadContext.java | 193 ------------------- .../CopyOnWriteSortedArrayThreadContextMap.java | 183 +++++++++++++++++- .../GarbageFreeSortedArrayThreadContextMap.java | 186 +++++++++++++++++- .../CopyOnWriteOpenHashMapThreadContextMap.java | 4 +- .../GarbageFreeOpenHashMapThreadContextMap.java | 4 +- 6 files changed, 361 insertions(+), 400 deletions(-) ---------------------------------------------------------------------- http://git-wip-us.apache.org/repos/asf/logging-log4j2/blob/4b166868/log4j-api/src/main/java/org/apache/logging/log4j/spi/AbstractCopyOnWriteMutableThreadContext.java ---------------------------------------------------------------------- diff --git a/log4j-api/src/main/java/org/apache/logging/log4j/spi/AbstractCopyOnWriteMutableThreadContext.java b/log4j-api/src/main/java/org/apache/logging/log4j/spi/AbstractCopyOnWriteMutableThreadContext.java deleted file mode 100644 index c71ed95..0000000 --- a/log4j-api/src/main/java/org/apache/logging/log4j/spi/AbstractCopyOnWriteMutableThreadContext.java +++ /dev/null @@ -1,191 +0,0 @@ -/* - * Licensed to the Apache Software Foundation (ASF) under one or more - * contributor license agreements. See the NOTICE file distributed with - * this work for additional information regarding copyright ownership. - * The ASF licenses this file to You under the Apache license, Version 2.0 - * (the "License"); you may not use this file except in compliance with - * the License. You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the license for the specific language governing permissions and - * limitations under the license. - */ -package org.apache.logging.log4j.spi; - -import java.util.Collections; -import java.util.Map; - -import org.apache.logging.log4j.util.PropertiesUtil; - -/** - * ThreadContextMap implementation backed by {@code MutableContextData}. - * A new ThreadContext Map is created each time it is updated and the Map stored is always - * immutable. This means the Map can be passed to other threads without concern that it will be updated. Since it is - * expected that the Map will be passed to many more log events than the number of keys it contains the performance - * should be much better than if the Map was copied for each event. - * - * @since 2.7 - */ -public abstract class AbstractCopyOnWriteMutableThreadContext implements ThreadContextMap, ThreadContextMap2, - CopyOnWrite, MutableContextDataSupplier { - - /** - * The default initial capacity. - */ - protected static final int DEFAULT_INITIAL_CAPACITY = 16; - - /** - * System property name that can be used to control the data structure's initial capacity. - */ - protected static final String PROPERTY_NAME_INITIAL_CAPACITY = "log4j2.ThreadContext.initial.capacity"; - - /** - * Property name ({@value} ) for selecting {@code InheritableThreadLocal} (value "true") or plain - * {@code ThreadLocal} (value is not "true") in the implementation. - */ - public static final String INHERITABLE_MAP = "isThreadContextMapInheritable"; - - private final ThreadLocal<MutableContextData> localMap; - - public AbstractCopyOnWriteMutableThreadContext() { - this.localMap = createThreadLocalMap(); - } - - // LOG4J2-479: by default, use a plain ThreadLocal, only use InheritableThreadLocal if configured. - // (This method is package protected for JUnit tests.) - private ThreadLocal<MutableContextData> createThreadLocalMap() { - final PropertiesUtil managerProps = PropertiesUtil.getProperties(); - final boolean inheritable = managerProps.getBooleanProperty(INHERITABLE_MAP); - if (inheritable) { - return new InheritableThreadLocal<MutableContextData>() { - @Override - protected MutableContextData childValue(final MutableContextData parentValue) { - return parentValue != null ? createMutableContextData(parentValue) : null; - } - }; - } - // if not inheritable, return plain ThreadLocal with null as initial value - return new ThreadLocal<>(); - } - - protected abstract MutableContextData createMutableContextData(); - - protected abstract MutableContextData createMutableContextData(final ContextData original); - - @Override - public void put(final String key, final String value) { - MutableContextData map = localMap.get(); - map = map == null ? createMutableContextData() : createMutableContextData(map); - map.putValue(key, value); - localMap.set(map); - } - - @Override - public void putAll(final Map<String, String> values) { - if (values == null || values.isEmpty()) { - return; - } - MutableContextData map = localMap.get(); - map = map == null ? createMutableContextData() : createMutableContextData(map); - for (final Map.Entry<String, String> entry : values.entrySet()) { - map.putValue(entry.getKey(), entry.getValue()); - } - localMap.set(map); - } - - @Override - public String get(final String key) { - final MutableContextData map = localMap.get(); - return map == null ? null : (String) map.getValue(key); - } - - @Override - public void remove(final String key) { - final MutableContextData map = localMap.get(); - if (map != null) { - final MutableContextData copy = createMutableContextData(map); - copy.remove(key); - localMap.set(copy); - } - } - - @Override - public void clear() { - localMap.remove(); - } - - @Override - public boolean containsKey(final String key) { - final MutableContextData map = localMap.get(); - return map != null && map.containsKey(key); - } - - @Override - public Map<String, String> getCopy() { - final MutableContextData map = localMap.get(); - return map == null ? Collections.<String, String>emptyMap() : map.asMap(); - } - - /** - * {@inheritDoc} - */ - @Override - public MutableContextData getMutableContextData() { - return localMap.get(); - } - - @Override - public Map<String, String> getImmutableMapOrNull() { - final MutableContextData map = localMap.get(); - return map == null ? null : Collections.unmodifiableMap(map.asMap()); - } - - @Override - public boolean isEmpty() { - final MutableContextData map = localMap.get(); - return map == null || map.size() == 0; - } - - @Override - public String toString() { - final MutableContextData map = localMap.get(); - return map == null ? "{}" : map.toString(); - } - - @Override - public int hashCode() { - final int prime = 31; - int result = 1; - final MutableContextData map = this.localMap.get(); - result = prime * result + ((map == null) ? 0 : map.hashCode()); - return result; - } - - @Override - public boolean equals(final Object obj) { - if (this == obj) { - return true; - } - if (obj == null) { - return false; - } - if (!(obj instanceof ThreadContextMap)) { - return false; - } - final ThreadContextMap other = (ThreadContextMap) obj; - final Map<String, String> map = this.getImmutableMapOrNull(); - final Map<String, String> otherMap = other.getImmutableMapOrNull(); - if (map == null) { - if (otherMap != null) { - return false; - } - } else if (!map.equals(otherMap)) { - return false; - } - return true; - } -} http://git-wip-us.apache.org/repos/asf/logging-log4j2/blob/4b166868/log4j-api/src/main/java/org/apache/logging/log4j/spi/AbstractGarbageFreeMutableThreadContext.java ---------------------------------------------------------------------- diff --git a/log4j-api/src/main/java/org/apache/logging/log4j/spi/AbstractGarbageFreeMutableThreadContext.java b/log4j-api/src/main/java/org/apache/logging/log4j/spi/AbstractGarbageFreeMutableThreadContext.java deleted file mode 100644 index 4e86761..0000000 --- a/log4j-api/src/main/java/org/apache/logging/log4j/spi/AbstractGarbageFreeMutableThreadContext.java +++ /dev/null @@ -1,193 +0,0 @@ -/* - * Licensed to the Apache Software Foundation (ASF) under one or more - * contributor license agreements. See the NOTICE file distributed with - * this work for additional information regarding copyright ownership. - * The ASF licenses this file to You under the Apache license, Version 2.0 - * (the "License"); you may not use this file except in compliance with - * the License. You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the license for the specific language governing permissions and - * limitations under the license. - */ -package org.apache.logging.log4j.spi; - -import java.util.Collections; -import java.util.Map; - -import org.apache.logging.log4j.util.PropertiesUtil; - -/** - * Garbage-free ThreadContextMap implementation backed by {@code MutableContextData}. - * <p> - * This implementation does <em>not</em> make a copy of its contents on every operation, so this data structure cannot - * be passed to log events. It is advisable to provide a fast way to copy data from this data structure into log - * events. - * </p> - * @since 2.7 - */ -public abstract class AbstractGarbageFreeMutableThreadContext implements ThreadContextMap, ThreadContextMap2, - MutableContextDataSupplier { - - /** - * The default initial capacity. - */ - protected static final int DEFAULT_INITIAL_CAPACITY = 16; - - /** - * System property name that can be used to control the data structure's initial capacity. - */ - protected static final String PROPERTY_NAME_INITIAL_CAPACITY = "log4j2.ThreadContext.initial.capacity"; - - /** - * Property name ({@value} ) for selecting {@code InheritableThreadLocal} (value "true") or plain - * {@code ThreadLocal} (value is not "true") in the implementation. - */ - public static final String INHERITABLE_MAP = "isThreadContextMapInheritable"; - - private final ThreadLocal<MutableContextData> localMap; - - public AbstractGarbageFreeMutableThreadContext() { - this.localMap = createThreadLocalMap(); - } - - // LOG4J2-479: by default, use a plain ThreadLocal, only use InheritableThreadLocal if configured. - // (This method is package protected for JUnit tests.) - private ThreadLocal<MutableContextData> createThreadLocalMap() { - final PropertiesUtil managerProps = PropertiesUtil.getProperties(); - final boolean inheritable = managerProps.getBooleanProperty(INHERITABLE_MAP); - if (inheritable) { - return new InheritableThreadLocal<MutableContextData>() { - @Override - protected MutableContextData childValue(final MutableContextData parentValue) { - return parentValue != null ? createMutableContextData(parentValue) : null; - } - }; - } - // if not inheritable, return plain ThreadLocal with null as initial value - return new ThreadLocal<>(); - } - - protected abstract MutableContextData createMutableContextData(); - - protected abstract MutableContextData createMutableContextData(final ContextData original); - - private MutableContextData getThreadLocalMap() { - MutableContextData map = localMap.get(); - if (map == null) { - map = createMutableContextData(); - localMap.set(map); - } - return map; - } - - @Override - public void put(final String key, final String value) { - getThreadLocalMap().putValue(key, value); - } - - @Override - public void putAll(final Map<String, String> values) { - if (values == null || values.isEmpty()) { - return; - } - final MutableContextData map = getThreadLocalMap(); - for (final Map.Entry<String, String> entry : values.entrySet()) { - map.putValue(entry.getKey(), entry.getValue()); - } - } - - @Override - public String get(final String key) { - final MutableContextData map = localMap.get(); - return map == null ? null : (String) map.getValue(key); - } - - @Override - public void remove(final String key) { - final MutableContextData map = localMap.get(); - if (map != null) { - map.remove(key); - } - } - - @Override - public void clear() { - localMap.remove(); - } - - @Override - public boolean containsKey(final String key) { - final MutableContextData map = localMap.get(); - return map != null && map.containsKey(key); - } - - @Override - public Map<String, String> getCopy() { - final MutableContextData map = localMap.get(); - return map == null ? Collections.<String, String>emptyMap() : map.asMap(); - } - - /** - * {@inheritDoc} - */ - @Override - public MutableContextData getMutableContextData() { - return localMap.get(); - } - - @Override - public Map<String, String> getImmutableMapOrNull() { - final MutableContextData map = localMap.get(); - return map == null ? null : Collections.unmodifiableMap(map.asMap()); - } - - @Override - public boolean isEmpty() { - final MutableContextData map = localMap.get(); - return map == null || map.size() == 0; - } - - @Override - public String toString() { - final MutableContextData map = localMap.get(); - return map == null ? "{}" : map.toString(); - } - - @Override - public int hashCode() { - final int prime = 31; - int result = 1; - final MutableContextData map = this.localMap.get(); - result = prime * result + ((map == null) ? 0 : map.hashCode()); - return result; - } - - @Override - public boolean equals(final Object obj) { - if (this == obj) { - return true; - } - if (obj == null) { - return false; - } - if (!(obj instanceof ThreadContextMap)) { - return false; - } - final ThreadContextMap other = (ThreadContextMap) obj; - final Map<String, String> map = this.getImmutableMapOrNull(); - final Map<String, String> otherMap = other.getImmutableMapOrNull(); - if (map == null) { - if (otherMap != null) { - return false; - } - } else if (!map.equals(otherMap)) { - return false; - } - return true; - } -} http://git-wip-us.apache.org/repos/asf/logging-log4j2/blob/4b166868/log4j-api/src/main/java/org/apache/logging/log4j/spi/CopyOnWriteSortedArrayThreadContextMap.java ---------------------------------------------------------------------- diff --git a/log4j-api/src/main/java/org/apache/logging/log4j/spi/CopyOnWriteSortedArrayThreadContextMap.java b/log4j-api/src/main/java/org/apache/logging/log4j/spi/CopyOnWriteSortedArrayThreadContextMap.java index f1bf509..afa9d99 100644 --- a/log4j-api/src/main/java/org/apache/logging/log4j/spi/CopyOnWriteSortedArrayThreadContextMap.java +++ b/log4j-api/src/main/java/org/apache/logging/log4j/spi/CopyOnWriteSortedArrayThreadContextMap.java @@ -16,24 +16,197 @@ */ package org.apache.logging.log4j.spi; +import java.util.Collections; +import java.util.Map; + import org.apache.logging.log4j.util.PropertiesUtil; /** - * {@code SortedArrayContextData}-based implementation of the {@code ThreadContextMap} interface that creates a copy of + * {@code ArrayContextData}-based implementation of the {@code ThreadContextMap} interface that creates a copy of * the data structure on every modification. Any particular instance of the data structure is a snapshot of the - * ThreadContext at some point in time and can safely be passed off to other threads + * ThreadContext at some point in time and can safely be passed off to other threads. Since it is + * expected that the Map will be passed to many more log events than the number of keys it contains the performance + * should be much better than if the Map was copied for each event. * * @since 2.7 */ -public class CopyOnWriteSortedArrayThreadContextMap extends AbstractCopyOnWriteMutableThreadContext { - @Override +public class CopyOnWriteSortedArrayThreadContextMap implements ThreadContextMap, ThreadContextMap2, + CopyOnWrite, MutableContextDataSupplier { + + /** + * The default initial capacity. + */ + protected static final int DEFAULT_INITIAL_CAPACITY = 16; + + /** + * System property name that can be used to control the data structure's initial capacity. + */ + protected static final String PROPERTY_NAME_INITIAL_CAPACITY = "log4j2.ThreadContext.initial.capacity"; + + /** + * Property name ({@value} ) for selecting {@code InheritableThreadLocal} (value "true") or plain + * {@code ThreadLocal} (value is not "true") in the implementation. + */ + public static final String INHERITABLE_MAP = "isThreadContextMapInheritable"; + + private final ThreadLocal<MutableContextData> localMap; + + public CopyOnWriteSortedArrayThreadContextMap() { + this.localMap = createThreadLocalMap(); + } + + // LOG4J2-479: by default, use a plain ThreadLocal, only use InheritableThreadLocal if configured. + // (This method is package protected for JUnit tests.) + private ThreadLocal<MutableContextData> createThreadLocalMap() { + final PropertiesUtil managerProps = PropertiesUtil.getProperties(); + final boolean inheritable = managerProps.getBooleanProperty(INHERITABLE_MAP); + if (inheritable) { + return new InheritableThreadLocal<MutableContextData>() { + @Override + protected MutableContextData childValue(final MutableContextData parentValue) { + return parentValue != null ? createMutableContextData(parentValue) : null; + } + }; + } + // if not inheritable, return plain ThreadLocal with null as initial value + return new ThreadLocal<>(); + } + + /** + * Returns an implementation of the {@code MutableContextData} used to back this thread context map. + * <p> + * Subclasses may override. + * </p> + * @return an implementation of the {@code MutableContextData} used to back this thread context map + */ protected MutableContextData createMutableContextData() { return new ArrayContextData(PropertiesUtil.getProperties().getIntegerProperty( PROPERTY_NAME_INITIAL_CAPACITY, DEFAULT_INITIAL_CAPACITY)); } - @Override + /** + * Returns an implementation of the {@code MutableContextData} used to back this thread context map, pre-populated + * with the contents of the specified context data. + * <p> + * Subclasses may override. + * </p> + * @param original the key-value pairs to initialize the returned context data with + * @return an implementation of the {@code MutableContextData} used to back this thread context map + */ protected MutableContextData createMutableContextData(final ContextData original) { return new ArrayContextData(original); } + + @Override + public void put(final String key, final String value) { + MutableContextData map = localMap.get(); + map = map == null ? createMutableContextData() : createMutableContextData(map); + map.putValue(key, value); + localMap.set(map); + } + + @Override + public void putAll(final Map<String, String> values) { + if (values == null || values.isEmpty()) { + return; + } + MutableContextData map = localMap.get(); + map = map == null ? createMutableContextData() : createMutableContextData(map); + for (final Map.Entry<String, String> entry : values.entrySet()) { + map.putValue(entry.getKey(), entry.getValue()); + } + localMap.set(map); + } + + @Override + public String get(final String key) { + final MutableContextData map = localMap.get(); + return map == null ? null : (String) map.getValue(key); + } + + @Override + public void remove(final String key) { + final MutableContextData map = localMap.get(); + if (map != null) { + final MutableContextData copy = createMutableContextData(map); + copy.remove(key); + localMap.set(copy); + } + } + + @Override + public void clear() { + localMap.remove(); + } + + @Override + public boolean containsKey(final String key) { + final MutableContextData map = localMap.get(); + return map != null && map.containsKey(key); + } + + @Override + public Map<String, String> getCopy() { + final MutableContextData map = localMap.get(); + return map == null ? Collections.<String, String>emptyMap() : map.asMap(); + } + + /** + * {@inheritDoc} + */ + @Override + public MutableContextData getMutableContextData() { + return localMap.get(); + } + + @Override + public Map<String, String> getImmutableMapOrNull() { + final MutableContextData map = localMap.get(); + return map == null ? null : Collections.unmodifiableMap(map.asMap()); + } + + @Override + public boolean isEmpty() { + final MutableContextData map = localMap.get(); + return map == null || map.size() == 0; + } + + @Override + public String toString() { + final MutableContextData map = localMap.get(); + return map == null ? "{}" : map.toString(); + } + + @Override + public int hashCode() { + final int prime = 31; + int result = 1; + final MutableContextData map = this.localMap.get(); + result = prime * result + ((map == null) ? 0 : map.hashCode()); + return result; + } + + @Override + public boolean equals(final Object obj) { + if (this == obj) { + return true; + } + if (obj == null) { + return false; + } + if (!(obj instanceof ThreadContextMap)) { + return false; + } + final ThreadContextMap other = (ThreadContextMap) obj; + final Map<String, String> map = this.getImmutableMapOrNull(); + final Map<String, String> otherMap = other.getImmutableMapOrNull(); + if (map == null) { + if (otherMap != null) { + return false; + } + } else if (!map.equals(otherMap)) { + return false; + } + return true; + } } http://git-wip-us.apache.org/repos/asf/logging-log4j2/blob/4b166868/log4j-api/src/main/java/org/apache/logging/log4j/spi/GarbageFreeSortedArrayThreadContextMap.java ---------------------------------------------------------------------- diff --git a/log4j-api/src/main/java/org/apache/logging/log4j/spi/GarbageFreeSortedArrayThreadContextMap.java b/log4j-api/src/main/java/org/apache/logging/log4j/spi/GarbageFreeSortedArrayThreadContextMap.java index 241af5c..5b4a938 100644 --- a/log4j-api/src/main/java/org/apache/logging/log4j/spi/GarbageFreeSortedArrayThreadContextMap.java +++ b/log4j-api/src/main/java/org/apache/logging/log4j/spi/GarbageFreeSortedArrayThreadContextMap.java @@ -16,27 +16,199 @@ */ package org.apache.logging.log4j.spi; +import java.util.Collections; +import java.util.Map; + import org.apache.logging.log4j.util.PropertiesUtil; /** - * {@code SortedArrayContextData}-based implementation of the {@code ThreadContextMap} interface that attempts not to + * {@code ArrayContextData}-based implementation of the {@code ThreadContextMap} interface that attempts not to * create temporary objects. Adding and removing key-value pairs will not create temporary objects. * <p> - * Since the underlying data structure is modified directly it is not suitable for passing by reference to other - * threads. Instead, client code needs to copy the contents when interacting with another thread. + * This implementation does <em>not</em> make a copy of its contents on every operation, so this data structure cannot + * be passed to log events. Instead, client code needs to copy the contents when interacting with another thread. * </p> - * * @since 2.7 */ -public class GarbageFreeSortedArrayThreadContextMap extends AbstractGarbageFreeMutableThreadContext { - @Override +public abstract class GarbageFreeSortedArrayThreadContextMap implements ThreadContextMap, ThreadContextMap2, + MutableContextDataSupplier { + + /** + * The default initial capacity. + */ + protected static final int DEFAULT_INITIAL_CAPACITY = 16; + + /** + * System property name that can be used to control the data structure's initial capacity. + */ + protected static final String PROPERTY_NAME_INITIAL_CAPACITY = "log4j2.ThreadContext.initial.capacity"; + + /** + * Property name ({@value} ) for selecting {@code InheritableThreadLocal} (value "true") or plain + * {@code ThreadLocal} (value is not "true") in the implementation. + */ + public static final String INHERITABLE_MAP = "isThreadContextMapInheritable"; + + private final ThreadLocal<MutableContextData> localMap; + + public GarbageFreeSortedArrayThreadContextMap() { + this.localMap = createThreadLocalMap(); + } + + // LOG4J2-479: by default, use a plain ThreadLocal, only use InheritableThreadLocal if configured. + // (This method is package protected for JUnit tests.) + private ThreadLocal<MutableContextData> createThreadLocalMap() { + final PropertiesUtil managerProps = PropertiesUtil.getProperties(); + final boolean inheritable = managerProps.getBooleanProperty(INHERITABLE_MAP); + if (inheritable) { + return new InheritableThreadLocal<MutableContextData>() { + @Override + protected MutableContextData childValue(final MutableContextData parentValue) { + return parentValue != null ? createMutableContextData(parentValue) : null; + } + }; + } + // if not inheritable, return plain ThreadLocal with null as initial value + return new ThreadLocal<>(); + } + + /** + * Returns an implementation of the {@code MutableContextData} used to back this thread context map. + * <p> + * Subclasses may override. + * </p> + * @return an implementation of the {@code MutableContextData} used to back this thread context map + */ protected MutableContextData createMutableContextData() { return new ArrayContextData(PropertiesUtil.getProperties().getIntegerProperty( PROPERTY_NAME_INITIAL_CAPACITY, DEFAULT_INITIAL_CAPACITY)); } - @Override + /** + * Returns an implementation of the {@code MutableContextData} used to back this thread context map, pre-populated + * with the contents of the specified context data. + * <p> + * Subclasses may override. + * </p> + * @param original the key-value pairs to initialize the returned context data with + * @return an implementation of the {@code MutableContextData} used to back this thread context map + */ protected MutableContextData createMutableContextData(final ContextData original) { return new ArrayContextData(original); } + + private MutableContextData getThreadLocalMap() { + MutableContextData map = localMap.get(); + if (map == null) { + map = createMutableContextData(); + localMap.set(map); + } + return map; + } + + @Override + public void put(final String key, final String value) { + getThreadLocalMap().putValue(key, value); + } + + @Override + public void putAll(final Map<String, String> values) { + if (values == null || values.isEmpty()) { + return; + } + final MutableContextData map = getThreadLocalMap(); + for (final Map.Entry<String, String> entry : values.entrySet()) { + map.putValue(entry.getKey(), entry.getValue()); + } + } + + @Override + public String get(final String key) { + final MutableContextData map = localMap.get(); + return map == null ? null : (String) map.getValue(key); + } + + @Override + public void remove(final String key) { + final MutableContextData map = localMap.get(); + if (map != null) { + map.remove(key); + } + } + + @Override + public void clear() { + localMap.remove(); + } + + @Override + public boolean containsKey(final String key) { + final MutableContextData map = localMap.get(); + return map != null && map.containsKey(key); + } + + @Override + public Map<String, String> getCopy() { + final MutableContextData map = localMap.get(); + return map == null ? Collections.<String, String>emptyMap() : map.asMap(); + } + + /** + * {@inheritDoc} + */ + @Override + public MutableContextData getMutableContextData() { + return localMap.get(); + } + + @Override + public Map<String, String> getImmutableMapOrNull() { + final MutableContextData map = localMap.get(); + return map == null ? null : Collections.unmodifiableMap(map.asMap()); + } + + @Override + public boolean isEmpty() { + final MutableContextData map = localMap.get(); + return map == null || map.size() == 0; + } + + @Override + public String toString() { + final MutableContextData map = localMap.get(); + return map == null ? "{}" : map.toString(); + } + + @Override + public int hashCode() { + final int prime = 31; + int result = 1; + final MutableContextData map = this.localMap.get(); + result = prime * result + ((map == null) ? 0 : map.hashCode()); + return result; + } + + @Override + public boolean equals(final Object obj) { + if (this == obj) { + return true; + } + if (obj == null) { + return false; + } + if (!(obj instanceof ThreadContextMap)) { + return false; + } + final ThreadContextMap other = (ThreadContextMap) obj; + final Map<String, String> map = this.getImmutableMapOrNull(); + final Map<String, String> otherMap = other.getImmutableMapOrNull(); + if (map == null) { + if (otherMap != null) { + return false; + } + } else if (!map.equals(otherMap)) { + return false; + } + return true; + } } http://git-wip-us.apache.org/repos/asf/logging-log4j2/blob/4b166868/log4j-perf/src/main/java/org/apache/logging/log4j/perf/nogc/CopyOnWriteOpenHashMapThreadContextMap.java ---------------------------------------------------------------------- diff --git a/log4j-perf/src/main/java/org/apache/logging/log4j/perf/nogc/CopyOnWriteOpenHashMapThreadContextMap.java b/log4j-perf/src/main/java/org/apache/logging/log4j/perf/nogc/CopyOnWriteOpenHashMapThreadContextMap.java index f219c90..e34c031 100644 --- a/log4j-perf/src/main/java/org/apache/logging/log4j/perf/nogc/CopyOnWriteOpenHashMapThreadContextMap.java +++ b/log4j-perf/src/main/java/org/apache/logging/log4j/perf/nogc/CopyOnWriteOpenHashMapThreadContextMap.java @@ -16,7 +16,7 @@ */ package org.apache.logging.log4j.perf.nogc; -import org.apache.logging.log4j.spi.AbstractCopyOnWriteMutableThreadContext; +import org.apache.logging.log4j.spi.CopyOnWriteSortedArrayThreadContextMap; import org.apache.logging.log4j.spi.ContextData; import org.apache.logging.log4j.spi.MutableContextData; import org.apache.logging.log4j.util.PropertiesUtil; @@ -28,7 +28,7 @@ import org.apache.logging.log4j.util.PropertiesUtil; * * @since 2.7 */ -public class CopyOnWriteOpenHashMapThreadContextMap extends AbstractCopyOnWriteMutableThreadContext { +public class CopyOnWriteOpenHashMapThreadContextMap extends CopyOnWriteSortedArrayThreadContextMap { @Override protected MutableContextData createMutableContextData() { return new OpenHashMapContextData<>(PropertiesUtil.getProperties().getIntegerProperty( http://git-wip-us.apache.org/repos/asf/logging-log4j2/blob/4b166868/log4j-perf/src/main/java/org/apache/logging/log4j/perf/nogc/GarbageFreeOpenHashMapThreadContextMap.java ---------------------------------------------------------------------- diff --git a/log4j-perf/src/main/java/org/apache/logging/log4j/perf/nogc/GarbageFreeOpenHashMapThreadContextMap.java b/log4j-perf/src/main/java/org/apache/logging/log4j/perf/nogc/GarbageFreeOpenHashMapThreadContextMap.java index 400a76c..cb97936 100644 --- a/log4j-perf/src/main/java/org/apache/logging/log4j/perf/nogc/GarbageFreeOpenHashMapThreadContextMap.java +++ b/log4j-perf/src/main/java/org/apache/logging/log4j/perf/nogc/GarbageFreeOpenHashMapThreadContextMap.java @@ -16,7 +16,7 @@ */ package org.apache.logging.log4j.perf.nogc; -import org.apache.logging.log4j.spi.AbstractGarbageFreeMutableThreadContext; +import org.apache.logging.log4j.spi.GarbageFreeSortedArrayThreadContextMap; import org.apache.logging.log4j.spi.ContextData; import org.apache.logging.log4j.spi.MutableContextData; import org.apache.logging.log4j.util.PropertiesUtil; @@ -31,7 +31,7 @@ import org.apache.logging.log4j.util.PropertiesUtil; * * @since 2.7 */ -public class GarbageFreeOpenHashMapThreadContextMap extends AbstractGarbageFreeMutableThreadContext { +public class GarbageFreeOpenHashMapThreadContextMap extends GarbageFreeSortedArrayThreadContextMap { @Override protected MutableContextData createMutableContextData() { return new OpenHashMapContextData<>(PropertiesUtil.getProperties().getIntegerProperty(
