LOG4J2-1412 make Unbox ringbuffer size configurable. Added javadoc.
Project: http://git-wip-us.apache.org/repos/asf/logging-log4j2/repo Commit: http://git-wip-us.apache.org/repos/asf/logging-log4j2/commit/80e0717e Tree: http://git-wip-us.apache.org/repos/asf/logging-log4j2/tree/80e0717e Diff: http://git-wip-us.apache.org/repos/asf/logging-log4j2/diff/80e0717e Branch: refs/heads/LOG4J-1181 Commit: 80e0717e0487063950576414f6752c3d37e37756 Parents: 8f298ef Author: rpopma <[email protected]> Authored: Mon Jun 6 20:32:33 2016 +0900 Committer: rpopma <[email protected]> Committed: Mon Jun 6 20:32:33 2016 +0900 ---------------------------------------------------------------------- .../org/apache/logging/log4j/util/Unbox.java | 57 +++++++++++++++++++- 1 file changed, 55 insertions(+), 2 deletions(-) ---------------------------------------------------------------------- http://git-wip-us.apache.org/repos/asf/logging-log4j2/blob/80e0717e/log4j-api/src/main/java/org/apache/logging/log4j/util/Unbox.java ---------------------------------------------------------------------- diff --git a/log4j-api/src/main/java/org/apache/logging/log4j/util/Unbox.java b/log4j-api/src/main/java/org/apache/logging/log4j/util/Unbox.java index e86dc69..137a702 100644 --- a/log4j-api/src/main/java/org/apache/logging/log4j/util/Unbox.java +++ b/log4j-api/src/main/java/org/apache/logging/log4j/util/Unbox.java @@ -16,6 +16,9 @@ */ package org.apache.logging.log4j.util; +import org.apache.logging.log4j.Logger; +import org.apache.logging.log4j.status.StatusLogger; + /** * Utility for preventing primitive parameter values from being auto-boxed. Auto-boxing creates temporary objects * which contribute to pressure on the garbage collector. With this utility users can convert primitive values directly @@ -30,13 +33,27 @@ package org.apache.logging.log4j.util; * // prevent primitive values from being auto-boxed * logger.debug("Long value={}, double value={}", box(longValue), box(doubleValue)); * </pre> + * <p> + * This class manages a small thread-local ring buffer of StringBuilders. + * Each time one of the {@code box()} methods is called, the next slot in the ring buffer is used, until the ring + * buffer is full and the first slot is reused. By default the Unbox ring buffer has 32 slots, so user code can + * have up to 32 boxed primitives in a single logger call. + * </p> + * <p> + * If more slots are required, set system property {@code log4j.unbox.ringbuffer.size} to the desired ring buffer size. + * Note that the specified number will be rounded up to the nearest power of 2. + * </p> */ @PerformanceSensitive("allocation") public class Unbox { - private static final int MASK = 16 - 1; + private static final Logger LOGGER = StatusLogger.getLogger(); + private static final int BITS_PER_INT = 32; + private static final int RINGBUFFER_MIN_SIZE = 32; + private static final int RINGBUFFER_SIZE = calculateRingBufferSize("log4j.unbox.ringbuffer.size"); + private static final int MASK = RINGBUFFER_SIZE - 1; private static class State { - private final StringBuilder[] ringBuffer = new StringBuilder[16]; + private final StringBuilder[] ringBuffer = new StringBuilder[RINGBUFFER_SIZE]; private int current; State() { for (int i = 0; i < ringBuffer.length; i++) { @@ -64,6 +81,37 @@ public class Unbox { private Unbox() { // this is a utility } + + private static int calculateRingBufferSize(final String propertyName) { + final String userPreferredRBSize = PropertiesUtil.getProperties().getStringProperty(propertyName, + String.valueOf(RINGBUFFER_MIN_SIZE)); + try { + int size = Integer.parseInt(userPreferredRBSize); + if (size < RINGBUFFER_MIN_SIZE) { + size = RINGBUFFER_MIN_SIZE; + LOGGER.warn("Invalid {} {}, using minimum size {}.", propertyName, userPreferredRBSize, + RINGBUFFER_MIN_SIZE); + } + return ceilingNextPowerOfTwo(size); + } catch (final Exception ex) { + LOGGER.warn("Invalid {} {}, using default size {}.", propertyName, userPreferredRBSize, + RINGBUFFER_MIN_SIZE); + return RINGBUFFER_MIN_SIZE; + } + } + + /** + * Calculate the next power of 2, greater than or equal to x. + * <p> + * From Hacker's Delight, Chapter 3, Harry S. Warren Jr. + * + * @param x Value to round up + * @return The next power of 2 from x inclusive + */ + private static int ceilingNextPowerOfTwo(final int x) { + return 1 << (BITS_PER_INT - Integer.numberOfLeadingZeros(x - 1)); + } + /** * Returns a {@code StringBuilder} containing the text representation of the specified primitive value. * This method will not allocate temporary objects. @@ -172,4 +220,9 @@ public class Unbox { private static StringBuilder getSB() { return getState().getStringBuilder(); } + + /** For testing. */ + static int getRingbufferSize() { + return RINGBUFFER_SIZE; + } }
