From d9d1b8586b4e8af1502c00e35d3dc36690e516ef Mon Sep 17 00:00:00 2001 From: Sunil Ramchandra Pawar Date: Mon, 7 Apr 2025 18:05:40 +0530 Subject: [PATCH] Addding a test cases for specific position BB. --- .../cassandra/utils/FastByteOperations.java | 19 ++- .../utils/FastByteOperationsTest.java | 110 ++++++++++++++++++ 2 files changed, 127 insertions(+), 2 deletions(-) diff --git a/src/java/org/apache/cassandra/utils/FastByteOperations.java b/src/java/org/apache/cassandra/utils/FastByteOperations.java index eff3793d46..8d64a5f2af 100644 --- a/src/java/org/apache/cassandra/utils/FastByteOperations.java +++ b/src/java/org/apache/cassandra/utils/FastByteOperations.java @@ -164,6 +164,7 @@ public class FastByteOperations static final long BYTE_ARRAY_BASE_OFFSET; static final long DIRECT_BUFFER_ADDRESS_OFFSET; static final long HEAP_HB_FIELD_OFFSET; + static final long HEAP_ARRAY_FIELD_OFFSET; static { @@ -197,6 +198,7 @@ public class FastByteOperations BYTE_ARRAY_BASE_OFFSET = theUnsafe.arrayBaseOffset(byte[].class); DIRECT_BUFFER_ADDRESS_OFFSET = theUnsafe.objectFieldOffset(Buffer.class.getDeclaredField("address")); HEAP_HB_FIELD_OFFSET = theUnsafe.objectFieldOffset(ByteBuffer.class.getDeclaredField("hb")); + HEAP_ARRAY_FIELD_OFFSET = theUnsafe.objectFieldOffset(ByteBuffer.class.getDeclaredField("offset")); } catch (Exception e) { @@ -227,16 +229,20 @@ public class FastByteOperations { Object obj1; long offset1; + + // Heap ByteBuffer (Mutable) if (buffer1.hasArray()) { obj1 = buffer1.array(); offset1 = BYTE_ARRAY_BASE_OFFSET + buffer1.arrayOffset() + position1; } + // Read-Only Heap ByteBuffer (Still has hb but read-only) else if (buffer1.isReadOnly() && !buffer1.isDirect()) { obj1 = theUnsafe.getObject(buffer1, HEAP_HB_FIELD_OFFSET); - offset1 = BYTE_ARRAY_BASE_OFFSET; + offset1 = BYTE_ARRAY_BASE_OFFSET + position1; } + // Direct ByteBuffer else { obj1 = null; @@ -287,7 +293,8 @@ public class FastByteOperations else if (srcBuf.isReadOnly() && !srcBuf.isDirect()) { src = theUnsafe.getObject(srcBuf, HEAP_HB_FIELD_OFFSET); - srcOffset = BYTE_ARRAY_BASE_OFFSET; + int arrayOffset = theUnsafe.getInt(srcBuf, HEAP_ARRAY_FIELD_OFFSET); + srcOffset = BYTE_ARRAY_BASE_OFFSET + arrayOffset ; } // Direct ByteBuffer else @@ -343,16 +350,20 @@ public class FastByteOperations Object obj1; long offset1; int length1; + + // Heap ByteBuffer (Mutable) if (buffer1.hasArray()) { obj1 = buffer1.array(); offset1 = BYTE_ARRAY_BASE_OFFSET + buffer1.arrayOffset(); } + // Read-Only Heap ByteBuffer (Still has hb but read-only) else if (buffer1.isReadOnly() && !buffer1.isDirect()) { obj1 = theUnsafe.getObject(buffer1, HEAP_HB_FIELD_OFFSET); offset1 = BYTE_ARRAY_BASE_OFFSET; } + // Direct ByteBuffer else { obj1 = null; @@ -372,16 +383,20 @@ public class FastByteOperations int position = buffer.position(); int limit = buffer.limit(); + + // Heap ByteBuffer (Mutable) if (buffer.hasArray()) { obj2 = buffer.array(); offset2 = BYTE_ARRAY_BASE_OFFSET + buffer.arrayOffset(); } + // Read-Only Heap ByteBuffer (Still has hb but read-only) else if (buffer.isReadOnly() && !buffer.isDirect()) { obj2 = theUnsafe.getObject(buffer, HEAP_HB_FIELD_OFFSET); offset2 = BYTE_ARRAY_BASE_OFFSET; } + // Direct ByteBuffer else { obj2 = null; diff --git a/test/unit/org/apache/cassandra/utils/FastByteOperationsTest.java b/test/unit/org/apache/cassandra/utils/FastByteOperationsTest.java index e2bc4d7d71..5776dbcc82 100644 --- a/test/unit/org/apache/cassandra/utils/FastByteOperationsTest.java +++ b/test/unit/org/apache/cassandra/utils/FastByteOperationsTest.java @@ -20,6 +20,7 @@ package org.apache.cassandra.utils; import java.nio.ByteBuffer; import java.util.Arrays; import java.util.Random; +import java.util.concurrent.ThreadLocalRandom; import org.junit.Test; @@ -66,6 +67,44 @@ public class FastByteOperationsTest testCopy(bytes1, wrap1(bytes1, false).asReadOnlyBuffer(), wrap2(empty, false), UO); } + @Test + public void testFastByteCopyWithPoistion() + { + byte[] bytes1 = new byte[128]; + byte[] empty = new byte[128]; + rand.nextBytes(bytes1); + + int randomPos = ThreadLocalRandom.current().nextInt(0, 101); + + testCopyWithPosition(bytes1, wrapR(bytes1, true, randomPos).asReadOnlyBuffer(), wrapR1(empty, true, randomPos), PJO, randomPos); + randomPos = ThreadLocalRandom.current().nextInt(0, 101); + testCopyWithPosition(bytes1, wrapR(bytes1, true, randomPos).asReadOnlyBuffer(), wrapR1(empty, false, randomPos), PJO, randomPos); + randomPos = ThreadLocalRandom.current().nextInt(0, 101); + testCopyWithPosition(bytes1, wrapR(bytes1, false, randomPos).asReadOnlyBuffer(), wrapR1(empty, true, randomPos), PJO, randomPos); + randomPos = ThreadLocalRandom.current().nextInt(0, 101); + testCopyWithPosition(bytes1, wrapR(bytes1, false, randomPos).asReadOnlyBuffer(), wrapR1(empty, false, randomPos), PJO, randomPos); + randomPos = ThreadLocalRandom.current().nextInt(0, 101); + testCopyWithPosition(bytes1, wrapR(bytes1, true, randomPos).asReadOnlyBuffer(), wrapR1(empty, true, randomPos), UO, randomPos); + randomPos = ThreadLocalRandom.current().nextInt(0, 101); + testCopyWithPosition(bytes1, wrapR(bytes1, true, randomPos).asReadOnlyBuffer(), wrapR1(empty, false, randomPos), UO, randomPos); + randomPos = ThreadLocalRandom.current().nextInt(0, 101); + testCopyWithPosition(bytes1, wrapR(bytes1, false, randomPos).asReadOnlyBuffer(), wrapR1(empty, true, randomPos), UO, randomPos); + randomPos = ThreadLocalRandom.current().nextInt(0, 101); + testCopyWithPosition(bytes1, wrapR(bytes1, false, randomPos).asReadOnlyBuffer(), wrapR1(empty, false, randomPos), UO, randomPos); + + } + + + private void testCopyWithPosition(byte[] canon, ByteBuffer src, ByteBuffer trg, FastByteOperations.ByteOperations ops, int position) + { + byte[] result = new byte[src.remaining()]; + byte[] canonSubArray = Arrays.copyOfRange(canon, position, canon.length); + ops.copy(src, src.position(), trg, trg.position(), src.remaining()); + ops.copy(trg, trg.position(), result, 0, trg.remaining()); + assert firstdiff(canonSubArray, result) < 0; + } + + private void testCopy(byte[] canon, ByteBuffer src, ByteBuffer trg, FastByteOperations.ByteOperations ops) { byte[] result = new byte[src.remaining()]; @@ -102,6 +141,38 @@ public class FastByteOperationsTest } } + @Test + public void testFastByteCompareRandomRead() + { + byte[] bytes1 = new byte[128]; + for (int i = 0 ; i < 1000 ; i++) + { + rand.nextBytes(bytes1); + for (int j = 0 ; j < 16 ; j++) + { + byte[] bytes2 = Arrays.copyOf(bytes1, bytes1.length - j); + testTwiddleOneByteComparisonsReadOnly(bytes1, bytes2, 16, true, 1); + testTwiddleOneByteComparisonsReadOnly(bytes1, bytes2, 16, true, -1); + testTwiddleOneByteComparisonsReadOnly(bytes1, bytes2, 16, false, 1); + testTwiddleOneByteComparisonsReadOnly(bytes1, bytes2, 16, false, -1); + testTwiddleOneByteComparisonsReadOnly(bytes1, bytes2, 16, true, 128); + testTwiddleOneByteComparisonsReadOnly(bytes1, bytes2, 16, false, 128); + } + } + } + + + private void testTwiddleOneByteComparisonsReadOnly(byte[] bytes1, byte[] bytes2, int count, boolean start, int inc) + { + for (int j = 0 ; j < count ; j++) + { + int index = start ? j : bytes2.length - (j + 1); + bytes2[index] += inc; + testComparisonsReadOnly(bytes1, bytes2); + bytes2[index] -= inc; + } + } + private void testTwiddleOneByteComparisons(byte[] bytes1, byte[] bytes2, int count, boolean start, int inc) { for (int j = 0 ; j < count ; j++) @@ -132,6 +203,45 @@ public class FastByteOperationsTest return buf; } + private static ByteBuffer wrapR(byte[] bytes, boolean direct, int position) + { + return sliceR(bytes, direct ? dbuf1 : hbuf1, position); + } + + private static ByteBuffer wrapR1(byte[] bytes, boolean direct, int position) + { + return sliceR(bytes, direct ? dbuf2 : hbuf2, position); + } + + private static ByteBuffer sliceR(byte[] bytes, ByteBuffer buf, int position) + { + buf = buf.duplicate(); + buf.put(bytes); + buf.position(position); + buf = buf.slice(); + + return buf; + + } + + private void testComparisonsReadOnly(byte[] bytes1, byte[] bytes2) + { + testComparison(bytes1, bytes2); + testComparison(bytes2, bytes1); + testComparison(wrap1(bytes1, false).asReadOnlyBuffer(), bytes2); + testComparison(wrap2(bytes2, false).asReadOnlyBuffer(), bytes1); + testComparison(wrap1(bytes1, false).asReadOnlyBuffer(), wrap2(bytes2, false)); + testComparison(wrap2(bytes2, false).asReadOnlyBuffer(), wrap1(bytes1, false)); + testComparison(wrap1(bytes1, true).asReadOnlyBuffer(), bytes2); + testComparison(wrap2(bytes2, true).asReadOnlyBuffer(), bytes1); + testComparison(wrap1(bytes1, true).asReadOnlyBuffer(), wrap2(bytes2, true)); + testComparison(wrap2(bytes2, true).asReadOnlyBuffer(), wrap1(bytes1, true)); + testComparison(wrap1(bytes1, true).asReadOnlyBuffer(), wrap2(bytes2, false)); + testComparison(wrap1(bytes1, false).asReadOnlyBuffer(), wrap2(bytes2, true)); + testComparison(wrap2(bytes2, true).asReadOnlyBuffer(), wrap1(bytes1, false)); + testComparison(wrap2(bytes2, false).asReadOnlyBuffer(), wrap1(bytes1, true)); + } + private void testComparisons(byte[] bytes1, byte[] bytes2) { testComparison(bytes1, bytes2);