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/02 15:13:51 UTC

logging-log4j2 git commit: LOG4J2-1349 make new ThreadContextMap implementations package-private and introduce factory to instantiate them in ThreadContext

Repository: logging-log4j2
Updated Branches:
  refs/heads/LOG4J2-1349-gcfree-threadcontext e6cf7c909 -> 7aac69c81


LOG4J2-1349 make new ThreadContextMap implementations package-private and introduce factory to instantiate them in ThreadContext


Project: http://git-wip-us.apache.org/repos/asf/logging-log4j2/repo
Commit: http://git-wip-us.apache.org/repos/asf/logging-log4j2/commit/7aac69c8
Tree: http://git-wip-us.apache.org/repos/asf/logging-log4j2/tree/7aac69c8
Diff: http://git-wip-us.apache.org/repos/asf/logging-log4j2/diff/7aac69c8

Branch: refs/heads/LOG4J2-1349-gcfree-threadcontext
Commit: 7aac69c81b2a8cbb8267424c1c6604b08f6009f5
Parents: e6cf7c9
Author: rpopma <rp...@apache.org>
Authored: Sat Sep 3 00:13:43 2016 +0900
Committer: rpopma <rp...@apache.org>
Committed: Sat Sep 3 00:13:43 2016 +0900

----------------------------------------------------------------------
 .../org/apache/logging/log4j/ThreadContext.java | 60 ++-----------
 .../CopyOnWriteSortedArrayThreadContextMap.java |  4 +-
 .../GarbageFreeSortedArrayThreadContextMap.java |  2 +-
 .../log4j/spi/ThreadContextMapFactory.java      | 91 ++++++++++++++++++++
 .../log4j/perf/jmh/ThreadContextBenchmark.java  | 14 ++-
 .../CopyOnWriteOpenHashMapThreadContextMap.java | 42 ---------
 .../GarbageFreeOpenHashMapThreadContextMap.java | 45 ----------
 .../CopyOnWriteOpenHashMapThreadContextMap.java | 44 ++++++++++
 .../GarbageFreeOpenHashMapThreadContextMap.java | 47 ++++++++++
 9 files changed, 196 insertions(+), 153 deletions(-)
----------------------------------------------------------------------


http://git-wip-us.apache.org/repos/asf/logging-log4j2/blob/7aac69c8/log4j-api/src/main/java/org/apache/logging/log4j/ThreadContext.java
----------------------------------------------------------------------
diff --git a/log4j-api/src/main/java/org/apache/logging/log4j/ThreadContext.java b/log4j-api/src/main/java/org/apache/logging/log4j/ThreadContext.java
index bc01bf8..4636469 100644
--- a/log4j-api/src/main/java/org/apache/logging/log4j/ThreadContext.java
+++ b/log4j-api/src/main/java/org/apache/logging/log4j/ThreadContext.java
@@ -27,19 +27,14 @@ import java.util.Map;
 import java.util.NoSuchElementException;
 
 import org.apache.logging.log4j.message.ParameterizedMessage;
-import org.apache.logging.log4j.spi.CopyOnWriteSortedArrayThreadContextMap;
-import org.apache.logging.log4j.spi.DefaultThreadContextMap;
 import org.apache.logging.log4j.spi.DefaultThreadContextStack;
-import org.apache.logging.log4j.spi.GarbageFreeSortedArrayThreadContextMap;
 import org.apache.logging.log4j.spi.NoOpThreadContextMap;
-import org.apache.logging.log4j.spi.Provider;
 import org.apache.logging.log4j.spi.ThreadContextMap;
 import org.apache.logging.log4j.spi.ThreadContextMap2;
+import org.apache.logging.log4j.spi.ThreadContextMapFactory;
 import org.apache.logging.log4j.spi.ThreadContextStack;
 import org.apache.logging.log4j.status.StatusLogger;
-import org.apache.logging.log4j.util.Constants;
 import org.apache.logging.log4j.util.PropertiesUtil;
-import org.apache.logging.log4j.util.ProviderUtil;
 
 /**
  * The ThreadContext allows applications to store information either in a Map or a Stack.
@@ -193,8 +188,6 @@ public final class ThreadContext {
     private static final String DISABLE_MAP = "disableThreadContextMap";
     private static final String DISABLE_STACK = "disableThreadContextStack";
     private static final String DISABLE_ALL = "disableThreadContext";
-    private static final String THREAD_CONTEXT_KEY = "log4j2.threadContextMap";
-    private static final String GC_FREE_THREAD_CONTEXT_KEY = "log4j2.garbagefree.threadContextMap";
 
     private static boolean disableAll;
     private static boolean useMap;
@@ -222,54 +215,11 @@ public final class ThreadContext {
         useMap = !(managerProps.getBooleanProperty(DISABLE_MAP) || disableAll);
 
         contextStack = new DefaultThreadContextStack(useStack);
-        final String threadContextMapName = managerProps.getStringProperty(THREAD_CONTEXT_KEY);
-        final ClassLoader cl = ProviderUtil.findClassLoader();
-        if (threadContextMapName != null) {
-            try {
-                final Class<?> clazz = cl.loadClass(threadContextMapName);
-                if (ThreadContextMap.class.isAssignableFrom(clazz)) {
-                    contextMap = (ThreadContextMap) clazz.newInstance();
-                }
-            } catch (final ClassNotFoundException cnfe) {
-                LOGGER.error("Unable to locate configured ThreadContextMap {}", threadContextMapName);
-            } catch (final Exception ex) {
-                LOGGER.error("Unable to create configured ThreadContextMap {}", threadContextMapName, ex);
-            }
-        }
-        if (contextMap == null && ProviderUtil.hasProviders()) {
-            final String factoryClassName = LogManager.getFactory().getClass().getName();
-            for (final Provider provider : ProviderUtil.getProviders()) {
-                if (factoryClassName.equals(provider.getClassName())) {
-                    final Class<? extends ThreadContextMap> clazz = provider.loadThreadContextMap();
-                    if (clazz != null) {
-                        try {
-                            contextMap = clazz.newInstance();
-                            break;
-                        } catch (final Exception e) {
-                            LOGGER.error("Unable to locate or load configured ThreadContextMap {}",
-                                    provider.getThreadContextMap(), e);
-                            contextMap = createThreadContextMap(useMap);
-                        }
-                    }
-                }
-            }
-        }
-        if (contextMap == null) {
-            contextMap = createThreadContextMap(useMap);
-        }
-    }
-
-    private static ThreadContextMap createThreadContextMap(final boolean doUseMap) {
-        if (!doUseMap) {
-            return new NoOpThreadContextMap();
-        }
-        if (Constants.ENABLE_THREADLOCALS) {
-            if (PropertiesUtil.getProperties().getBooleanProperty(GC_FREE_THREAD_CONTEXT_KEY)) {
-                return new GarbageFreeSortedArrayThreadContextMap();
-            }
-            return new CopyOnWriteSortedArrayThreadContextMap();
+        if (!useMap) {
+            contextMap = new NoOpThreadContextMap();
+        } else {
+            contextMap = ThreadContextMapFactory.createThreadContextMap();
         }
-        return new DefaultThreadContextMap(doUseMap);
     }
 
     /**

http://git-wip-us.apache.org/repos/asf/logging-log4j2/blob/7aac69c8/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 80c0e4d..81c69d5 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
@@ -32,8 +32,8 @@ import org.apache.logging.log4j.util.PropertiesUtil;
  *
  * @since 2.7
  */
-public class CopyOnWriteSortedArrayThreadContextMap implements ThreadContextMap, ThreadContextMap2,
-        CopyOnWrite, MutableContextDataSupplier {
+class CopyOnWriteSortedArrayThreadContextMap implements ThreadContextMap, ThreadContextMap2, CopyOnWrite,
+        MutableContextDataSupplier {
 
     /**
      * The default initial capacity.

http://git-wip-us.apache.org/repos/asf/logging-log4j2/blob/7aac69c8/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 04705dd..cf93367 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
@@ -32,7 +32,7 @@ import org.apache.logging.log4j.util.PropertiesUtil;
  * </p>
  * @since 2.7
  */
-public class GarbageFreeSortedArrayThreadContextMap implements ThreadContextMap, ThreadContextMap2,
+class GarbageFreeSortedArrayThreadContextMap implements ThreadContextMap, ThreadContextMap2,
         MutableContextDataSupplier {
 
     /**

http://git-wip-us.apache.org/repos/asf/logging-log4j2/blob/7aac69c8/log4j-api/src/main/java/org/apache/logging/log4j/spi/ThreadContextMapFactory.java
----------------------------------------------------------------------
diff --git a/log4j-api/src/main/java/org/apache/logging/log4j/spi/ThreadContextMapFactory.java b/log4j-api/src/main/java/org/apache/logging/log4j/spi/ThreadContextMapFactory.java
new file mode 100644
index 0000000..b44f883
--- /dev/null
+++ b/log4j-api/src/main/java/org/apache/logging/log4j/spi/ThreadContextMapFactory.java
@@ -0,0 +1,91 @@
+/*
+ * 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 org.apache.logging.log4j.LogManager;
+import org.apache.logging.log4j.Logger;
+import org.apache.logging.log4j.status.StatusLogger;
+import org.apache.logging.log4j.util.Constants;
+import org.apache.logging.log4j.util.PropertiesUtil;
+import org.apache.logging.log4j.util.ProviderUtil;
+
+/**
+ * Creates the ThreadContextMap instance used by the ThreadContext.
+ *
+ * @see ThreadContextMap
+ * @see org.apache.logging.log4j.ThreadContext
+ * @since 2.7
+ */
+public final class ThreadContextMapFactory {
+    private static final Logger LOGGER = StatusLogger.getLogger();
+    private static final String THREAD_CONTEXT_KEY = "log4j2.threadContextMap";
+    private static final String GC_FREE_THREAD_CONTEXT_KEY = "log4j2.garbagefree.threadContextMap";
+
+    private ThreadContextMapFactory() {
+    }
+
+    public static ThreadContextMap createThreadContextMap() {
+        final PropertiesUtil managerProps = PropertiesUtil.getProperties();
+        final String threadContextMapName = managerProps.getStringProperty(THREAD_CONTEXT_KEY);
+        final ClassLoader cl = ProviderUtil.findClassLoader();
+        ThreadContextMap result = null;
+        if (threadContextMapName != null) {
+            try {
+                final Class<?> clazz = cl.loadClass(threadContextMapName);
+                if (ThreadContextMap.class.isAssignableFrom(clazz)) {
+                    result = (ThreadContextMap) clazz.newInstance();
+                }
+            } catch (final ClassNotFoundException cnfe) {
+                LOGGER.error("Unable to locate configured ThreadContextMap {}", threadContextMapName);
+            } catch (final Exception ex) {
+                LOGGER.error("Unable to create configured ThreadContextMap {}", threadContextMapName, ex);
+            }
+        }
+        if (result == null && ProviderUtil.hasProviders()) {
+            final String factoryClassName = LogManager.getFactory().getClass().getName();
+            for (final Provider provider : ProviderUtil.getProviders()) {
+                if (factoryClassName.equals(provider.getClassName())) {
+                    final Class<? extends ThreadContextMap> clazz = provider.loadThreadContextMap();
+                    if (clazz != null) {
+                        try {
+                            result = clazz.newInstance();
+                            break;
+                        } catch (final Exception e) {
+                            LOGGER.error("Unable to locate or load configured ThreadContextMap {}",
+                                    provider.getThreadContextMap(), e);
+                            result = createDefaultThreadContextMap();
+                        }
+                    }
+                }
+            }
+        }
+        if (result == null) {
+            result = createDefaultThreadContextMap();
+        }
+        return result;
+    }
+
+    private static ThreadContextMap createDefaultThreadContextMap() {
+        if (Constants.ENABLE_THREADLOCALS) {
+            if (PropertiesUtil.getProperties().getBooleanProperty(GC_FREE_THREAD_CONTEXT_KEY)) {
+                return new GarbageFreeSortedArrayThreadContextMap();
+            }
+            return new CopyOnWriteSortedArrayThreadContextMap();
+        }
+        return new DefaultThreadContextMap(true);
+    }
+}

http://git-wip-us.apache.org/repos/asf/logging-log4j2/blob/7aac69c8/log4j-perf/src/main/java/org/apache/logging/log4j/perf/jmh/ThreadContextBenchmark.java
----------------------------------------------------------------------
diff --git a/log4j-perf/src/main/java/org/apache/logging/log4j/perf/jmh/ThreadContextBenchmark.java b/log4j-perf/src/main/java/org/apache/logging/log4j/perf/jmh/ThreadContextBenchmark.java
index 6e07abb..c45f4c6 100644
--- a/log4j-perf/src/main/java/org/apache/logging/log4j/perf/jmh/ThreadContextBenchmark.java
+++ b/log4j-perf/src/main/java/org/apache/logging/log4j/perf/jmh/ThreadContextBenchmark.java
@@ -30,15 +30,13 @@ import org.apache.logging.log4j.ThreadContextBenchmarkAccess;
 import org.apache.logging.log4j.core.config.Property;
 import org.apache.logging.log4j.core.impl.ContextDataInjector;
 import org.apache.logging.log4j.core.impl.ContextDataInjectorFactory;
-import org.apache.logging.log4j.util.ArrayContextData;
-import org.apache.logging.log4j.perf.nogc.CopyOnWriteOpenHashMapThreadContextMap;
-import org.apache.logging.log4j.spi.CopyOnWriteSortedArrayThreadContextMap;
+import org.apache.logging.log4j.perf.nogc.OpenHashMapContextData;
+import org.apache.logging.log4j.spi.CopyOnWriteOpenHashMapThreadContextMap;
 import org.apache.logging.log4j.spi.DefaultThreadContextMap;
-import org.apache.logging.log4j.perf.nogc.GarbageFreeOpenHashMapThreadContextMap;
-import org.apache.logging.log4j.spi.GarbageFreeSortedArrayThreadContextMap;
+import org.apache.logging.log4j.spi.GarbageFreeOpenHashMapThreadContextMap;
 import org.apache.logging.log4j.spi.MutableContextData;
-import org.apache.logging.log4j.perf.nogc.OpenHashMapContextData;
 import org.apache.logging.log4j.spi.ThreadContextMap;
+import org.apache.logging.log4j.util.ArrayContextData;
 import org.openjdk.jmh.annotations.Benchmark;
 import org.openjdk.jmh.annotations.BenchmarkMode;
 import org.openjdk.jmh.annotations.Fork;
@@ -83,9 +81,9 @@ public class ThreadContextBenchmark {
     static {
         IMPLEMENTATIONS.put(DEFAULT_CONTEXT_MAP, DefaultThreadContextMap.class);
         IMPLEMENTATIONS.put(COPY_OPENHASH_MAP, CopyOnWriteOpenHashMapThreadContextMap.class);
-        IMPLEMENTATIONS.put(COPY_ARRAY_MAP, CopyOnWriteSortedArrayThreadContextMap.class);
+        IMPLEMENTATIONS.put(COPY_ARRAY_MAP, CopyOnWriteOpenHashMapThreadContextMap.SUPER); //CopyOnWriteSortedArrayThreadContextMap.class);
         IMPLEMENTATIONS.put(NO_GC_OPENHASH_MAP, GarbageFreeOpenHashMapThreadContextMap.class);
-        IMPLEMENTATIONS.put(NO_GC_ARRAY_MAP, GarbageFreeSortedArrayThreadContextMap.class);
+        IMPLEMENTATIONS.put(NO_GC_ARRAY_MAP, GarbageFreeOpenHashMapThreadContextMap.SUPER); //GarbageFreeSortedArrayThreadContextMap.class);
     }
 
     @Param({ "Default", "CopyOpenHash", "CopySortedArray", "NoGcOpenHash", "NoGcSortedArray"})

http://git-wip-us.apache.org/repos/asf/logging-log4j2/blob/7aac69c8/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
deleted file mode 100644
index e34c031..0000000
--- a/log4j-perf/src/main/java/org/apache/logging/log4j/perf/nogc/CopyOnWriteOpenHashMapThreadContextMap.java
+++ /dev/null
@@ -1,42 +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.perf.nogc;
-
-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;
-
-/**
- * {@code OpenHashMapContextData}-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
- *
- * @since 2.7
- */
-public class CopyOnWriteOpenHashMapThreadContextMap extends CopyOnWriteSortedArrayThreadContextMap {
-    @Override
-    protected MutableContextData createMutableContextData() {
-        return new OpenHashMapContextData<>(PropertiesUtil.getProperties().getIntegerProperty(
-                PROPERTY_NAME_INITIAL_CAPACITY, DEFAULT_INITIAL_CAPACITY));
-    }
-
-    @Override
-    protected MutableContextData createMutableContextData(final ContextData original) {
-        return new OpenHashMapContextData<>(original);
-    }
-}

http://git-wip-us.apache.org/repos/asf/logging-log4j2/blob/7aac69c8/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
deleted file mode 100644
index cb97936..0000000
--- a/log4j-perf/src/main/java/org/apache/logging/log4j/perf/nogc/GarbageFreeOpenHashMapThreadContextMap.java
+++ /dev/null
@@ -1,45 +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.perf.nogc;
-
-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;
-
-/**
- * {@code OpenHashMapContextData}-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.
- * </p>
- *
- * @since 2.7
- */
-public class GarbageFreeOpenHashMapThreadContextMap extends GarbageFreeSortedArrayThreadContextMap {
-    @Override
-    protected MutableContextData createMutableContextData() {
-        return new OpenHashMapContextData<>(PropertiesUtil.getProperties().getIntegerProperty(
-                PROPERTY_NAME_INITIAL_CAPACITY, DEFAULT_INITIAL_CAPACITY));
-    }
-
-    @Override
-    protected MutableContextData createMutableContextData(final ContextData original) {
-        return new OpenHashMapContextData<>(original);
-    }
-}

http://git-wip-us.apache.org/repos/asf/logging-log4j2/blob/7aac69c8/log4j-perf/src/main/java/org/apache/logging/log4j/spi/CopyOnWriteOpenHashMapThreadContextMap.java
----------------------------------------------------------------------
diff --git a/log4j-perf/src/main/java/org/apache/logging/log4j/spi/CopyOnWriteOpenHashMapThreadContextMap.java b/log4j-perf/src/main/java/org/apache/logging/log4j/spi/CopyOnWriteOpenHashMapThreadContextMap.java
new file mode 100644
index 0000000..463e3ed
--- /dev/null
+++ b/log4j-perf/src/main/java/org/apache/logging/log4j/spi/CopyOnWriteOpenHashMapThreadContextMap.java
@@ -0,0 +1,44 @@
+/*
+ * 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 org.apache.logging.log4j.perf.nogc.OpenHashMapContextData;
+import org.apache.logging.log4j.util.PropertiesUtil;
+
+/**
+ * {@code OpenHashMapContextData}-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
+ *
+ * @since 2.7
+ */
+public class CopyOnWriteOpenHashMapThreadContextMap extends CopyOnWriteSortedArrayThreadContextMap {
+
+    /** Constant used in benchmark code */
+    public static final Class<? extends ThreadContextMap> SUPER = CopyOnWriteSortedArrayThreadContextMap.class;
+
+    @Override
+    protected MutableContextData createMutableContextData() {
+        return new OpenHashMapContextData<>(PropertiesUtil.getProperties().getIntegerProperty(
+                PROPERTY_NAME_INITIAL_CAPACITY, DEFAULT_INITIAL_CAPACITY));
+    }
+
+    @Override
+    protected MutableContextData createMutableContextData(final ContextData original) {
+        return new OpenHashMapContextData<>(original);
+    }
+}

http://git-wip-us.apache.org/repos/asf/logging-log4j2/blob/7aac69c8/log4j-perf/src/main/java/org/apache/logging/log4j/spi/GarbageFreeOpenHashMapThreadContextMap.java
----------------------------------------------------------------------
diff --git a/log4j-perf/src/main/java/org/apache/logging/log4j/spi/GarbageFreeOpenHashMapThreadContextMap.java b/log4j-perf/src/main/java/org/apache/logging/log4j/spi/GarbageFreeOpenHashMapThreadContextMap.java
new file mode 100644
index 0000000..5df5dda
--- /dev/null
+++ b/log4j-perf/src/main/java/org/apache/logging/log4j/spi/GarbageFreeOpenHashMapThreadContextMap.java
@@ -0,0 +1,47 @@
+/*
+ * 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 org.apache.logging.log4j.perf.nogc.OpenHashMapContextData;
+import org.apache.logging.log4j.util.PropertiesUtil;
+
+/**
+ * {@code OpenHashMapContextData}-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.
+ * </p>
+ *
+ * @since 2.7
+ */
+public class GarbageFreeOpenHashMapThreadContextMap extends GarbageFreeSortedArrayThreadContextMap {
+
+    /** Constant used in benchmark code */
+    public static final Class<? extends ThreadContextMap> SUPER = GarbageFreeSortedArrayThreadContextMap.class;
+
+    @Override
+    protected MutableContextData createMutableContextData() {
+        return new OpenHashMapContextData<>(PropertiesUtil.getProperties().getIntegerProperty(
+                PROPERTY_NAME_INITIAL_CAPACITY, DEFAULT_INITIAL_CAPACITY));
+    }
+
+    @Override
+    protected MutableContextData createMutableContextData(final ContextData original) {
+        return new OpenHashMapContextData<>(original);
+    }
+}