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/04 07:20:36 UTC
[1/5] logging-log4j2 git commit: LOG4J2-1349 add ability to freeze()
context data for use in copy-on-write scenarios
Repository: logging-log4j2
Updated Branches:
refs/heads/LOG4J2-1349-gcfree-threadcontext 7aac69c81 -> 189f87d13
LOG4J2-1349 add ability to freeze() context data for use in copy-on-write scenarios
Project: http://git-wip-us.apache.org/repos/asf/logging-log4j2/repo
Commit: http://git-wip-us.apache.org/repos/asf/logging-log4j2/commit/945bfe04
Tree: http://git-wip-us.apache.org/repos/asf/logging-log4j2/tree/945bfe04
Diff: http://git-wip-us.apache.org/repos/asf/logging-log4j2/diff/945bfe04
Branch: refs/heads/LOG4J2-1349-gcfree-threadcontext
Commit: 945bfe041caa7b645c7f838234b1331a2ab96609
Parents: 7aac69c
Author: rpopma <rp...@apache.org>
Authored: Sun Sep 4 15:53:17 2016 +0900
Committer: rpopma <rp...@apache.org>
Committed: Sun Sep 4 15:53:17 2016 +0900
----------------------------------------------------------------------
.../org/apache/logging/log4j/spi/MutableContextData.java | 11 +++++++++++
1 file changed, 11 insertions(+)
----------------------------------------------------------------------
http://git-wip-us.apache.org/repos/asf/logging-log4j2/blob/945bfe04/log4j-api/src/main/java/org/apache/logging/log4j/spi/MutableContextData.java
----------------------------------------------------------------------
diff --git a/log4j-api/src/main/java/org/apache/logging/log4j/spi/MutableContextData.java b/log4j-api/src/main/java/org/apache/logging/log4j/spi/MutableContextData.java
index 8bc64e8..1ee60c9 100644
--- a/log4j-api/src/main/java/org/apache/logging/log4j/spi/MutableContextData.java
+++ b/log4j-api/src/main/java/org/apache/logging/log4j/spi/MutableContextData.java
@@ -65,4 +65,15 @@ public interface MutableContextData extends ContextData {
* {@link #forEach(TriConsumer, Object)}.
*/
void remove(final String key);
+
+ /**
+ * Ensures that further changes to this object are ignored.
+ */
+ void freeze();
+
+ /**
+ * Returns {@code true} if this object has been {@linkplain #freeze() frozen}, {@code false} otherwise.
+ * @return {@code true} if this object has been {@linkplain #freeze() frozen}, {@code false} otherwise
+ */
+ boolean isFrozen();
}
\ No newline at end of file
[4/5] logging-log4j2 git commit: LOG4J2-1349 bugfix: putAll() should
not overwrite existing values
Posted by rp...@apache.org.
LOG4J2-1349 bugfix: putAll() should not overwrite existing values
Project: http://git-wip-us.apache.org/repos/asf/logging-log4j2/repo
Commit: http://git-wip-us.apache.org/repos/asf/logging-log4j2/commit/863cc124
Tree: http://git-wip-us.apache.org/repos/asf/logging-log4j2/tree/863cc124
Diff: http://git-wip-us.apache.org/repos/asf/logging-log4j2/diff/863cc124
Branch: refs/heads/LOG4J2-1349-gcfree-threadcontext
Commit: 863cc124dfdc0fe05128a8c144c6413f92b5d99f
Parents: e59f15f
Author: rpopma <rp...@apache.org>
Authored: Sun Sep 4 15:56:02 2016 +0900
Committer: rpopma <rp...@apache.org>
Committed: Sun Sep 4 15:56:02 2016 +0900
----------------------------------------------------------------------
.../main/java/org/apache/logging/log4j/util/ArrayContextData.java | 2 +-
1 file changed, 1 insertion(+), 1 deletion(-)
----------------------------------------------------------------------
http://git-wip-us.apache.org/repos/asf/logging-log4j2/blob/863cc124/log4j-api/src/main/java/org/apache/logging/log4j/util/ArrayContextData.java
----------------------------------------------------------------------
diff --git a/log4j-api/src/main/java/org/apache/logging/log4j/util/ArrayContextData.java b/log4j-api/src/main/java/org/apache/logging/log4j/util/ArrayContextData.java
index 3b665b3..01b2c8c 100644
--- a/log4j-api/src/main/java/org/apache/logging/log4j/util/ArrayContextData.java
+++ b/log4j-api/src/main/java/org/apache/logging/log4j/util/ArrayContextData.java
@@ -243,7 +243,7 @@ public class ArrayContextData implements MutableContextData, ThreadContextMap {
assertNotFrozen();
assertNoConcurrentModification();
- if (source instanceof ArrayContextData) {
+ if (source instanceof ArrayContextData && this.size == 0) {
initFrom0((ArrayContextData) source);
} else if (source != null) {
if (source == this) {
[2/5] logging-log4j2 git commit: LOG4J2-1349 freeze context data so
that shared copies cannot be modified
Posted by rp...@apache.org.
LOG4J2-1349 freeze context data so that shared copies cannot be modified
Project: http://git-wip-us.apache.org/repos/asf/logging-log4j2/repo
Commit: http://git-wip-us.apache.org/repos/asf/logging-log4j2/commit/950b62f6
Tree: http://git-wip-us.apache.org/repos/asf/logging-log4j2/tree/950b62f6
Diff: http://git-wip-us.apache.org/repos/asf/logging-log4j2/diff/950b62f6
Branch: refs/heads/LOG4J2-1349-gcfree-threadcontext
Commit: 950b62f6272ea1d6a44d49320614f5113ff8aea2
Parents: 945bfe0
Author: rpopma <rp...@apache.org>
Authored: Sun Sep 4 15:54:02 2016 +0900
Committer: rpopma <rp...@apache.org>
Committed: Sun Sep 4 15:54:02 2016 +0900
----------------------------------------------------------------------
.../logging/log4j/spi/CopyOnWriteSortedArrayThreadContextMap.java | 3 +++
1 file changed, 3 insertions(+)
----------------------------------------------------------------------
http://git-wip-us.apache.org/repos/asf/logging-log4j2/blob/950b62f6/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 81c69d5..57348dd 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
@@ -104,6 +104,7 @@ class CopyOnWriteSortedArrayThreadContextMap implements ThreadContextMap, Thread
MutableContextData map = localMap.get();
map = map == null ? createMutableContextData() : createMutableContextData(map);
map.putValue(key, value);
+ map.freeze();
localMap.set(map);
}
@@ -117,6 +118,7 @@ class CopyOnWriteSortedArrayThreadContextMap implements ThreadContextMap, Thread
for (final Map.Entry<String, String> entry : values.entrySet()) {
map.putValue(entry.getKey(), entry.getValue());
}
+ map.freeze();
localMap.set(map);
}
@@ -132,6 +134,7 @@ class CopyOnWriteSortedArrayThreadContextMap implements ThreadContextMap, Thread
if (map != null) {
final MutableContextData copy = createMutableContextData(map);
copy.remove(key);
+ copy.freeze();
localMap.set(copy);
}
}
[3/5] logging-log4j2 git commit: LOG4J2-1349 implement support for
freeze() and isFrozen(); add tests
Posted by rp...@apache.org.
LOG4J2-1349 implement support for freeze() and isFrozen(); add tests
Project: http://git-wip-us.apache.org/repos/asf/logging-log4j2/repo
Commit: http://git-wip-us.apache.org/repos/asf/logging-log4j2/commit/e59f15f6
Tree: http://git-wip-us.apache.org/repos/asf/logging-log4j2/tree/e59f15f6
Diff: http://git-wip-us.apache.org/repos/asf/logging-log4j2/diff/e59f15f6
Branch: refs/heads/LOG4J2-1349-gcfree-threadcontext
Commit: e59f15f65a7b1b39f0f61b9b7e2b3f28ada387c0
Parents: 950b62f
Author: rpopma <rp...@apache.org>
Authored: Sun Sep 4 15:55:10 2016 +0900
Committer: rpopma <rp...@apache.org>
Committed: Sun Sep 4 15:55:10 2016 +0900
----------------------------------------------------------------------
.../logging/log4j/util/ArrayContextData.java | 63 +++++-
.../log4j/util/ArrayContextDataTest.java | 208 +++++++++++++++++++
2 files changed, 267 insertions(+), 4 deletions(-)
----------------------------------------------------------------------
http://git-wip-us.apache.org/repos/asf/logging-log4j2/blob/e59f15f6/log4j-api/src/main/java/org/apache/logging/log4j/util/ArrayContextData.java
----------------------------------------------------------------------
diff --git a/log4j-api/src/main/java/org/apache/logging/log4j/util/ArrayContextData.java b/log4j-api/src/main/java/org/apache/logging/log4j/util/ArrayContextData.java
index bdc9951..3b665b3 100644
--- a/log4j-api/src/main/java/org/apache/logging/log4j/util/ArrayContextData.java
+++ b/log4j-api/src/main/java/org/apache/logging/log4j/util/ArrayContextData.java
@@ -20,6 +20,7 @@ import java.io.IOException;
import java.io.InvalidObjectException;
import java.util.Arrays;
import java.util.Collections;
+import java.util.ConcurrentModificationException;
import java.util.HashMap;
import java.util.Map;
import java.util.Objects;
@@ -70,6 +71,7 @@ public class ArrayContextData implements MutableContextData, ThreadContextMap {
* An empty array instance to share when the table is not inflated.
*/
private static final String[] EMPTY = {};
+ private static final String FROZEN = "Frozen collection cannot be modified";
private transient String[] keys = EMPTY;
private transient Object[] values = EMPTY;
@@ -86,6 +88,8 @@ public class ArrayContextData implements MutableContextData, ThreadContextMap {
// If table == EMPTY_TABLE then this is the initial capacity at which the
// table will be created when inflated.
private int threshold;
+ private boolean immutable;
+ private transient boolean iterating;
public ArrayContextData() {
this(DEFAULT_INITIAL_CAPACITY);
@@ -107,8 +111,26 @@ public class ArrayContextData implements MutableContextData, ThreadContextMap {
}
}
+ private void assertNotFrozen() {
+ if (immutable) {
+ throw new UnsupportedOperationException(FROZEN);
+ }
+ }
+
+ private void assertNoConcurrentModification() {
+ if (iterating) {
+ throw new ConcurrentModificationException();
+ }
+ }
+
@Override
public void clear() {
+ if (keys == EMPTY) {
+ return;
+ }
+ assertNotFrozen();
+ assertNoConcurrentModification();
+
Arrays.fill(keys, 0, size, null);
Arrays.fill(values, 0, size, null);
size = 0;
@@ -130,6 +152,16 @@ public class ArrayContextData implements MutableContextData, ThreadContextMap {
}
@Override
+ public void freeze() {
+ immutable = true;
+ }
+
+ @Override
+ public boolean isFrozen() {
+ return immutable;
+ }
+
+ @Override
public Map<String, String> getCopy() {
return asMap();
}
@@ -182,6 +214,9 @@ public class ArrayContextData implements MutableContextData, ThreadContextMap {
@Override
public void putValue(final String key, final Object value) {
+ assertNotFrozen();
+ assertNoConcurrentModification();
+
if (keys == EMPTY) {
inflateTable(threshold);
}
@@ -205,9 +240,15 @@ public class ArrayContextData implements MutableContextData, ThreadContextMap {
@Override
public void putAll(final ContextData source) {
+ assertNotFrozen();
+ assertNoConcurrentModification();
+
if (source instanceof ArrayContextData) {
initFrom0((ArrayContextData) source);
} else if (source != null) {
+ if (source == this) {
+ return; // this.putAll(this) does not modify this collection
+ }
source.forEach(PUT_ALL, this);
}
}
@@ -261,8 +302,12 @@ public class ArrayContextData implements MutableContextData, ThreadContextMap {
if (keys == EMPTY) {
return;
}
+
final int index = indexOfKey(key);
if (index >= 0) {
+ assertNotFrozen();
+ assertNoConcurrentModification();
+
System.arraycopy(keys, index + 1, keys, index, size - index);
System.arraycopy(values, index + 1, values, index, size - index);
size--;
@@ -292,16 +337,26 @@ public class ArrayContextData implements MutableContextData, ThreadContextMap {
@SuppressWarnings("unchecked")
@Override
public <V> void forEach(BiConsumer<String, ? super V> action) {
- for (int i = 0; i < size; i++) {
- action.accept(keys[i], (V) values[i]);
+ iterating = true;
+ try {
+ for (int i = 0; i < size; i++) {
+ action.accept(keys[i], (V) values[i]);
+ }
+ } finally {
+ iterating = false;
}
}
@SuppressWarnings("unchecked")
@Override
public <V, T> void forEach(TriConsumer<String, ? super V, T> action, T state) {
- for (int i = 0; i < size; i++) {
- action.accept(keys[i], (V) values[i], state);
+ iterating = true;
+ try {
+ for (int i = 0; i < size; i++) {
+ action.accept(keys[i], (V) values[i], state);
+ }
+ } finally {
+ iterating = false;
}
}
http://git-wip-us.apache.org/repos/asf/logging-log4j2/blob/e59f15f6/log4j-api/src/test/java/org/apache/logging/log4j/util/ArrayContextDataTest.java
----------------------------------------------------------------------
diff --git a/log4j-api/src/test/java/org/apache/logging/log4j/util/ArrayContextDataTest.java b/log4j-api/src/test/java/org/apache/logging/log4j/util/ArrayContextDataTest.java
index e3ac0a4..ae79888 100644
--- a/log4j-api/src/test/java/org/apache/logging/log4j/util/ArrayContextDataTest.java
+++ b/log4j-api/src/test/java/org/apache/logging/log4j/util/ArrayContextDataTest.java
@@ -21,6 +21,7 @@ import java.io.IOException;
import java.io.ObjectInputStream;
import java.io.ObjectOutputStream;
import java.lang.reflect.Field;
+import java.util.ConcurrentModificationException;
import java.util.HashMap;
import java.util.Map;
@@ -181,6 +182,213 @@ public class ArrayContextDataTest {
}
@Test
+ public void testPutAll_KeepsExistingValues() {
+ final ArrayContextData original = new ArrayContextData();
+ original.put("a", "aaa");
+ original.put("b", "bbb");
+ original.put("c", "ccc");
+ assertEquals("size", 3, original.size());
+
+ // add empty context data
+ original.putAll(new ArrayContextData());
+ assertEquals("size after put empty", 3, original.size());
+ assertEquals("aaa", original.get("a"));
+ assertEquals("bbb", original.get("b"));
+ assertEquals("ccc", original.get("c"));
+
+ final ArrayContextData other = new ArrayContextData();
+ other.put("1", "111");
+ other.put("2", "222");
+ other.put("3", "333");
+ original.putAll(other);
+
+ assertEquals("size after put other", 6, original.size());
+ assertEquals("aaa", original.get("a"));
+ assertEquals("bbb", original.get("b"));
+ assertEquals("ccc", original.get("c"));
+ assertEquals("111", original.get("1"));
+ assertEquals("222", original.get("2"));
+ assertEquals("333", original.get("3"));
+ }
+
+ @Test
+ public void testPutAllSelfDoesNotModify() {
+ final ArrayContextData original = new ArrayContextData();
+ original.put("a", "aaa");
+ original.put("b", "bbb");
+ original.put("c", "ccc");
+ assertEquals("size", 3, original.size());
+
+ // putAll with self
+ original.putAll(original);
+ assertEquals("size after put empty", 3, original.size());
+ assertEquals("aaa", original.get("a"));
+ assertEquals("bbb", original.get("b"));
+ assertEquals("ccc", original.get("c"));
+ }
+
+ @Test(expected = ConcurrentModificationException.class)
+ public void testConcurrentModificationBiConsumerPut() {
+ final ArrayContextData original = new ArrayContextData();
+ original.put("a", "aaa");
+ original.forEach(new BiConsumer<String, Object>() {
+ @Override
+ public void accept(final String s, final Object o) {
+ original.put("c", "other");
+ }
+ });
+ }
+
+ @Test(expected = ConcurrentModificationException.class)
+ public void testConcurrentModificationBiConsumerPutValue() {
+ final ArrayContextData original = new ArrayContextData();
+ original.put("a", "aaa");
+ original.forEach(new BiConsumer<String, Object>() {
+ @Override
+ public void accept(final String s, final Object o) {
+ original.putValue("c", "other");
+ }
+ });
+ }
+
+ @Test(expected = ConcurrentModificationException.class)
+ public void testConcurrentModificationBiConsumerRemove() {
+ final ArrayContextData original = new ArrayContextData();
+ original.put("a", "aaa");
+ original.forEach(new BiConsumer<String, Object>() {
+ @Override
+ public void accept(final String s, final Object o) {
+ original.remove("a");
+ }
+ });
+ }
+
+ @Test(expected = ConcurrentModificationException.class)
+ public void testConcurrentModificationBiConsumerClear() {
+ final ArrayContextData original = new ArrayContextData();
+ original.put("a", "aaa");
+ original.forEach(new BiConsumer<String, Object>() {
+ @Override
+ public void accept(final String s, final Object o) {
+ original.clear();
+ }
+ });
+ }
+
+ @Test(expected = ConcurrentModificationException.class)
+ public void testConcurrentModificationTriConsumerPut() {
+ final ArrayContextData original = new ArrayContextData();
+ original.put("a", "aaa");
+ original.forEach(new TriConsumer<String, Object, Object>() {
+ @Override
+ public void accept(final String s, final Object o, final Object o2) {
+ original.put("c", "other");
+ }
+ }, null);
+ }
+
+ @Test(expected = ConcurrentModificationException.class)
+ public void testConcurrentModificationTriConsumerPutValue() {
+ final ArrayContextData original = new ArrayContextData();
+ original.put("a", "aaa");
+ original.forEach(new TriConsumer<String, Object, Object>() {
+ @Override
+ public void accept(final String s, final Object o, final Object o2) {
+ original.putValue("c", "other");
+ }
+ }, null);
+ }
+
+ @Test(expected = ConcurrentModificationException.class)
+ public void testConcurrentModificationTriConsumerRemove() {
+ final ArrayContextData original = new ArrayContextData();
+ original.put("a", "aaa");
+ original.forEach(new TriConsumer<String, Object, Object>() {
+ @Override
+ public void accept(final String s, final Object o, final Object o2) {
+ original.remove("a");
+ }
+ }, null);
+ }
+
+ @Test(expected = ConcurrentModificationException.class)
+ public void testConcurrentModificationTriConsumerClear() {
+ final ArrayContextData original = new ArrayContextData();
+ original.put("a", "aaa");
+ original.forEach(new TriConsumer<String, Object, Object>() {
+ @Override
+ public void accept(final String s, final Object o, final Object o2) {
+ original.clear();
+ }
+ }, null);
+ }
+
+ @Test
+ public void testInitiallyNotFrozen() {
+ assertFalse(new ArrayContextData().isFrozen());
+ }
+
+ @Test
+ public void testIsFrozenAfterCallingFreeze() {
+ final ArrayContextData original = new ArrayContextData();
+ assertFalse("before freeze", original.isFrozen());
+ original.freeze();
+ assertTrue("after freeze", original.isFrozen());
+ }
+
+ @Test(expected = UnsupportedOperationException.class)
+ public void testFreezeProhibitsPut() {
+ final ArrayContextData original = new ArrayContextData();
+ original.freeze();
+ original.put("a", "aaa");
+ }
+
+ @Test(expected = UnsupportedOperationException.class)
+ public void testFreezeProhibitsPutValue() {
+ final ArrayContextData original = new ArrayContextData();
+ original.freeze();
+ original.putValue("a", "aaa");
+ }
+
+ @Test(expected = UnsupportedOperationException.class)
+ public void testFreezeProhibitsRemove() {
+ final ArrayContextData original = new ArrayContextData();
+ original.put("b", "bbb");
+ original.freeze();
+ original.remove("b"); // existing key: modifies the collection
+ }
+
+ @Test
+ public void testFreezeAllowsRemoveOfNonExistingKey() {
+ final ArrayContextData original = new ArrayContextData();
+ original.put("b", "bbb");
+ original.freeze();
+ original.remove("a"); // no actual modification
+ }
+
+ @Test
+ public void testFreezeAllowsRemoveIfEmpty() {
+ final ArrayContextData original = new ArrayContextData();
+ original.freeze();
+ original.remove("a"); // no exception
+ }
+
+ @Test(expected = UnsupportedOperationException.class)
+ public void testFreezeProhibitsClear() {
+ final ArrayContextData original = new ArrayContextData();
+ original.put("a", "aaa");
+ original.freeze();
+ original.clear();
+ }
+
+ @Test
+ public void testFreezeAllowsClearIfEmpty() {
+ final ArrayContextData original = new ArrayContextData();
+ original.freeze();
+ original.clear();
+ }
+
+ @Test
public void testPutInsertsInAlphabeticOrder() throws Exception {
final ArrayContextData original = new ArrayContextData();
original.put("a", "avalue");
[5/5] logging-log4j2 git commit: LOG4J2-1349 log event
implementations should not try to modify shared copies of copy-on-write
context data
Posted by rp...@apache.org.
LOG4J2-1349 log event implementations should not try to modify shared copies of copy-on-write context data
Project: http://git-wip-us.apache.org/repos/asf/logging-log4j2/repo
Commit: http://git-wip-us.apache.org/repos/asf/logging-log4j2/commit/189f87d1
Tree: http://git-wip-us.apache.org/repos/asf/logging-log4j2/tree/189f87d1
Diff: http://git-wip-us.apache.org/repos/asf/logging-log4j2/diff/189f87d1
Branch: refs/heads/LOG4J2-1349-gcfree-threadcontext
Commit: 189f87d138d9e7f7df05468c60a011f29298919e
Parents: 863cc12
Author: rpopma <rp...@apache.org>
Authored: Sun Sep 4 16:07:17 2016 +0900
Committer: rpopma <rp...@apache.org>
Committed: Sun Sep 4 16:07:17 2016 +0900
----------------------------------------------------------------------
.../apache/logging/log4j/core/async/RingBufferLogEvent.java | 8 +++++++-
.../org/apache/logging/log4j/core/impl/Log4jLogEvent.java | 7 ++++++-
.../org/apache/logging/log4j/core/impl/MutableLogEvent.java | 6 +++++-
3 files changed, 18 insertions(+), 3 deletions(-)
----------------------------------------------------------------------
http://git-wip-us.apache.org/repos/asf/logging-log4j2/blob/189f87d1/log4j-core/src/main/java/org/apache/logging/log4j/core/async/RingBufferLogEvent.java
----------------------------------------------------------------------
diff --git a/log4j-core/src/main/java/org/apache/logging/log4j/core/async/RingBufferLogEvent.java b/log4j-core/src/main/java/org/apache/logging/log4j/core/async/RingBufferLogEvent.java
index d20be14..423578c 100644
--- a/log4j-core/src/main/java/org/apache/logging/log4j/core/async/RingBufferLogEvent.java
+++ b/log4j-core/src/main/java/org/apache/logging/log4j/core/async/RingBufferLogEvent.java
@@ -381,9 +381,15 @@ public class RingBufferLogEvent implements LogEvent, ReusableMessage, CharSequen
this.message = null;
this.thrown = null;
this.thrownProxy = null;
- this.contextData.clear();
this.contextStack = null;
this.location = null;
+ if (contextData != null) {
+ if (contextData.isFrozen()) { // came from CopyOnWrite thread context
+ contextData = null;
+ } else {
+ contextData.clear();
+ }
+ }
trimMessageText();
http://git-wip-us.apache.org/repos/asf/logging-log4j2/blob/189f87d1/log4j-core/src/main/java/org/apache/logging/log4j/core/impl/Log4jLogEvent.java
----------------------------------------------------------------------
diff --git a/log4j-core/src/main/java/org/apache/logging/log4j/core/impl/Log4jLogEvent.java b/log4j-core/src/main/java/org/apache/logging/log4j/core/impl/Log4jLogEvent.java
index 8e152f3..19b7afd 100644
--- a/log4j-core/src/main/java/org/apache/logging/log4j/core/impl/Log4jLogEvent.java
+++ b/log4j-core/src/main/java/org/apache/logging/log4j/core/impl/Log4jLogEvent.java
@@ -132,8 +132,13 @@ public class Log4jLogEvent implements LogEvent {
if (other.getContextData() instanceof MutableContextData) {
this.contextData = (MutableContextData) other.getContextData();
} else {
- this.contextData.clear();
+ if (this.contextData.isFrozen()) {
+ this.contextData = ContextDataFactory.createContextData();
+ } else {
+ this.contextData.clear();
+ }
this.contextData.putAll(other.getContextData());
+
}
this.thrownProxy = other.getThrownProxy();
this.source = other.getSource();
http://git-wip-us.apache.org/repos/asf/logging-log4j2/blob/189f87d1/log4j-core/src/main/java/org/apache/logging/log4j/core/impl/MutableLogEvent.java
----------------------------------------------------------------------
diff --git a/log4j-core/src/main/java/org/apache/logging/log4j/core/impl/MutableLogEvent.java b/log4j-core/src/main/java/org/apache/logging/log4j/core/impl/MutableLogEvent.java
index 97cb5d6..2a4f59b 100644
--- a/log4j-core/src/main/java/org/apache/logging/log4j/core/impl/MutableLogEvent.java
+++ b/log4j-core/src/main/java/org/apache/logging/log4j/core/impl/MutableLogEvent.java
@@ -120,7 +120,11 @@ public class MutableLogEvent implements LogEvent, ReusableMessage {
thrownProxy = null;
source = null;
if (contextData != null) {
- contextData.clear();
+ if (contextData.isFrozen()) { // came from CopyOnWrite thread context
+ contextData = null;
+ } else {
+ contextData.clear();
+ }
}
contextStack = null;