You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@zipkin.apache.org by an...@apache.org on 2019/05/11 08:49:44 UTC

[incubator-zipkin] branch master updated: Reuse char[] buffer when decoding hex fields. (#2582)

This is an automated email from the ASF dual-hosted git repository.

anuraaga pushed a commit to branch master
in repository https://gitbox.apache.org/repos/asf/incubator-zipkin.git


The following commit(s) were added to refs/heads/master by this push:
     new 5592e82  Reuse char[] buffer when decoding hex fields. (#2582)
5592e82 is described below

commit 5592e82cbc743b2263e74cf34c724685c5337ad1
Author: Anuraag Agrawal <an...@gmail.com>
AuthorDate: Sat May 11 17:49:37 2019 +0900

    Reuse char[] buffer when decoding hex fields. (#2582)
    
    * Reuse char[] buffer when decoding hex fields.
    
    * Better(?) threadlocal
    
    * Better exception type.
    
    * Extract ID buffer for potential use in other locations.
    
    * Remove unneessary change.
    
    * Remove unused variable.
---
 .../java/zipkin2/codec/ProtobufSpanDecoder.java    | 13 +++++++++---
 .../main/java/zipkin2/codec/WireSpanDecoder.java   | 24 +++++++++++++++++++++-
 .../src/main/java/zipkin2/internal/Platform.java   | 16 +++++++++++++++
 .../main/java/zipkin2/internal/Proto3Fields.java   | 10 +++++++--
 4 files changed, 57 insertions(+), 6 deletions(-)

diff --git a/benchmarks/src/main/java/zipkin2/codec/ProtobufSpanDecoder.java b/benchmarks/src/main/java/zipkin2/codec/ProtobufSpanDecoder.java
index f63d62c..0df0d03 100644
--- a/benchmarks/src/main/java/zipkin2/codec/ProtobufSpanDecoder.java
+++ b/benchmarks/src/main/java/zipkin2/codec/ProtobufSpanDecoder.java
@@ -25,6 +25,7 @@ import java.util.List;
 import java.util.logging.Logger;
 import zipkin2.Endpoint;
 import zipkin2.Span;
+import zipkin2.internal.Platform;
 
 public class ProtobufSpanDecoder {
   static final Logger LOG = Logger.getLogger(ProtobufSpanDecoder.class.getName());
@@ -271,16 +272,22 @@ public class ProtobufSpanDecoder {
 
   private static String readHexString(CodedInputStream input) throws IOException {
     int size = input.readRawVarint32();
+    int length = size * 2;
 
-    char[] result = new char[size * 2];
+    // All our hex fields are at most 32 characters.
+    if (length > 32) {
+      throw new AssertionError("hex field greater than 32 chars long: " + length);
+    }
+
+    char[] result = Platform.get().idBuffer();
 
-    for (int i = 0; i < result.length; i += 2) {
+    for (int i = 0; i < length; i += 2) {
       byte b = input.readRawByte();
       result[i] = HEX_DIGITS[(b >> 4) & 0xf];
       result[i + 1] = HEX_DIGITS[b & 0xf];
     }
 
-    return new String(result);
+    return new String(result, 0, length);
   }
 
   static void logAndSkip(CodedInputStream input, int tag) throws IOException {
diff --git a/benchmarks/src/main/java/zipkin2/codec/WireSpanDecoder.java b/benchmarks/src/main/java/zipkin2/codec/WireSpanDecoder.java
index a7e7a24..d5b1f84 100644
--- a/benchmarks/src/main/java/zipkin2/codec/WireSpanDecoder.java
+++ b/benchmarks/src/main/java/zipkin2/codec/WireSpanDecoder.java
@@ -26,8 +26,10 @@ import java.util.ArrayList;
 import java.util.List;
 import java.util.logging.Logger;
 import okio.Buffer;
+import okio.ByteString;
 import zipkin2.Endpoint;
 import zipkin2.Span;
+import zipkin2.internal.Platform;
 
 public class WireSpanDecoder {
   static final Logger LOG = Logger.getLogger(WireSpanDecoder.class.getName());
@@ -279,8 +281,28 @@ public class WireSpanDecoder {
     return spans;
   }
 
+  static final char[] HEX_DIGITS =
+    {'0', '1', '2', '3', '4', '5', '6', '7', '8', '9', 'a', 'b', 'c', 'd', 'e', 'f'};
+
+  // https://github.com/square/wire/issues/958
   private static String readHexString(ProtoReader input) throws IOException {
-    return input.readBytes().hex();
+    ByteString bytes = input.readBytes();
+    int length = bytes.size() * 2;
+
+    // All our hex fields are at most 32 characters.
+    if (length > 32) {
+      throw new AssertionError("hex field greater than 32 chars long: " + length);
+    }
+
+    char[] result = Platform.get().idBuffer();
+
+    for (int i = 0; i < bytes.size(); i ++) {
+      byte b = bytes.getByte(i);
+      result[2 * i] = HEX_DIGITS[(b >> 4) & 0xf];
+      result[2 * i + 1] = HEX_DIGITS[b & 0xf];
+    }
+
+    return new String(result, 0, length);
   }
 
   static void logAndSkip(ProtoReader input, int tag) throws IOException {
diff --git a/zipkin/src/main/java/zipkin2/internal/Platform.java b/zipkin/src/main/java/zipkin2/internal/Platform.java
index fad3606..6e10fb8 100644
--- a/zipkin/src/main/java/zipkin2/internal/Platform.java
+++ b/zipkin/src/main/java/zipkin2/internal/Platform.java
@@ -27,9 +27,25 @@ import org.jvnet.animal_sniffer.IgnoreJRERequirement;
 public abstract class Platform {
   private static final Platform PLATFORM = findPlatform();
 
+  private static final ThreadLocal<char[]> ID_BUFFER = new ThreadLocal<>();
+
   Platform() {
   }
 
+  /**
+   * Returns a {@link ThreadLocal} reused {@code char[]} for use when decoding bytes into a hex
+   * string. The buffer should be immediately copied into a {@link String} after decoding within the
+   * same method.
+   */
+  public char[] idBuffer() {
+    char[] idBuffer = ID_BUFFER.get();
+    if (idBuffer == null) {
+      idBuffer = new char[32];
+      ID_BUFFER.set(idBuffer);
+    }
+    return idBuffer;
+  }
+
   public RuntimeException uncheckedIOException(IOException e) {
     return new RuntimeException(e);
   }
diff --git a/zipkin/src/main/java/zipkin2/internal/Proto3Fields.java b/zipkin/src/main/java/zipkin2/internal/Proto3Fields.java
index 24076db..ba2df27 100644
--- a/zipkin/src/main/java/zipkin2/internal/Proto3Fields.java
+++ b/zipkin/src/main/java/zipkin2/internal/Proto3Fields.java
@@ -190,7 +190,13 @@ final class Proto3Fields {
 
     @Override String readValue(Buffer buffer, int length) {
       length *= 2;
-      char[] result = new char[length];
+
+      // All our hex fields are at most 32 characters.
+      if (length > 32) {
+        throw new IllegalArgumentException("hex field greater than 32 chars long: " + length);
+      }
+
+      char[] result = Platform.get().idBuffer();
 
       for (int i = 0; i < length; i += 2) {
         byte b = buffer.readByte();
@@ -198,7 +204,7 @@ final class Proto3Fields {
         result[i + 1] = HEX_DIGITS[b & 0xf];
       }
 
-      return new String(result);
+      return new String(result, 0, length);
     }
   }