You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@logging.apache.org by gg...@apache.org on 2018/03/01 00:21:14 UTC

logging-log4j2 git commit: [LOG4J2-2276] ConcurrentModificationException from org.apache.logging.log4j.status.StatusLogger.< clinit>(StatusLogger.java:71).

Repository: logging-log4j2
Updated Branches:
  refs/heads/release-2.x a10da6d43 -> a07176b6a


[LOG4J2-2276] ConcurrentModificationException from
org.apache.logging.log4j.status.StatusLogger.&lt;clinit>(StatusLogger.java:71).

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

Branch: refs/heads/release-2.x
Commit: a07176b6a96eb062a92b6fd167332ea2bb22fbf4
Parents: a10da6d
Author: Gary Gregory <ga...@gmail.com>
Authored: Wed Feb 28 17:21:10 2018 -0700
Committer: Gary Gregory <ga...@gmail.com>
Committed: Wed Feb 28 17:21:10 2018 -0700

----------------------------------------------------------------------
 .../util/SystemPropertiesPropertySource.java    | 19 ++++--
 .../SystemPropertiesPropertySourceTest.java     | 72 ++++++++++++++++++++
 src/changes/changes.xml                         |  3 +
 3 files changed, 90 insertions(+), 4 deletions(-)
----------------------------------------------------------------------


http://git-wip-us.apache.org/repos/asf/logging-log4j2/blob/a07176b6/log4j-api/src/main/java/org/apache/logging/log4j/util/SystemPropertiesPropertySource.java
----------------------------------------------------------------------
diff --git a/log4j-api/src/main/java/org/apache/logging/log4j/util/SystemPropertiesPropertySource.java b/log4j-api/src/main/java/org/apache/logging/log4j/util/SystemPropertiesPropertySource.java
index af10fb0..627b968 100644
--- a/log4j-api/src/main/java/org/apache/logging/log4j/util/SystemPropertiesPropertySource.java
+++ b/log4j-api/src/main/java/org/apache/logging/log4j/util/SystemPropertiesPropertySource.java
@@ -16,7 +16,8 @@
  */
 package org.apache.logging.log4j.util;
 
-import java.util.Map;
+import java.util.Objects;
+import java.util.Properties;
 
 /**
  * PropertySource backed by the current system properties. Other than having a higher priority over normal properties,
@@ -26,17 +27,27 @@ import java.util.Map;
  */
 public class SystemPropertiesPropertySource implements PropertySource {
 
+    private static final int DEFAULT_PRIORITY = 100;
     private static final String PREFIX = "log4j2.";
 
     @Override
     public int getPriority() {
-        return 100;
+        return DEFAULT_PRIORITY;
     }
 
     @Override
     public void forEach(final BiConsumer<String, String> action) {
-        for (final Map.Entry<Object, Object> entry : System.getProperties().entrySet()) {
-            action.accept(((String) entry.getKey()), ((String) entry.getValue()));
+        final Properties properties = System.getProperties();
+        // Lock properties only long enough to get a thread-safe SAFE snapshot of its current keys, an array.
+        final Object[] keySet;
+        synchronized (properties) {
+            keySet = properties.keySet().toArray();
+        }
+        // Then traverse for an unknown amount of time.
+        // Some keys may now be absent, in which case, the value is null.
+        for (final Object key : keySet) {
+            final String keyStr = Objects.toString(key, null);
+            action.accept(keyStr, properties.getProperty(keyStr));
         }
     }
 

http://git-wip-us.apache.org/repos/asf/logging-log4j2/blob/a07176b6/log4j-api/src/test/java/org/apache/logging/log4j/util/SystemPropertiesPropertySourceTest.java
----------------------------------------------------------------------
diff --git a/log4j-api/src/test/java/org/apache/logging/log4j/util/SystemPropertiesPropertySourceTest.java b/log4j-api/src/test/java/org/apache/logging/log4j/util/SystemPropertiesPropertySourceTest.java
new file mode 100644
index 0000000..e492e4a
--- /dev/null
+++ b/log4j-api/src/test/java/org/apache/logging/log4j/util/SystemPropertiesPropertySourceTest.java
@@ -0,0 +1,72 @@
+package org.apache.logging.log4j.util;
+
+import java.util.Properties;
+import java.util.concurrent.ExecutionException;
+import java.util.concurrent.ExecutorService;
+import java.util.concurrent.Executors;
+import java.util.concurrent.Future;
+
+import org.junit.Test;
+
+/*
+ * 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.
+ */
+
+/**
+ * Tests https://issues.apache.org/jira/browse/LOG4J2-2276.
+ */
+public class SystemPropertiesPropertySourceTest {
+
+	private static final int ITERATIONS = 10000;
+
+	/**
+	 * Tests avoiding a ConcurrentModificationException. For example:
+	 * 
+	 * <pre>
+	 * java.util.ConcurrentModificationException
+	 *  at java.util.Hashtable$Enumerator.next(Hashtable.java:1167)
+	 *  at org.apache.logging.log4j.util.SystemPropertiesPropertySource.forEach(SystemPropertiesPropertySource.java:38)
+	 *  at org.apache.logging.log4j.util.SystemPropertiesPropertySourceTest.testMultiThreadedAccess(SystemPropertiesPropertySourceTest.java:47)
+	 * </pre>
+	 */
+	@Test
+	public void testMultiThreadedAccess() throws InterruptedException, ExecutionException {
+		ExecutorService threadPool = Executors.newSingleThreadExecutor();
+		try {
+			Future<?> future = threadPool.submit(new Runnable() {
+
+				@Override
+				public void run() {
+					final Properties properties = System.getProperties();
+					for (int i = 0; i < ITERATIONS; i++) {
+						properties.setProperty("FOO_" + i, "BAR");
+					}
+				}
+			});
+			for (int i = 0; i < ITERATIONS; i++)
+				new SystemPropertiesPropertySource().forEach(new BiConsumer<String, String>() {
+					@Override
+					public void accept(final String key, final String value) {
+						// nothing
+					}
+				});
+			future.get();
+		} finally {
+			threadPool.shutdown();
+		}
+	}
+
+}

http://git-wip-us.apache.org/repos/asf/logging-log4j2/blob/a07176b6/src/changes/changes.xml
----------------------------------------------------------------------
diff --git a/src/changes/changes.xml b/src/changes/changes.xml
index d4bff2b..b8ec985 100644
--- a/src/changes/changes.xml
+++ b/src/changes/changes.xml
@@ -207,6 +207,9 @@
       <action issue="LOG4J2-2270" dev="ggregory" type="fix" due-to="Cyril Martin">
         Strings::join, when called with [null] returns "null" instead of EMPTY.
       </action>      
+      <action issue="LOG4J2-2276" dev="ggregory" type="fix" due-to="Sean Baxter">
+        ConcurrentModificationException from org.apache.logging.log4j.status.StatusLogger.&lt;clinit>(StatusLogger.java:71).
+      </action>      
     </release>
     <release version="2.10.0" date="2017-11-18" description="GA Release 2.10.0">
       <action issue="LOG4J2-2120" dev="mikes" type="add" due-to="Carter Douglas Kozak">