On Tue, Jan 23, 2018 at 3:01 PM, Remko Popma <remko.po...@gmail.com> wrote:
> This solution should work. Thanks for taking care of this, Gary! > > One thing, why are the new fields capitalized? It makes the field names > look like class names in the code. I’ve never seen that convention. Should > they not be simply lower case? > Hm... I use ALL_CAPS when the fields are final (constants). An instance var is camelCase and a static var is CamelCase. Then you can tell what is what. Should I change static vars to camelCase? Gary > (Shameless plug) Every java main() method deserves http://picocli.info > > > On Jan 24, 2018, at 6:20, ggreg...@apache.org wrote: > > > > Repository: logging-log4j2 > > Updated Branches: > > refs/heads/master 81d12ad14 -> 93e97932c > > > > > > [LOG4J2-2212]Unnecessary contention in > > CopyOnWriteSortedArrayThreadContextMap. > > [LOG4J2-2213] Unnecessary contention in > > GarbageFreeSortedArrayThreadContextMap. > > > > Project: http://git-wip-us.apache.org/repos/asf/logging-log4j2/repo > > Commit: http://git-wip-us.apache.org/repos/asf/logging-log4j2/ > commit/93e97932 > > Tree: http://git-wip-us.apache.org/repos/asf/logging-log4j2/tree/ > 93e97932 > > Diff: http://git-wip-us.apache.org/repos/asf/logging-log4j2/diff/ > 93e97932 > > > > Branch: refs/heads/master > > Commit: 93e97932c871a94486b8dc1c16f6ae3a77184871 > > Parents: 81d12ad > > Author: Gary Gregory <garydgreg...@gmail.com> > > Authored: Tue Jan 23 14:20:14 2018 -0700 > > Committer: Gary Gregory <garydgreg...@gmail.com> > > Committed: Tue Jan 23 14:20:14 2018 -0700 > > > > ---------------------------------------------------------------------- > > .../org/apache/logging/log4j/ThreadContext.java | 1 + > > .../CopyOnWriteSortedArrayThreadContextMap.java | 21 ++++++++--- > > .../GarbageFreeSortedArrayThreadContextMap.java | 23 ++++++++++-- > > .../log4j/spi/ThreadContextMapFactory.java | 39 > ++++++++++++++++---- > > .../log4j/ThreadContextInheritanceTest.java | 8 +++- > > .../logging/log4j/core/LoggerContext.java | 7 ++++ > > src/changes/changes.xml | 11 ++++++ > > 7 files changed, 92 insertions(+), 18 deletions(-) > > ---------------------------------------------------------------------- > > > > > > http://git-wip-us.apache.org/repos/asf/logging-log4j2/blob/ > 93e97932/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 fc018b9..c4ae445 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 > > @@ -211,6 +211,7 @@ public final class ThreadContext { > > * <em>Consider private, used for testing.</em> > > */ > > static void init() { > > + ThreadContextMapFactory.init(); > > contextMap = null; > > final PropertiesUtil managerProps = > PropertiesUtil.getProperties(); > > disableAll = managerProps.getBooleanProperty(DISABLE_ALL); > > > > http://git-wip-us.apache.org/repos/asf/logging-log4j2/blob/ > 93e97932/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 d5e466f..fd94566 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 > > @@ -53,9 +53,23 @@ class CopyOnWriteSortedArrayThreadContextMap > implements ReadOnlyThreadContextMap > > protected static final String PROPERTY_NAME_INITIAL_CAPACITY = > "log4j2.ThreadContext.initial.capacity"; > > > > private static final StringMap EMPTY_CONTEXT_DATA = new > SortedArrayStringMap(1); > > + > > + private static volatile int InitialCapacity; > > + private static volatile boolean InheritableMap; > > > > + /** > > + * Initializes static variables based on system properties. > Normally called when this class is initialized by the VM > > + * and when Log4j is reconfigured. > > + */ > > + static void init() { > > + final PropertiesUtil properties = PropertiesUtil.getProperties() > ; > > + InitialCapacity = properties.getIntegerProperty( > PROPERTY_NAME_INITIAL_CAPACITY, DEFAULT_INITIAL_CAPACITY); > > + InheritableMap = properties.getBooleanProperty( > INHERITABLE_MAP); > > + } > > + > > static { > > EMPTY_CONTEXT_DATA.freeze(); > > + init(); > > } > > > > private final ThreadLocal<StringMap> localMap; > > @@ -67,9 +81,7 @@ class CopyOnWriteSortedArrayThreadContextMap > implements ReadOnlyThreadContextMap > > // LOG4J2-479: by default, use a plain ThreadLocal, only use > InheritableThreadLocal if configured. > > // (This method is package protected for JUnit tests.) > > private ThreadLocal<StringMap> createThreadLocalMap() { > > - final PropertiesUtil managerProps = > PropertiesUtil.getProperties(); > > - final boolean inheritable = managerProps.getBooleanProperty( > INHERITABLE_MAP); > > - if (inheritable) { > > + if (InheritableMap) { > > return new InheritableThreadLocal<StringMap>() { > > @Override > > protected StringMap childValue(final StringMap > parentValue) { > > @@ -94,8 +106,7 @@ class CopyOnWriteSortedArrayThreadContextMap > implements ReadOnlyThreadContextMap > > * @return an implementation of the {@code StringMap} used to back > this thread context map > > */ > > protected StringMap createStringMap() { > > - return new SortedArrayStringMap(PropertiesUtil.getProperties() > .getIntegerProperty( > > - PROPERTY_NAME_INITIAL_CAPACITY, > DEFAULT_INITIAL_CAPACITY)); > > + return new SortedArrayStringMap(InitialCapacity); > > } > > > > /** > > > > http://git-wip-us.apache.org/repos/asf/logging-log4j2/blob/ > 93e97932/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 f11fd66..d695b9c 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 > > @@ -53,6 +53,23 @@ class GarbageFreeSortedArrayThreadContextMap > implements ReadOnlyThreadContextMap > > protected static final String PROPERTY_NAME_INITIAL_CAPACITY = > "log4j2.ThreadContext.initial.capacity"; > > > > protected final ThreadLocal<StringMap> localMap; > > + > > + private static volatile int InitialCapacity; > > + private static volatile boolean InheritableMap; > > + > > + /** > > + * Initializes static variables based on system properties. > Normally called when this class is initialized by the VM > > + * and when Log4j is reconfigured. > > + */ > > + static void init() { > > + final PropertiesUtil properties = PropertiesUtil.getProperties() > ; > > + InitialCapacity = properties.getIntegerProperty( > PROPERTY_NAME_INITIAL_CAPACITY, DEFAULT_INITIAL_CAPACITY); > > + InheritableMap = properties.getBooleanProperty( > INHERITABLE_MAP); > > + } > > + > > + static { > > + init(); > > + } > > > > public GarbageFreeSortedArrayThreadContextMap() { > > this.localMap = createThreadLocalMap(); > > @@ -62,8 +79,7 @@ class GarbageFreeSortedArrayThreadContextMap > implements ReadOnlyThreadContextMap > > // (This method is package protected for JUnit tests.) > > private ThreadLocal<StringMap> createThreadLocalMap() { > > final PropertiesUtil managerProps = > PropertiesUtil.getProperties(); > > - final boolean inheritable = managerProps.getBooleanProperty( > INHERITABLE_MAP); > > - if (inheritable) { > > + if (InheritableMap) { > > return new InheritableThreadLocal<StringMap>() { > > @Override > > protected StringMap childValue(final StringMap > parentValue) { > > @@ -83,8 +99,7 @@ class GarbageFreeSortedArrayThreadContextMap > implements ReadOnlyThreadContextMap > > * @return an implementation of the {@code StringMap} used to back > this thread context map > > */ > > protected StringMap createStringMap() { > > - return new SortedArrayStringMap(PropertiesUtil.getProperties() > .getIntegerProperty( > > - PROPERTY_NAME_INITIAL_CAPACITY, > DEFAULT_INITIAL_CAPACITY)); > > + return new SortedArrayStringMap(InitialCapacity); > > } > > > > /** > > > > http://git-wip-us.apache.org/repos/asf/logging-log4j2/blob/ > 93e97932/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 > > index 47187dc..05c0e2d 100644 > > --- 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 > > @@ -49,25 +49,50 @@ 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 static boolean GcFreeThreadContextKey; > > + private static String ThreadContextMapName; > > > > + static { > > + initPrivate(); > > + } > > + > > + /** > > + * Initializes static variables based on system properties. > Normally called when this class is initialized by the VM > > + * and when Log4j is reconfigured. > > + */ > > + public static void init() { > > + CopyOnWriteSortedArrayThreadContextMap.init(); > > + GarbageFreeSortedArrayThreadContextMap.init(); > > + initPrivate(); > > + } > > + > > + /** > > + * Initializes static variables based on system properties. > Normally called when this class is initialized by the VM > > + * and when Log4j is reconfigured. > > + */ > > + private static void initPrivate() { > > + final PropertiesUtil properties = PropertiesUtil.getProperties() > ; > > + ThreadContextMapName = properties.getStringProperty( > THREAD_CONTEXT_KEY); > > + GcFreeThreadContextKey = properties.getBooleanProperty( > GC_FREE_THREAD_CONTEXT_KEY); > > + } > > + > > 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) { > > + if (ThreadContextMapName != null) { > > try { > > - final Class<?> clazz = cl.loadClass( > threadContextMapName); > > + 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); > > + LOGGER.error("Unable to locate configured > ThreadContextMap {}", ThreadContextMapName); > > } catch (final Exception ex) { > > - LOGGER.error("Unable to create configured > ThreadContextMap {}", threadContextMapName, ex); > > + LOGGER.error("Unable to create configured > ThreadContextMap {}", ThreadContextMapName, ex); > > } > > } > > if (result == null && ProviderUtil.hasProviders() && > LogManager.getFactory() != null) { //LOG4J2-1658 > > @@ -96,7 +121,7 @@ public final class ThreadContextMapFactory { > > > > private static ThreadContextMap createDefaultThreadContextMap() { > > if (Constants.ENABLE_THREADLOCALS) { > > - if (PropertiesUtil.getProperties( > ).getBooleanProperty(GC_FREE_THREAD_CONTEXT_KEY)) { > > + if (GcFreeThreadContextKey) { > > return new GarbageFreeSortedArrayThreadContextMap(); > > } > > return new CopyOnWriteSortedArrayThreadContextMap(); > > > > http://git-wip-us.apache.org/repos/asf/logging-log4j2/blob/ > 93e97932/log4j-api/src/test/java/org/apache/logging/log4j/ > ThreadContextInheritanceTest.java > > ---------------------------------------------------------------------- > > diff --git a/log4j-api/src/test/java/org/apache/logging/log4j/ > ThreadContextInheritanceTest.java b/log4j-api/src/test/java/org/ > apache/logging/log4j/ThreadContextInheritanceTest.java > > index 9c46e3f..a2e5fce 100644 > > --- a/log4j-api/src/test/java/org/apache/logging/log4j/ > ThreadContextInheritanceTest.java > > +++ b/log4j-api/src/test/java/org/apache/logging/log4j/ > ThreadContextInheritanceTest.java > > @@ -16,13 +16,16 @@ > > */ > > package org.apache.logging.log4j; > > > > +import static org.junit.Assert.assertEquals; > > +import static org.junit.Assert.assertFalse; > > +import static org.junit.Assert.assertNull; > > +import static org.junit.Assert.assertTrue; > > + > > import org.apache.logging.log4j.spi.DefaultThreadContextMap; > > import org.junit.AfterClass; > > import org.junit.BeforeClass; > > import org.junit.Test; > > > > -import static org.junit.Assert.*; > > - > > /** > > * Tests {@link ThreadContext}. > > */ > > @@ -54,6 +57,7 @@ public class ThreadContextInheritanceTest { > > @Test > > public void testInheritanceSwitchedOn() throws Exception { > > System.setProperty(DefaultThreadContextMap.INHERITABLE_MAP, > "true"); > > + ThreadContext.init(); > > try { > > ThreadContext.clearMap(); > > ThreadContext.put("Greeting", "Hello"); > > > > http://git-wip-us.apache.org/repos/asf/logging-log4j2/blob/ > 93e97932/log4j-core/src/main/java/org/apache/logging/log4j/ > core/LoggerContext.java > > ---------------------------------------------------------------------- > > diff --git > > a/log4j-core/src/main/java/org/apache/logging/log4j/core/LoggerContext.java > b/log4j-core/src/main/java/org/apache/logging/log4j/core/ > LoggerContext.java > > index cd15dce..8234024 100644 > > --- a/log4j-core/src/main/java/org/apache/logging/log4j/core/ > LoggerContext.java > > +++ b/log4j-core/src/main/java/org/apache/logging/log4j/core/ > LoggerContext.java > > @@ -49,9 +49,11 @@ import org.apache.logging.log4j.spi.AbstractLogger; > > import org.apache.logging.log4j.spi.LoggerContextFactory; > > import org.apache.logging.log4j.spi.LoggerRegistry; > > import org.apache.logging.log4j.spi.Terminable; > > +import org.apache.logging.log4j.spi.ThreadContextMapFactory; > > import org.apache.logging.log4j.util.LoaderUtil; > > import org.apache.logging.log4j.util.PropertiesUtil; > > > > + > > /** > > * The LoggerContext is the anchor for the logging system. It maintains > a list of all the loggers requested by > > * applications and a reference to the Configuration. The Configuration > will contain the configured loggers, appenders, > > @@ -662,6 +664,7 @@ public class LoggerContext extends AbstractLifeCycle > > @Override > > public synchronized void onChange(final Reconfigurable > reconfigurable) { > > LOGGER.debug("Reconfiguration started for context {} ({})", > contextName, this); > > + initApiModule(); > > final Configuration newConfig = reconfigurable.reconfigure(); > > if (newConfig != null) { > > setConfiguration(newConfig); > > @@ -671,6 +674,10 @@ public class LoggerContext extends AbstractLifeCycle > > } > > } > > > > + private void initApiModule() { > > + ThreadContextMapFactory.init(); // Or make public and call > ThreadContext.init() which calls ThreadContextMapFactory.init(). > > + } > > + > > // LOG4J2-151: changed visibility from private to protected > > protected Logger newInstance(final LoggerContext ctx, final String > name, final MessageFactory messageFactory) { > > return new Logger(ctx, name, messageFactory); > > > > http://git-wip-us.apache.org/repos/asf/logging-log4j2/blob/ > 93e97932/src/changes/changes.xml > > ---------------------------------------------------------------------- > > diff --git a/src/changes/changes.xml b/src/changes/changes.xml > > index b2f05d5..c918d0d 100644 > > --- a/src/changes/changes.xml > > +++ b/src/changes/changes.xml > > @@ -131,6 +131,17 @@ > > <action issue="LOG4J2-2210" dev="ggregory" type="update" > due-to="Björn Kautler"> > > Fix error log message for Script which says ScriptFile instead. > > </action> > > + <action issue="LOG4J2-2212" dev="ggregory" type="update" > due-to="Daniel Feist, Gary Gregory"> > > + Unnecessary contention in CopyOnWriteSortedArrayThreadCo > ntextMap. > > + </action> > > + <action issue="LOG4J2-2213" dev="ggregory" type="update" > due-to="Daniel Feist, Gary Gregory"> > > + Unnecessary contention in GarbageFreeSortedArrayThreadCo > ntextMap. > > + </action> > > + <!-- > > + <action issue="LOG4J2-2205" dev="ggregory" type="update" > due-to="Björn Kautler"> > > + New module log4j-mongodb3: Remove use of deprecated MongoDB > APIs and code to the Java driver version 3 API. > > + </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 "> > > >