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/LOG4J2-1395
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;
+    }
 }

Reply via email to