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

pkarwasz pushed a commit to branch fix/2238_fix_jdk_string_map
in repository https://gitbox.apache.org/repos/asf/logging-log4j2.git

commit f83d1926738ba958e3ecce1715f5c5755b3aa6e3
Author: Piotr P. Karwasz <[email protected]>
AuthorDate: Mon Jan 29 19:56:29 2024 +0100

    Fix regression in `JdkMapAdapterStringMap` performance
    
    We introduce a new constructor for `JdkMapAdapterStringMap` to prevent
    the performance penalty of an exception if the map is immutable.
---
 .../log4j/core/impl/JdkMapAdapterStringMapTest.java      |  1 +
 .../logging/log4j/core/impl/JdkMapAdapterStringMap.java  | 16 +++++++++++++++-
 .../log4j/core/impl/ThreadContextDataInjector.java       | 14 +++++++-------
 .../logging/log4j/core/util/ContextDataProvider.java     |  2 +-
 .../log4j/layout/template/json/util/JsonWriterTest.java  |  4 ++--
 src/changelog/.3.x.x/2238_fix_jdk_string_map.xml         | 10 ++++++++++
 6 files changed, 36 insertions(+), 11 deletions(-)

diff --git 
a/log4j-core-test/src/test/java/org/apache/logging/log4j/core/impl/JdkMapAdapterStringMapTest.java
 
b/log4j-core-test/src/test/java/org/apache/logging/log4j/core/impl/JdkMapAdapterStringMapTest.java
index 65e894814d..39953f0474 100644
--- 
a/log4j-core-test/src/test/java/org/apache/logging/log4j/core/impl/JdkMapAdapterStringMapTest.java
+++ 
b/log4j-core-test/src/test/java/org/apache/logging/log4j/core/impl/JdkMapAdapterStringMapTest.java
@@ -44,6 +44,7 @@ public class JdkMapAdapterStringMapTest {
     @Test
     public void testConstructorDisallowsNull() {
         assertThrows(NullPointerException.class, () -> new 
JdkMapAdapterStringMap(null));
+        assertThrows(NullPointerException.class, () -> new 
JdkMapAdapterStringMap(null, false));
     }
 
     @Test
diff --git 
a/log4j-core/src/main/java/org/apache/logging/log4j/core/impl/JdkMapAdapterStringMap.java
 
b/log4j-core/src/main/java/org/apache/logging/log4j/core/impl/JdkMapAdapterStringMap.java
index 8da3952cd8..b158143093 100644
--- 
a/log4j-core/src/main/java/org/apache/logging/log4j/core/impl/JdkMapAdapterStringMap.java
+++ 
b/log4j-core/src/main/java/org/apache/logging/log4j/core/impl/JdkMapAdapterStringMap.java
@@ -47,9 +47,14 @@ public class JdkMapAdapterStringMap implements StringMap {
     private transient String[] sortedKeys;
 
     public JdkMapAdapterStringMap() {
-        this(new HashMap<String, String>());
+        this(new HashMap<String, String>(), false);
     }
 
+    /**
+     * @deprecated for performance reasons since 2.23.
+     *             Use {@link #JdkMapAdapterStringMap(Map, boolean)} instead.
+     */
+    @Deprecated
     public JdkMapAdapterStringMap(final Map<String, String> map) {
         this.map = Objects.requireNonNull(map, "map");
         try {
@@ -59,6 +64,15 @@ public class JdkMapAdapterStringMap implements StringMap {
         }
     }
 
+    /**
+     * @param map a JDK map,
+     * @param immutable must be {@code true} if the map is immutable or it 
should not be modified.
+     */
+    public JdkMapAdapterStringMap(final Map<String, String> map, final boolean 
immutable) {
+        this.map = Objects.requireNonNull(map, "map");
+        this.immutable = immutable;
+    }
+
     @Override
     public Map<String, String> toMap() {
         return map;
diff --git 
a/log4j-core/src/main/java/org/apache/logging/log4j/core/impl/ThreadContextDataInjector.java
 
b/log4j-core/src/main/java/org/apache/logging/log4j/core/impl/ThreadContextDataInjector.java
index 4df68ce64a..24d8604bca 100644
--- 
a/log4j-core/src/main/java/org/apache/logging/log4j/core/impl/ThreadContextDataInjector.java
+++ 
b/log4j-core/src/main/java/org/apache/logging/log4j/core/impl/ThreadContextDataInjector.java
@@ -121,7 +121,7 @@ public class ThreadContextDataInjector {
             // data. Note that we cannot reuse the specified StringMap: some 
Loggers may have properties defined
             // and others not, so the LogEvent's context data may have been 
replaced with an immutable copy from
             // the ThreadContext - this will throw an 
UnsupportedOperationException if we try to modify it.
-            final StringMap result = new JdkMapAdapterStringMap(new 
HashMap<>(copy));
+            final StringMap result = new JdkMapAdapterStringMap(new 
HashMap<>(copy), false);
             for (int i = 0; i < props.size(); i++) {
                 final Property prop = props.get(i);
                 if (!copy.containsKey(prop.getName())) {
@@ -133,20 +133,20 @@ public class ThreadContextDataInjector {
         }
 
         private static JdkMapAdapterStringMap frozenStringMap(final 
Map<String, String> copy) {
-            final JdkMapAdapterStringMap result = new 
JdkMapAdapterStringMap(copy);
-            result.freeze();
-            return result;
+            return new JdkMapAdapterStringMap(copy, true);
         }
 
         @Override
         public ReadOnlyStringMap rawContextData() {
             final ReadOnlyThreadContextMap map = 
ThreadContext.getThreadContextMap();
-            if (map instanceof ReadOnlyStringMap) {
-                return (ReadOnlyStringMap) map;
+            if (map != null) {
+                return map.getReadOnlyContextData();
             }
             // note: default ThreadContextMap is null
             final Map<String, String> copy = 
ThreadContext.getImmutableContext();
-            return copy.isEmpty() ? 
ContextDataFactory.emptyFrozenContextData() : new JdkMapAdapterStringMap(copy);
+            return copy.isEmpty()
+                    ? ContextDataFactory.emptyFrozenContextData()
+                    : new JdkMapAdapterStringMap(copy, true);
         }
     }
 
diff --git 
a/log4j-core/src/main/java/org/apache/logging/log4j/core/util/ContextDataProvider.java
 
b/log4j-core/src/main/java/org/apache/logging/log4j/core/util/ContextDataProvider.java
index b96967d87f..f4351a9d79 100644
--- 
a/log4j-core/src/main/java/org/apache/logging/log4j/core/util/ContextDataProvider.java
+++ 
b/log4j-core/src/main/java/org/apache/logging/log4j/core/util/ContextDataProvider.java
@@ -36,6 +36,6 @@ public interface ContextDataProvider {
      * @return the context data in a StringMap.
      */
     default StringMap supplyStringMap() {
-        return new JdkMapAdapterStringMap(supplyContextData());
+        return new JdkMapAdapterStringMap(supplyContextData(), true);
     }
 }
diff --git 
a/log4j-layout-template-json-test/src/test/java/org/apache/logging/log4j/layout/template/json/util/JsonWriterTest.java
 
b/log4j-layout-template-json-test/src/test/java/org/apache/logging/log4j/layout/template/json/util/JsonWriterTest.java
index c97ec50b9e..9f672f226a 100644
--- 
a/log4j-layout-template-json-test/src/test/java/org/apache/logging/log4j/layout/template/json/util/JsonWriterTest.java
+++ 
b/log4j-layout-template-json-test/src/test/java/org/apache/logging/log4j/layout/template/json/util/JsonWriterTest.java
@@ -149,7 +149,7 @@ class JsonWriterTest {
 
     @Test
     void test_writeObject_StringMap() {
-        final StringMap map = new 
JdkMapAdapterStringMap(Collections.singletonMap("a", "b"));
+        final StringMap map = new 
JdkMapAdapterStringMap(Collections.singletonMap("a", "b"), true);
         final String expectedJson = "{'a':'b'}".replace('\'', '"');
         final String actualJson = withLockedWriterReturning(writer -> 
writer.use(() -> writer.writeObject(map)));
         Assertions.assertThat(actualJson).isEqualTo(expectedJson);
@@ -224,7 +224,7 @@ class JsonWriterTest {
                                         put("foo", "bar");
                                     }
                                 }),
-                                new 
JdkMapAdapterStringMap(Collections.singletonMap("a", "b"))));
+                                new 
JdkMapAdapterStringMap(Collections.singletonMap("a", "b"), true)));
                 put("key7", (StringBuilderFormattable) buffer -> 
buffer.append(7.7777777777777D));
             }
         };
diff --git a/src/changelog/.3.x.x/2238_fix_jdk_string_map.xml 
b/src/changelog/.3.x.x/2238_fix_jdk_string_map.xml
new file mode 100644
index 0000000000..6c4dd7e4dc
--- /dev/null
+++ b/src/changelog/.3.x.x/2238_fix_jdk_string_map.xml
@@ -0,0 +1,10 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<entry xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance";
+       xmlns="http://logging.apache.org/log4j/changelog";
+       xsi:schemaLocation="http://logging.apache.org/log4j/changelog 
https://logging.apache.org/log4j/changelog-0.1.2.xsd";
+       type="fixed">
+  <issue id="2238" 
link="https://github.com/apache/logging-log4j2/issues/2238"/>
+  <description format="asciidoc">
+    Fix regression in `JdkMapAdapterStringMap` performance.
+  </description>
+</entry>

Reply via email to