You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@logging.apache.org by rp...@apache.org on 2016/09/11 06:27:56 UTC
[15/50] logging-log4j2 git commit: LOG4J2-1349 simplified: collapsed
abstract with concrete thread context map classes
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/master
Commit: 4b1668684d92a41f26e185d942bd33550c4c5464
Parents: 65a551e
Author: rpopma <rp...@apache.org>
Authored: Wed Aug 31 21:50:25 2016 +0900
Committer: rpopma <rp...@apache.org>
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(