You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@qpid.apache.org by ta...@apache.org on 2018/08/10 16:40:57 UTC

qpid-proton-j git commit: PROTON-1911 Improve performance of String encodes when possible

Repository: qpid-proton-j
Updated Branches:
  refs/heads/master 7484cc8e4 -> 7eac8b945


PROTON-1911 Improve performance of String encodes when possible

Optimize the String encoding by adding new method to WritableBuffer that
allows the buffer implementation to optimize how String values are
encoded to UTF8 bytes based on the buffer type.  Using the Java 8
default implementation support for interface methods add a default
version that behaves as the older releases would.  For the ByteBuffer
wrapper optimize the writes by accessing the buffer data in the most
direct way possible.

Help on this solution provided by Robbie Gemmell and Francesco Nigro

Project: http://git-wip-us.apache.org/repos/asf/qpid-proton-j/repo
Commit: http://git-wip-us.apache.org/repos/asf/qpid-proton-j/commit/7eac8b94
Tree: http://git-wip-us.apache.org/repos/asf/qpid-proton-j/tree/7eac8b94
Diff: http://git-wip-us.apache.org/repos/asf/qpid-proton-j/diff/7eac8b94

Branch: refs/heads/master
Commit: 7eac8b945c8ce90f091126d34cf174e8792fdfc0
Parents: 7484cc8
Author: Timothy Bish <ta...@gmail.com>
Authored: Fri Aug 10 12:40:12 2018 -0400
Committer: Timothy Bish <ta...@gmail.com>
Committed: Fri Aug 10 12:40:12 2018 -0400

----------------------------------------------------------------------
 .../proton/codec/CompositeWritableBuffer.java   |  31 +++-
 .../proton/codec/DroppingWritableBuffer.java    |  10 +-
 .../apache/qpid/proton/codec/EncoderImpl.java   |  93 ++++++------
 .../qpid/proton/codec/WritableBuffer.java       | 151 +++++++++++++------
 .../org/apache/qpid/proton/codec/Benchmark.java |  13 +-
 .../qpid/proton/codec/StringTypeTest.java       | 130 ++++++++++++++--
 6 files changed, 315 insertions(+), 113 deletions(-)
----------------------------------------------------------------------


http://git-wip-us.apache.org/repos/asf/qpid-proton-j/blob/7eac8b94/proton-j/src/main/java/org/apache/qpid/proton/codec/CompositeWritableBuffer.java
----------------------------------------------------------------------
diff --git a/proton-j/src/main/java/org/apache/qpid/proton/codec/CompositeWritableBuffer.java b/proton-j/src/main/java/org/apache/qpid/proton/codec/CompositeWritableBuffer.java
index 5b2c71c..7d1fef2 100644
--- a/proton-j/src/main/java/org/apache/qpid/proton/codec/CompositeWritableBuffer.java
+++ b/proton-j/src/main/java/org/apache/qpid/proton/codec/CompositeWritableBuffer.java
@@ -1,4 +1,3 @@
-package org.apache.qpid.proton.codec;
 /*
  *
  * Licensed to the Apache Software Foundation (ASF) under one
@@ -19,9 +18,10 @@ package org.apache.qpid.proton.codec;
  * under the License.
  *
 */
-
+package org.apache.qpid.proton.codec;
 
 import java.nio.ByteBuffer;
+import java.nio.charset.StandardCharsets;
 
 public class CompositeWritableBuffer implements WritableBuffer
 {
@@ -34,21 +34,25 @@ public class CompositeWritableBuffer implements WritableBuffer
         _second = second;
     }
 
+    @Override
     public void put(byte b)
     {
         (_first.hasRemaining() ? _first : _second).put(b);
     }
 
+    @Override
     public void putFloat(float f)
     {
         putInt(Float.floatToRawIntBits(f));
     }
 
+    @Override
     public void putDouble(double d)
     {
         putLong(Double.doubleToRawLongBits(d));
     }
 
+    @Override
     public void putShort(short s)
     {
         int remaining = _first.remaining();
@@ -69,6 +73,7 @@ public class CompositeWritableBuffer implements WritableBuffer
         }
     }
 
+    @Override
     public void putInt(int i)
     {
         int remaining = _first.remaining();
@@ -89,6 +94,7 @@ public class CompositeWritableBuffer implements WritableBuffer
         }
     }
 
+    @Override
     public void putLong(long l)
     {
         int remaining = _first.remaining();
@@ -109,26 +115,31 @@ public class CompositeWritableBuffer implements WritableBuffer
         }
     }
 
+    @Override
     public boolean hasRemaining()
     {
         return _first.hasRemaining() || _second.hasRemaining();
     }
 
+    @Override
     public int remaining()
     {
         return _first.remaining()+_second.remaining();
     }
 
+    @Override
     public int position()
     {
         return _first.position()+_second.position();
     }
 
+    @Override
     public int limit()
     {
         return _first.limit() + _second.limit();
     }
 
+    @Override
     public void position(int position)
     {
         int first_limit = _first.limit();
@@ -144,6 +155,7 @@ public class CompositeWritableBuffer implements WritableBuffer
         }
     }
 
+    @Override
     public void put(byte[] src, int offset, int length)
     {
         final int firstRemaining = _first.remaining();
@@ -162,6 +174,7 @@ public class CompositeWritableBuffer implements WritableBuffer
         _second.put(src, offset+firstRemaining, length-firstRemaining);
     }
 
+    @Override
     public void put(ByteBuffer payload)
     {
         int firstRemaining = _first.remaining();
@@ -209,4 +222,18 @@ public class CompositeWritableBuffer implements WritableBuffer
         }
         _second.put(payload);
     }
+
+    @Override
+    public void put(String value)
+    {
+        if (_first.hasRemaining())
+        {
+            byte[] utf8Bytes = value.getBytes(StandardCharsets.UTF_8);
+            put(utf8Bytes, 0, utf8Bytes.length);
+        }
+        else
+        {
+            _second.put(value);
+        }
+    }
 }

http://git-wip-us.apache.org/repos/asf/qpid-proton-j/blob/7eac8b94/proton-j/src/main/java/org/apache/qpid/proton/codec/DroppingWritableBuffer.java
----------------------------------------------------------------------
diff --git a/proton-j/src/main/java/org/apache/qpid/proton/codec/DroppingWritableBuffer.java b/proton-j/src/main/java/org/apache/qpid/proton/codec/DroppingWritableBuffer.java
index ade5a08..067c41a 100644
--- a/proton-j/src/main/java/org/apache/qpid/proton/codec/DroppingWritableBuffer.java
+++ b/proton-j/src/main/java/org/apache/qpid/proton/codec/DroppingWritableBuffer.java
@@ -21,6 +21,7 @@
 package org.apache.qpid.proton.codec;
 
 import java.nio.ByteBuffer;
+import java.nio.charset.StandardCharsets;
 
 public class DroppingWritableBuffer implements WritableBuffer
 {
@@ -106,8 +107,15 @@ public class DroppingWritableBuffer implements WritableBuffer
     }
 
     @Override
-    public void put(ReadableBuffer payload) {
+    public void put(ReadableBuffer payload)
+    {
         _pos += payload.remaining();
         payload.position(payload.limit());
     }
+
+    @Override
+    public void put(String value)
+    {
+        _pos += value.getBytes(StandardCharsets.UTF_8).length;
+    }
 }

http://git-wip-us.apache.org/repos/asf/qpid-proton-j/blob/7eac8b94/proton-j/src/main/java/org/apache/qpid/proton/codec/EncoderImpl.java
----------------------------------------------------------------------
diff --git a/proton-j/src/main/java/org/apache/qpid/proton/codec/EncoderImpl.java b/proton-j/src/main/java/org/apache/qpid/proton/codec/EncoderImpl.java
index d709a77..512805b 100644
--- a/proton-j/src/main/java/org/apache/qpid/proton/codec/EncoderImpl.java
+++ b/proton-j/src/main/java/org/apache/qpid/proton/codec/EncoderImpl.java
@@ -80,12 +80,6 @@ public final class EncoderImpl implements ByteBufferEncoder
 
     private final ArrayType             _arrayType;
 
-    EncoderImpl(ByteBuffer buffer, DecoderImpl decoder)
-    {
-        this(decoder);
-        setByteBuffer(buffer);
-    }
-
     public EncoderImpl(DecoderImpl decoder)
     {
         _decoder                = decoder;
@@ -129,10 +123,9 @@ public final class EncoderImpl implements ByteBufferEncoder
                                                 _floatType,
                                                 _doubleType,
                                                 _characterType);
-
-
     }
 
+    @Override
     public void setByteBuffer(final ByteBuffer buf)
     {
         _buffer = new WritableBuffer.ByteBufferWrapper(buf);
@@ -228,11 +221,13 @@ public final class EncoderImpl implements ByteBufferEncoder
         _describedTypesClassRegistry.put(clazz, type);
     }
 
+    @Override
     public void writeNull()
     {
         _buffer.put(EncodingCodes.NULL);
     }
 
+    @Override
     public void writeBoolean(final boolean bool)
     {
         if (bool)
@@ -245,6 +240,7 @@ public final class EncoderImpl implements ByteBufferEncoder
         }
     }
 
+    @Override
     public void writeBoolean(final Boolean bool)
     {
         if(bool == null)
@@ -261,6 +257,7 @@ public final class EncoderImpl implements ByteBufferEncoder
         }
     }
 
+    @Override
     public void writeUnsignedByte(final UnsignedByte ubyte)
     {
         if(ubyte == null)
@@ -273,6 +270,7 @@ public final class EncoderImpl implements ByteBufferEncoder
         }
     }
 
+    @Override
     public void writeUnsignedShort(final UnsignedShort ushort)
     {
         if(ushort == null)
@@ -285,6 +283,7 @@ public final class EncoderImpl implements ByteBufferEncoder
         }
     }
 
+    @Override
     public void writeUnsignedInteger(final UnsignedInteger uint)
     {
         if(uint == null)
@@ -297,6 +296,7 @@ public final class EncoderImpl implements ByteBufferEncoder
         }
     }
 
+    @Override
     public void writeUnsignedLong(final UnsignedLong ulong)
     {
         if(ulong == null)
@@ -309,11 +309,13 @@ public final class EncoderImpl implements ByteBufferEncoder
         }
     }
 
+    @Override
     public void writeByte(final byte b)
     {
         _byteType.write(b);
     }
 
+    @Override
     public void writeByte(final Byte b)
     {
         if(b == null)
@@ -326,11 +328,13 @@ public final class EncoderImpl implements ByteBufferEncoder
         }
     }
 
+    @Override
     public void writeShort(final short s)
     {
         _shortType.write(s);
     }
 
+    @Override
     public void writeShort(final Short s)
     {
         if(s == null)
@@ -343,11 +347,13 @@ public final class EncoderImpl implements ByteBufferEncoder
         }
     }
 
+    @Override
     public void writeInteger(final int i)
     {
         _integerType.write(i);
     }
 
+    @Override
     public void writeInteger(final Integer i)
     {
         if(i == null)
@@ -360,11 +366,13 @@ public final class EncoderImpl implements ByteBufferEncoder
         }
     }
 
+    @Override
     public void writeLong(final long l)
     {
         _longType.write(l);
     }
 
+    @Override
     public void writeLong(final Long l)
     {
 
@@ -378,11 +386,13 @@ public final class EncoderImpl implements ByteBufferEncoder
         }
     }
 
+    @Override
     public void writeFloat(final float f)
     {
         _floatType.write(f);
     }
 
+    @Override
     public void writeFloat(final Float f)
     {
         if(f == null)
@@ -395,11 +405,13 @@ public final class EncoderImpl implements ByteBufferEncoder
         }
     }
 
+    @Override
     public void writeDouble(final double d)
     {
         _doubleType.write(d);
     }
 
+    @Override
     public void writeDouble(final Double d)
     {
         if(d == null)
@@ -412,6 +424,7 @@ public final class EncoderImpl implements ByteBufferEncoder
         }
     }
 
+    @Override
     public void writeDecimal32(final Decimal32 d)
     {
         if(d == null)
@@ -424,6 +437,7 @@ public final class EncoderImpl implements ByteBufferEncoder
         }
     }
 
+    @Override
     public void writeDecimal64(final Decimal64 d)
     {
         if(d == null)
@@ -436,6 +450,7 @@ public final class EncoderImpl implements ByteBufferEncoder
         }
     }
 
+    @Override
     public void writeDecimal128(final Decimal128 d)
     {
         if(d == null)
@@ -448,12 +463,14 @@ public final class EncoderImpl implements ByteBufferEncoder
         }
     }
 
+    @Override
     public void writeCharacter(final char c)
     {
         // TODO - java character may be half of a pair, should probably throw exception then
         _characterType.write(c);
     }
 
+    @Override
     public void writeCharacter(final Character c)
     {
         if(c == null)
@@ -466,11 +483,13 @@ public final class EncoderImpl implements ByteBufferEncoder
         }
     }
 
+    @Override
     public void writeTimestamp(final long timestamp)
     {
         _timestampType.fastWrite(this, timestamp);
     }
 
+    @Override
     public void writeTimestamp(final Date d)
     {
         if(d == null)
@@ -483,6 +502,7 @@ public final class EncoderImpl implements ByteBufferEncoder
         }
     }
 
+    @Override
     public void writeUUID(final UUID uuid)
     {
         if(uuid == null)
@@ -496,6 +516,7 @@ public final class EncoderImpl implements ByteBufferEncoder
 
     }
 
+    @Override
     public void writeBinary(final Binary b)
     {
         if(b == null)
@@ -508,6 +529,7 @@ public final class EncoderImpl implements ByteBufferEncoder
         }
     }
 
+    @Override
     public void writeString(final String s)
     {
         if(s == null)
@@ -520,6 +542,7 @@ public final class EncoderImpl implements ByteBufferEncoder
         }
     }
 
+    @Override
     public void writeSymbol(final Symbol s)
     {
         if(s == null)
@@ -533,6 +556,7 @@ public final class EncoderImpl implements ByteBufferEncoder
 
     }
 
+    @Override
     public void writeList(final List l)
     {
         if(l == null)
@@ -545,6 +569,7 @@ public final class EncoderImpl implements ByteBufferEncoder
         }
     }
 
+    @Override
     public void writeMap(final Map m)
     {
 
@@ -558,6 +583,7 @@ public final class EncoderImpl implements ByteBufferEncoder
         }
     }
 
+    @Override
     public void writeDescribedType(final DescribedType d)
     {
         if(d == null)
@@ -572,6 +598,7 @@ public final class EncoderImpl implements ByteBufferEncoder
         }
     }
 
+    @Override
     public void writeArray(final boolean[] a)
     {
         if(a == null)
@@ -584,6 +611,7 @@ public final class EncoderImpl implements ByteBufferEncoder
         }
     }
 
+    @Override
     public void writeArray(final byte[] a)
     {
         if(a == null)
@@ -596,6 +624,7 @@ public final class EncoderImpl implements ByteBufferEncoder
         }
     }
 
+    @Override
     public void writeArray(final short[] a)
     {
         if(a == null)
@@ -608,6 +637,7 @@ public final class EncoderImpl implements ByteBufferEncoder
         }
     }
 
+    @Override
     public void writeArray(final int[] a)
     {
         if(a == null)
@@ -620,6 +650,7 @@ public final class EncoderImpl implements ByteBufferEncoder
         }
     }
 
+    @Override
     public void writeArray(final long[] a)
     {
         if(a == null)
@@ -632,6 +663,7 @@ public final class EncoderImpl implements ByteBufferEncoder
         }
     }
 
+    @Override
     public void writeArray(final float[] a)
     {
         if(a == null)
@@ -644,6 +676,7 @@ public final class EncoderImpl implements ByteBufferEncoder
         }
     }
 
+    @Override
     public void writeArray(final double[] a)
     {
         if(a == null)
@@ -656,6 +689,7 @@ public final class EncoderImpl implements ByteBufferEncoder
         }
     }
 
+    @Override
     public void writeArray(final char[] a)
     {
         if(a == null)
@@ -668,6 +702,7 @@ public final class EncoderImpl implements ByteBufferEncoder
         }
     }
 
+    @Override
     public void writeArray(final Object[] a)
     {
         if(a == null)
@@ -680,6 +715,7 @@ public final class EncoderImpl implements ByteBufferEncoder
         }
     }
 
+    @Override
     public void writeObject(final Object o)
     {
         if (o == null)
@@ -802,46 +838,9 @@ public final class EncoderImpl implements ByteBufferEncoder
         _buffer.put(src, offset, length);
     }
 
-    void writeRaw(String string)
+    void writeRaw(final String string)
     {
-        final int length = string.length();
-        int c;
-
-        for (int i = 0; i < length; i++)
-        {
-            c = string.charAt(i);
-            if ((c & 0xFF80) == 0)          /* U+0000..U+007F */
-            {
-                _buffer.put((byte) c);
-            }
-            else if ((c & 0xF800) == 0)     /* U+0080..U+07FF */
-            {
-                _buffer.put((byte)(0xC0 | ((c >> 6) & 0x1F)));
-                _buffer.put((byte)(0x80 | (c & 0x3F)));
-            }
-            else if ((c & 0xD800) != 0xD800 || (c > 0xDBFF))     /* U+0800..U+FFFF - excluding surrogate pairs */
-            {
-                _buffer.put((byte)(0xE0 | ((c >> 12) & 0x0F)));
-                _buffer.put((byte)(0x80 | ((c >> 6) & 0x3F)));
-                _buffer.put((byte)(0x80 | (c & 0x3F)));
-            }
-            else
-            {
-                int low;
-
-                if((++i == length) || ((low = string.charAt(i)) & 0xDC00) != 0xDC00)
-                {
-                    throw new IllegalArgumentException("String contains invalid Unicode code points");
-                }
-
-                c = 0x010000 + ((c & 0x03FF) << 10) + (low & 0x03FF);
-
-                _buffer.put((byte)(0xF0 | ((c >> 18) & 0x07)));
-                _buffer.put((byte)(0x80 | ((c >> 12) & 0x3F)));
-                _buffer.put((byte)(0x80 | ((c >> 6) & 0x3F)));
-                _buffer.put((byte)(0x80 | (c & 0x3F)));
-            }
-        }
+        _buffer.put(string);
     }
 
     AMQPType getNullTypeEncoder()

http://git-wip-us.apache.org/repos/asf/qpid-proton-j/blob/7eac8b94/proton-j/src/main/java/org/apache/qpid/proton/codec/WritableBuffer.java
----------------------------------------------------------------------
diff --git a/proton-j/src/main/java/org/apache/qpid/proton/codec/WritableBuffer.java b/proton-j/src/main/java/org/apache/qpid/proton/codec/WritableBuffer.java
index 67c8292..6941ed7 100644
--- a/proton-j/src/main/java/org/apache/qpid/proton/codec/WritableBuffer.java
+++ b/proton-j/src/main/java/org/apache/qpid/proton/codec/WritableBuffer.java
@@ -23,8 +23,7 @@ package org.apache.qpid.proton.codec;
 
 import java.nio.ByteBuffer;
 
-public interface WritableBuffer
-{
+public interface WritableBuffer {
     void put(byte b);
 
     void putFloat(float f);
@@ -51,131 +50,191 @@ public interface WritableBuffer
 
     void put(ReadableBuffer payload);
 
+    default void put(final String value) {
+        final int length = value.length();
+
+        for (int i = 0; i < length; i++) {
+            int c = value.charAt(i);
+            if ((c & 0xFF80) == 0) {
+                // U+0000..U+007F
+                put((byte) c);
+            } else if ((c & 0xF800) == 0)  {
+                // U+0080..U+07FF
+                put((byte) (0xC0 | ((c >> 6) & 0x1F)));
+                put((byte) (0x80 | (c & 0x3F)));
+            } else if ((c & 0xD800) != 0xD800 || (c > 0xDBFF)) {
+                // U+0800..U+FFFF - excluding surrogate pairs
+                put((byte) (0xE0 | ((c >> 12) & 0x0F)));
+                put((byte) (0x80 | ((c >> 6) & 0x3F)));
+                put((byte) (0x80 | (c & 0x3F)));
+            } else {
+                int low;
+
+                if ((++i == length) || ((low = value.charAt(i)) & 0xDC00) != 0xDC00) {
+                    throw new IllegalArgumentException("String contains invalid Unicode code points");
+                }
+
+                c = 0x010000 + ((c & 0x03FF) << 10) + (low & 0x03FF);
+
+                put((byte) (0xF0 | ((c >> 18) & 0x07)));
+                put((byte) (0x80 | ((c >> 12) & 0x3F)));
+                put((byte) (0x80 | ((c >> 6) & 0x3F)));
+                put((byte) (0x80 | (c & 0x3F)));
+            }
+        }
+    }
+
     int limit();
 
-    class ByteBufferWrapper implements WritableBuffer
-    {
+    class ByteBufferWrapper implements WritableBuffer {
         private final ByteBuffer _buf;
 
-        public ByteBufferWrapper(ByteBuffer buf)
-        {
+        public ByteBufferWrapper(ByteBuffer buf) {
             _buf = buf;
         }
 
         @Override
-        public void put(byte b)
-        {
+        public void put(byte b) {
             _buf.put(b);
         }
 
         @Override
-        public void putFloat(float f)
-        {
+        public void putFloat(float f) {
             _buf.putFloat(f);
         }
 
         @Override
-        public void putDouble(double d)
-        {
+        public void putDouble(double d) {
             _buf.putDouble(d);
         }
 
         @Override
-        public void put(byte[] src, int offset, int length)
-        {
+        public void put(byte[] src, int offset, int length) {
             _buf.put(src, offset, length);
         }
 
         @Override
-        public void putShort(short s)
-        {
+        public void putShort(short s) {
             _buf.putShort(s);
         }
 
         @Override
-        public void putInt(int i)
-        {
+        public void putInt(int i) {
             _buf.putInt(i);
         }
 
         @Override
-        public void putLong(long l)
-        {
+        public void putLong(long l) {
             _buf.putLong(l);
         }
 
         @Override
-        public boolean hasRemaining()
-        {
+        public boolean hasRemaining() {
             return _buf.hasRemaining();
         }
 
         @Override
-        public int remaining()
-        {
+        public int remaining() {
             return _buf.remaining();
         }
 
         @Override
-        public int position()
-        {
+        public int position() {
             return _buf.position();
         }
 
         @Override
-        public void position(int position)
-        {
+        public void position(int position) {
             _buf.position(position);
         }
 
         @Override
-        public void put(ByteBuffer src)
-        {
+        public void put(ByteBuffer src) {
             _buf.put(src);
         }
 
         @Override
-        public void put(ReadableBuffer src)
-        {
+        public void put(ReadableBuffer src) {
             src.get(this);
         }
 
         @Override
-        public int limit()
-        {
+        public void put(final String value) {
+            final int length = value.length();
+
+            int pos = _buf.position();
+
+            for (int i = 0; i < length; i++) {
+                int c = value.charAt(i);
+                if ((c & 0xFF80) == 0) {
+                    // U+0000..U+007F
+                    put(pos++, (byte) c);
+                } else if ((c & 0xF800) == 0)  {
+                    // U+0080..U+07FF
+                    put(pos++, (byte) (0xC0 | ((c >> 6) & 0x1F)));
+                    put(pos++, (byte) (0x80 | (c & 0x3F)));
+                } else if ((c & 0xD800) != 0xD800 || (c > 0xDBFF))  {
+                    // U+0800..U+FFFF - excluding surrogate pairs
+                    put(pos++, (byte) (0xE0 | ((c >> 12) & 0x0F)));
+                    put(pos++, (byte) (0x80 | ((c >> 6) & 0x3F)));
+                    put(pos++, (byte) (0x80 | (c & 0x3F)));
+                } else {
+                    int low;
+
+                    if ((++i == length) || ((low = value.charAt(i)) & 0xDC00) != 0xDC00) {
+                        throw new IllegalArgumentException("String contains invalid Unicode code points");
+                    }
+
+                    c = 0x010000 + ((c & 0x03FF) << 10) + (low & 0x03FF);
+
+                    put(pos++, (byte) (0xF0 | ((c >> 18) & 0x07)));
+                    put(pos++, (byte) (0x80 | ((c >> 12) & 0x3F)));
+                    put(pos++, (byte) (0x80 | ((c >> 6) & 0x3F)));
+                    put(pos++, (byte) (0x80 | (c & 0x3F)));
+                }
+            }
+
+            // Now move the buffer position to reflect the work done here
+            _buf.position(pos);
+        }
+
+        @Override
+        public int limit() {
             return _buf.limit();
         }
 
-        public ByteBuffer byteBuffer()
-        {
+        public ByteBuffer byteBuffer() {
             return _buf;
         }
 
-        public ReadableBuffer toReadableBuffer()
-        {
+        public ReadableBuffer toReadableBuffer() {
             return ReadableBuffer.ByteBufferReader.wrap((ByteBuffer) _buf.duplicate().flip());
         }
 
         @Override
-        public String toString()
-        {
+        public String toString() {
             return String.format("[pos: %d, limit: %d, remaining:%d]", _buf.position(), _buf.limit(), _buf.remaining());
         }
 
-        public static ByteBufferWrapper allocate(int size)
-        {
+        public static ByteBufferWrapper allocate(int size) {
             ByteBuffer allocated = ByteBuffer.allocate(size);
             return new ByteBufferWrapper(allocated);
         }
 
-        public static ByteBufferWrapper wrap(ByteBuffer buffer)
-        {
+        public static ByteBufferWrapper wrap(ByteBuffer buffer) {
             return new ByteBufferWrapper(buffer);
         }
 
-        public static ByteBufferWrapper wrap(byte[] bytes)
-        {
+        public static ByteBufferWrapper wrap(byte[] bytes) {
             return new ByteBufferWrapper(ByteBuffer.wrap(bytes));
         }
+
+        private void put(int index, byte value) {
+            if (_buf.hasArray()) {
+                _buf.array()[_buf.arrayOffset() + index] = value;
+            } else {
+                _buf.put(index, value);
+            }
+        }
     }
 }

http://git-wip-us.apache.org/repos/asf/qpid-proton-j/blob/7eac8b94/proton-j/src/test/java/org/apache/qpid/proton/codec/Benchmark.java
----------------------------------------------------------------------
diff --git a/proton-j/src/test/java/org/apache/qpid/proton/codec/Benchmark.java b/proton-j/src/test/java/org/apache/qpid/proton/codec/Benchmark.java
index 5dd4077..e1e78ad 100644
--- a/proton-j/src/test/java/org/apache/qpid/proton/codec/Benchmark.java
+++ b/proton-j/src/test/java/org/apache/qpid/proton/codec/Benchmark.java
@@ -34,8 +34,8 @@ import org.apache.qpid.proton.amqp.UnsignedByte;
 import org.apache.qpid.proton.amqp.UnsignedInteger;
 import org.apache.qpid.proton.amqp.UnsignedShort;
 import org.apache.qpid.proton.amqp.messaging.Accepted;
-import org.apache.qpid.proton.amqp.messaging.Data;
 import org.apache.qpid.proton.amqp.messaging.ApplicationProperties;
+import org.apache.qpid.proton.amqp.messaging.Data;
 import org.apache.qpid.proton.amqp.messaging.Header;
 import org.apache.qpid.proton.amqp.messaging.MessageAnnotations;
 import org.apache.qpid.proton.amqp.messaging.Properties;
@@ -243,8 +243,9 @@ public class Benchmark implements Runnable {
 
     private void benchmarkProperties() throws IOException {
         Properties properties = new Properties();
-        properties.setTo("queue:1");
-        properties.setMessageId("ID:Message:1");
+        properties.setTo("queue:1-1024");
+        properties.setReplyTo("queue:1-11024-reply");
+        properties.setMessageId("ID:255f1297-5a71-4df1-8147-b2cdf850a56f:1");
         properties.setCreationTime(new Date(System.currentTimeMillis()));
 
         resultSet.start();
@@ -377,9 +378,9 @@ public class Benchmark implements Runnable {
     }
 
     private void benchmarkString() throws IOException {
-        String string1 = new String("String-1");
-        String string2 = new String("String-2");
-        String string3 = new String("String-3");
+        String string1 = new String("String-1-somewhat-long-test-to-validate-performance-improvements-to-the-proton-j-codec-@!%$");
+        String string2 = new String("String-2-somewhat-long-test-to-validate-performance-improvements-to-the-proton-j-codec-@!%$");
+        String string3 = new String("String-3-somewhat-long-test-to-validate-performance-improvements-to-the-proton-j-codec-@!%$");
 
         resultSet.start();
         for (int i = 0; i < ITERATIONS; i++) {

http://git-wip-us.apache.org/repos/asf/qpid-proton-j/blob/7eac8b94/proton-j/src/test/java/org/apache/qpid/proton/codec/StringTypeTest.java
----------------------------------------------------------------------
diff --git a/proton-j/src/test/java/org/apache/qpid/proton/codec/StringTypeTest.java b/proton-j/src/test/java/org/apache/qpid/proton/codec/StringTypeTest.java
index 944a0f2..3ba2007 100644
--- a/proton-j/src/test/java/org/apache/qpid/proton/codec/StringTypeTest.java
+++ b/proton-j/src/test/java/org/apache/qpid/proton/codec/StringTypeTest.java
@@ -44,13 +44,13 @@ public class StringTypeTest
     private static final List<String> TEST_DATA = generateTestData();
 
     /**
-     * Loop over all the chars in given {@link UnicodeBlock}s and return a
-     * {@link Set <String>} containing all the possible values as their
-     * {@link String} values.
+     * Loop over all the chars in given {@link UnicodeBlock}s and return a {@link Set <String>}
+     * containing all the possible values as their {@link String} values.
      *
-     * @param blocks the {@link UnicodeBlock}s to loop over
-     * @return a {@link Set <String>} containing all the possible values as
-     * {@link String} values
+     * @param blocks
+     *        the {@link UnicodeBlock}s to loop over
+     * @return a {@link Set <String>} containing all the possible values as {@link String}
+     *         values
      */
     private static Set<String> getAllStringsFromUnicodeBlocks(final UnicodeBlock... blocks)
     {
@@ -87,10 +87,9 @@ public class StringTypeTest
         return strings;
     }
 
-
     /**
-     * Test the encoding and decoding of various complicated Unicode characters
-     * which will end up as "surrogate pairs" when encoded to UTF-8
+     * Test the encoding and decoding of various complicated Unicode characters which will end
+     * up as "surrogate pairs" when encoded to UTF-8
      */
     @Test
     public void calculateUTF8Length()
@@ -102,7 +101,7 @@ public class StringTypeTest
     }
 
     /**
-     * Test the encoding and decoding of various  Unicode characters
+     * Test the encoding and decoding of various Unicode characters
      */
     @Test
     public void encodeDecodeStrings()
@@ -225,7 +224,7 @@ public class StringTypeTest
                                                      UnicodeBlock.GREEK,
                                                      UnicodeBlock.LETTERLIKE_SYMBOLS));
                 // blocks with surrogate pairs
-                //TODO: restore others when Java 7 is baseline
+                // TODO: restore others when Java 7 is baseline
                 addAll(getAllStringsFromUnicodeBlocks(UnicodeBlock.LINEAR_B_SYLLABARY,
                                                      /*UnicodeBlock.MISCELLANEOUS_SYMBOLS_AND_PICTOGRAPHS,*/
                                                      UnicodeBlock.MUSICAL_SYMBOLS,
@@ -246,4 +245,113 @@ public class StringTypeTest
             }
         };
     }
+
+    @Test
+    public void testEncodeAndDecodeUsingWritableBufferDefaultPutString() {
+        final DecoderImpl decoder = new DecoderImpl();
+        final EncoderImpl encoder = new EncoderImpl(decoder);
+        AMQPDefinedTypes.registerAllTypes(decoder, encoder);
+
+        for (final String input : TEST_DATA) {
+            final WritableBufferWithoutPutStringOverride sink = new WritableBufferWithoutPutStringOverride(16);
+            final AmqpValue inputValue = new AmqpValue(input);
+            encoder.setByteBuffer(sink);
+            encoder.writeObject(inputValue);
+            ReadableBuffer source = new ReadableBuffer.ByteBufferReader(ByteBuffer.wrap(sink.getArray(), 0, sink.getArrayLength()));
+            decoder.setBuffer(source);
+            final AmqpValue outputValue = (AmqpValue) decoder.readObject();
+            assertEquals("Failed to round trip String correctly: ", input, outputValue.getValue());
+        }
+    }
+
+    /**
+     * Test class which implements WritableBuffer but does not override the default put(String)
+     * method, used to verify the default method is in place and works.
+     */
+    private static final class WritableBufferWithoutPutStringOverride implements WritableBuffer {
+
+        private final ByteBufferWrapper delegate;
+
+        public WritableBufferWithoutPutStringOverride(int capacity) {
+            delegate = WritableBuffer.ByteBufferWrapper.allocate(capacity);
+        }
+
+        public byte[] getArray() {
+            return delegate.byteBuffer().array();
+        }
+
+        public int getArrayLength() {
+            return delegate.byteBuffer().position();
+        }
+
+        @Override
+        public void put(byte b) {
+            delegate.put(b);
+        }
+
+        @Override
+        public void putShort(short value) {
+            delegate.putShort(value);
+        }
+
+        @Override
+        public void putInt(int value) {
+            delegate.putInt(value);
+        }
+
+        @Override
+        public void putLong(long value) {
+            delegate.putLong(value);
+        }
+
+        @Override
+        public void putFloat(float value) {
+            delegate.putFloat(value);
+        }
+
+        @Override
+        public void putDouble(double value) {
+            delegate.putDouble(value);
+        }
+
+        @Override
+        public void put(byte[] src, int offset, int length) {
+            delegate.put(src, offset, length);
+        }
+
+        @Override
+        public boolean hasRemaining() {
+            return delegate.hasRemaining();
+        }
+
+        @Override
+        public int remaining() {
+            return delegate.remaining();
+        }
+
+        @Override
+        public int position() {
+            return delegate.position();
+        }
+
+        @Override
+        public void position(int position) {
+            delegate.position(position);
+        }
+
+        @Override
+        public void put(ByteBuffer payload) {
+            delegate.put(payload);
+        }
+
+        @Override
+        public int limit() {
+            return delegate.limit();
+        }
+
+        @Override
+        public void put(ReadableBuffer src) {
+            delegate.put(src);
+        }
+    }
 }


---------------------------------------------------------------------
To unsubscribe, e-mail: commits-unsubscribe@qpid.apache.org
For additional commands, e-mail: commits-help@qpid.apache.org