PROTON-1965: also apply optimisation when the compared span is within the current array
diff --git a/proton-j/src/main/java/org/apache/qpid/proton/codec/CompositeReadableBuffer.java b/proton-j/src/main/java/org/apache/qpid/proton/codec/CompositeReadableBuffer.java
index 409b192..5310faf 100644
--- a/proton-j/src/main/java/org/apache/qpid/proton/codec/CompositeReadableBuffer.java
+++ b/proton-j/src/main/java/org/apache/qpid/proton/codec/CompositeReadableBuffer.java
@@ -103,6 +103,7 @@
return currentArray != null && (contents == null || contents.size() == 1);
}
+ @Override
public int capacity() {
return capacity;
}
@@ -840,7 +841,14 @@
return false;
}
- if (hasArray()) {
+ if (remaining == 0) {
+ // No content to compare, and we already checked 'remaining' is equal. Protects from NPE below.
+ return true;
+ }
+
+ if (hasArray() || remaining <= currentArray.length - currentOffset) {
+ // Either there is only one array, or the span to compare is within a single chunk of this buffer,
+ // allowing the compare to directly access the underlying array instead of using slower get methods.
return equals(currentArray, currentOffset, remaining, buffer);
} else {
return equals(this, buffer);
diff --git a/proton-j/src/test/java/org/apache/qpid/proton/codec/CompositeReadableBufferTest.java b/proton-j/src/test/java/org/apache/qpid/proton/codec/CompositeReadableBufferTest.java
index 5325f17..84c63f7 100644
--- a/proton-j/src/test/java/org/apache/qpid/proton/codec/CompositeReadableBufferTest.java
+++ b/proton-j/src/test/java/org/apache/qpid/proton/codec/CompositeReadableBufferTest.java
@@ -3696,6 +3696,68 @@
assertEquals(0, buffer2.position());
}
+ @Test
+ public void testEqualsWhenContentRemainingIsSubsetOfSingleChunkInMultiArrayBufferSame() {
+ CompositeReadableBuffer buffer1 = new CompositeReadableBuffer();
+ CompositeReadableBuffer buffer2 = new CompositeReadableBuffer();
+
+ byte[] data1 = new byte[] {-1, -1, 0, 1, 2, 3, 4, 5};
+ byte[] data2 = new byte[] {-1, -1, -1, 0, 1, 2, 3, 4, 5};
+
+ buffer1.append(data1);
+ buffer1.position(2);
+
+ buffer2.append(data2);
+ buffer2.position(3);
+
+ byte[] data3 = new byte[] { 5, 4, 3, 2, 1 };
+ buffer1.append(data3);
+ buffer2.append(data3);
+
+ buffer1.limit(data1.length);
+ buffer2.limit(data2.length);
+
+ assertEquals(6, buffer1.remaining());
+ assertEquals(6, buffer2.remaining());
+
+ assertEquals(buffer1, buffer2);
+ assertEquals(buffer2, buffer1);
+
+ assertEquals(2, buffer1.position());
+ assertEquals(3, buffer2.position());
+ }
+
+ @Test
+ public void testEqualsWhenContentRemainingIsSubsetOfSingleChunkInMultiArrayBufferNotSame() {
+ CompositeReadableBuffer buffer1 = new CompositeReadableBuffer();
+ CompositeReadableBuffer buffer2 = new CompositeReadableBuffer();
+
+ byte[] data1 = new byte[] {-1, -1, 0, 1, 2, 3, 4, 5};
+ byte[] data2 = new byte[] {-1, -1, -1, 0, 1, 2, 3, 4, -1};
+
+ buffer1.append(data1);
+ buffer1.position(2);
+
+ buffer2.append(data2);
+ buffer2.position(3);
+
+ byte[] data3 = new byte[] { 5, 4, 3, 2, 1 };
+ buffer1.append(data3);
+ buffer2.append(data3);
+
+ buffer1.limit(data1.length);
+ buffer2.limit(data2.length);
+
+ assertEquals(6, buffer1.remaining());
+ assertEquals(6, buffer2.remaining());
+
+ assertNotEquals(buffer1, buffer2);
+ assertNotEquals(buffer2, buffer1);
+
+ assertEquals(2, buffer1.position());
+ assertEquals(3, buffer2.position());
+ }
+
//----- Utility Methods --------------------------------------------------//
private void assertContentEquals(CompositeReadableBuffer buffer, byte array[], int offset, int length) {
diff --git a/tests/performance-jmh/src/main/java/org/apache/qpid/proton/codec/CompositeReadableBufferBenchmark.java b/tests/performance-jmh/src/main/java/org/apache/qpid/proton/codec/CompositeReadableBufferBenchmark.java
index 4d58a68..4eda8fd 100644
--- a/tests/performance-jmh/src/main/java/org/apache/qpid/proton/codec/CompositeReadableBufferBenchmark.java
+++ b/tests/performance-jmh/src/main/java/org/apache/qpid/proton/codec/CompositeReadableBufferBenchmark.java
@@ -46,6 +46,8 @@
private boolean direct;
@Param({"1", "2"})
private int chunks;
+ private CompositeReadableBuffer compositePartial;
+ private ReadableBuffer bufferReaderPartial;
@Setup
public void init() {
@@ -62,6 +64,9 @@
byte[] lastChunk = new byte[remaining];
composite.append(lastChunk);
}
+
+ compositePartial = composite.duplicate().limit(sizePerChunk);
+ bufferReaderPartial = bufferReader.duplicate().limit(sizePerChunk);
}
@Benchmark
@@ -70,6 +75,12 @@
return composite.equals(bufferReader);
}
+ @Benchmark
+ public boolean equalsToWithSingleArraySubsetOfBuffer() {
+ compositePartial.position(0);
+ return compositePartial.equals(bufferReaderPartial);
+ }
+
public static void main(String[] args) throws RunnerException {
runBenchmark(CompositeReadableBuffer.class);
}