You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@logging.apache.org by pk...@apache.org on 2024/05/20 10:17:39 UTC

(logging-log4j2) branch feature/2.x/cleanup-thread-context2 updated: Add inheritability to `StringArrayThreadContextMap`

This is an automated email from the ASF dual-hosted git repository.

pkarwasz pushed a commit to branch feature/2.x/cleanup-thread-context2
in repository https://gitbox.apache.org/repos/asf/logging-log4j2.git


The following commit(s) were added to refs/heads/feature/2.x/cleanup-thread-context2 by this push:
     new 80cce5007a Add inheritability to `StringArrayThreadContextMap`
80cce5007a is described below

commit 80cce5007a00bcb6df317071f35b36dbacfd9e5b
Author: Piotr P. Karwasz <pi...@karwasz.org>
AuthorDate: Mon May 20 12:17:32 2024 +0200

    Add inheritability to `StringArrayThreadContextMap`
---
 .../log4j/core/context/ThreadContextMapTest.java   |  4 +-
 .../core/impl/ThreadContextDataInjectorTest.java   |  2 +-
 .../AbstractSortedArrayThreadContextMap.java       |  3 +-
 .../core/context/StringArrayThreadContextMap.java  | 61 ++++++++++++++--------
 4 files changed, 46 insertions(+), 24 deletions(-)

diff --git a/log4j-core-test/src/test/java/org/apache/logging/log4j/core/context/ThreadContextMapTest.java b/log4j-core-test/src/test/java/org/apache/logging/log4j/core/context/ThreadContextMapTest.java
index 7f8e0fa5f9..aff6dd63a4 100644
--- a/log4j-core-test/src/test/java/org/apache/logging/log4j/core/context/ThreadContextMapTest.java
+++ b/log4j-core-test/src/test/java/org/apache/logging/log4j/core/context/ThreadContextMapTest.java
@@ -38,7 +38,9 @@ class ThreadContextMapTest extends AbstractThreadContextMapTest {
         props.setProperty("log4j2.isThreadContextMapInheritable", "true");
         final PropertiesUtil util = new PropertiesUtil(props);
         return Stream.of(
-                new CopyOnWriteSortedArrayThreadContextMap(util), new GarbageFreeSortedArrayThreadContextMap(util));
+                new StringArrayThreadContextMap(util),
+                new CopyOnWriteSortedArrayThreadContextMap(util),
+                new GarbageFreeSortedArrayThreadContextMap(util));
     }
 
     @ParameterizedTest
diff --git a/log4j-core-test/src/test/java/org/apache/logging/log4j/core/impl/ThreadContextDataInjectorTest.java b/log4j-core-test/src/test/java/org/apache/logging/log4j/core/impl/ThreadContextDataInjectorTest.java
index efa723bad0..03c3be708f 100644
--- a/log4j-core-test/src/test/java/org/apache/logging/log4j/core/impl/ThreadContextDataInjectorTest.java
+++ b/log4j-core-test/src/test/java/org/apache/logging/log4j/core/impl/ThreadContextDataInjectorTest.java
@@ -52,7 +52,7 @@ public class ThreadContextDataInjectorTest {
         return asList(new String[][] {
             {"org.apache.logging.log4j.core.context.CopyOnWriteSortedArrayThreadContextMap"},
             {"org.apache.logging.log4j.core.context.GarbageFreeSortedArrayThreadContextMap"},
-            // {"org.apache.logging.log4j.core.context.StringArrayThreadContextMap"}
+            {"org.apache.logging.log4j.core.context.StringArrayThreadContextMap"}
         });
     }
 
diff --git a/log4j-core/src/main/java/org/apache/logging/log4j/core/context/AbstractSortedArrayThreadContextMap.java b/log4j-core/src/main/java/org/apache/logging/log4j/core/context/AbstractSortedArrayThreadContextMap.java
index 508ce701f7..7dcf7d23b1 100644
--- a/log4j-core/src/main/java/org/apache/logging/log4j/core/context/AbstractSortedArrayThreadContextMap.java
+++ b/log4j-core/src/main/java/org/apache/logging/log4j/core/context/AbstractSortedArrayThreadContextMap.java
@@ -31,6 +31,7 @@ import org.jspecify.annotations.Nullable;
 
 /**
  * Commons base class for {@link StringMap}-based implementations of {@code ThreadContextMap}.
+ * @since 2.24.0
  */
 public abstract class AbstractSortedArrayThreadContextMap implements ReadOnlyThreadContextMap, ObjectThreadContextMap {
 
@@ -38,7 +39,7 @@ public abstract class AbstractSortedArrayThreadContextMap implements ReadOnlyThr
      * 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 static final String INHERITABLE_MAP = "isThreadContextMapInheritable";
 
     /**
      * The default initial capacity.
diff --git a/log4j-core/src/main/java/org/apache/logging/log4j/core/context/StringArrayThreadContextMap.java b/log4j-core/src/main/java/org/apache/logging/log4j/core/context/StringArrayThreadContextMap.java
index 0416a00ef3..0fadf2304f 100644
--- a/log4j-core/src/main/java/org/apache/logging/log4j/core/context/StringArrayThreadContextMap.java
+++ b/log4j-core/src/main/java/org/apache/logging/log4j/core/context/StringArrayThreadContextMap.java
@@ -16,12 +16,14 @@
  */
 package org.apache.logging.log4j.core.context;
 
+import java.util.Arrays;
 import java.util.HashMap;
 import java.util.Map;
 import java.util.Objects;
 import org.apache.logging.log4j.core.context.internal.UnmodifiableArrayBackedMap;
 import org.apache.logging.log4j.spi.ThreadContextMap;
 import org.apache.logging.log4j.util.BiConsumer;
+import org.apache.logging.log4j.util.PropertiesUtil;
 import org.apache.logging.log4j.util.ReadOnlyStringMap;
 import org.apache.logging.log4j.util.TriConsumer;
 import org.jspecify.annotations.NullMarked;
@@ -41,31 +43,48 @@ import org.jspecify.annotations.Nullable;
 public class StringArrayThreadContextMap implements ThreadContextMap, ReadOnlyStringMap {
     private static final long serialVersionUID = -2635197170958057849L;
 
-    private ThreadLocal<Object @Nullable []> threadLocalMapState;
+    /**
+     * Property name ({@value} ) for selecting {@code InheritableThreadLocal} (value "true") or plain
+     * {@code ThreadLocal} (value is not "true") in the implementation.
+     */
+    private static final String INHERITABLE_MAP = "isThreadContextMapInheritable";
+
+    private ThreadLocal<Object @Nullable []> localMap;
 
     public StringArrayThreadContextMap() {
-        threadLocalMapState = new ThreadLocal<>();
+        localMap = new ThreadLocal<>();
+    }
+
+    StringArrayThreadContextMap(final PropertiesUtil properties) {
+        localMap = properties.getBooleanProperty(INHERITABLE_MAP)
+                ? new InheritableThreadLocal<Object @Nullable []>() {
+                    @Override
+                    protected Object @Nullable [] childValue(final Object @Nullable [] parentValue) {
+                        return parentValue != null ? Arrays.copyOf(parentValue, parentValue.length) : null;
+                    }
+                }
+                : new ThreadLocal<>();
     }
 
     @Override
     public void put(final String key, final String value) {
-        final Object[] state = threadLocalMapState.get();
+        final Object[] state = localMap.get();
         final UnmodifiableArrayBackedMap modifiedMap =
                 UnmodifiableArrayBackedMap.getInstance(state).copyAndPut(key, value);
-        threadLocalMapState.set(modifiedMap.getBackingArray());
+        localMap.set(modifiedMap.getBackingArray());
     }
 
     @Override
     public void putAll(final Map<String, String> m) {
-        final Object[] state = threadLocalMapState.get();
+        final Object[] state = localMap.get();
         final UnmodifiableArrayBackedMap modifiedMap =
                 UnmodifiableArrayBackedMap.getInstance(state).copyAndPutAll(m);
-        threadLocalMapState.set(modifiedMap.getBackingArray());
+        localMap.set(modifiedMap.getBackingArray());
     }
 
     @Override
     public @Nullable String get(final String key) {
-        final Object[] state = threadLocalMapState.get();
+        final Object[] state = localMap.get();
         if (state == null) {
             return null;
         }
@@ -74,27 +93,27 @@ public class StringArrayThreadContextMap implements ThreadContextMap, ReadOnlySt
 
     @Override
     public void remove(final String key) {
-        final Object[] state = threadLocalMapState.get();
+        final Object[] state = localMap.get();
         if (state != null) {
             final UnmodifiableArrayBackedMap modifiedMap =
                     UnmodifiableArrayBackedMap.getInstance(state).copyAndRemove(key);
-            threadLocalMapState.set(modifiedMap.getBackingArray());
+            localMap.set(modifiedMap.getBackingArray());
         }
     }
 
     @Override
     public void removeAll(final Iterable<String> keys) {
-        final Object[] state = threadLocalMapState.get();
+        final Object[] state = localMap.get();
         if (state != null) {
             final UnmodifiableArrayBackedMap modifiedMap =
                     UnmodifiableArrayBackedMap.getInstance(state).copyAndRemoveAll(keys);
-            threadLocalMapState.set(modifiedMap.getBackingArray());
+            localMap.set(modifiedMap.getBackingArray());
         }
     }
 
     @Override
     public void clear() {
-        threadLocalMapState.remove();
+        localMap.remove();
     }
 
     @Override
@@ -104,13 +123,13 @@ public class StringArrayThreadContextMap implements ThreadContextMap, ReadOnlySt
 
     @Override
     public boolean containsKey(final String key) {
-        final Object @Nullable [] state = threadLocalMapState.get();
+        final Object @Nullable [] state = localMap.get();
         return (state != null && (UnmodifiableArrayBackedMap.getInstance(state)).containsKey(key));
     }
 
     @Override
     public <V> void forEach(final BiConsumer<String, ? super V> action) {
-        final Object[] state = threadLocalMapState.get();
+        final Object[] state = localMap.get();
         if (state == null) {
             return;
         }
@@ -120,7 +139,7 @@ public class StringArrayThreadContextMap implements ThreadContextMap, ReadOnlySt
 
     @Override
     public <V, S> void forEach(final TriConsumer<String, ? super V, S> action, final S state) {
-        final Object[] localState = threadLocalMapState.get();
+        final Object[] localState = localMap.get();
         if (localState == null) {
             return;
         }
@@ -136,7 +155,7 @@ public class StringArrayThreadContextMap implements ThreadContextMap, ReadOnlySt
 
     @Override
     public Map<String, String> getCopy() {
-        final Object[] state = threadLocalMapState.get();
+        final Object[] state = localMap.get();
         if (state == null) {
             return new HashMap<>(0);
         }
@@ -145,7 +164,7 @@ public class StringArrayThreadContextMap implements ThreadContextMap, ReadOnlySt
 
     @Override
     public @Nullable Map<String, String> getImmutableMapOrNull() {
-        final Object[] state = threadLocalMapState.get();
+        final Object[] state = localMap.get();
         return (state == null ? null : UnmodifiableArrayBackedMap.getInstance(state));
     }
 
@@ -156,13 +175,13 @@ public class StringArrayThreadContextMap implements ThreadContextMap, ReadOnlySt
 
     @Override
     public int size() {
-        final Object[] state = threadLocalMapState.get();
+        final Object[] state = localMap.get();
         return UnmodifiableArrayBackedMap.getInstance(state).size();
     }
 
     @Override
     public String toString() {
-        final Object[] state = threadLocalMapState.get();
+        final Object[] state = localMap.get();
         return state == null
                 ? "{}"
                 : UnmodifiableArrayBackedMap.getInstance(state).toString();
@@ -172,7 +191,7 @@ public class StringArrayThreadContextMap implements ThreadContextMap, ReadOnlySt
     public int hashCode() {
         final int prime = 31;
         int result = 1;
-        final Object[] state = threadLocalMapState.get();
+        final Object[] state = localMap.get();
         result = prime * result
                 + ((state == null)
                         ? 0
@@ -192,7 +211,7 @@ public class StringArrayThreadContextMap implements ThreadContextMap, ReadOnlySt
             return false;
         }
         final ThreadContextMap other = (ThreadContextMap) obj;
-        final Map<String, String> map = UnmodifiableArrayBackedMap.getInstance(this.threadLocalMapState.get());
+        final Map<String, String> map = UnmodifiableArrayBackedMap.getInstance(this.localMap.get());
         final Map<String, String> otherMap = other.getImmutableMapOrNull();
         return Objects.equals(map, otherMap);
     }