From 6f413eef873d530139faa7160974a93a8f7de191 Mon Sep 17 00:00:00 2001 From: Sunil Ramchandra Pawar Date: Thu, 27 Mar 2025 13:04:59 +0530 Subject: [PATCH 1/7] Adding a case to handle read-only BB. --- .../cassandra/utils/FastByteOperations.java | 24 ++++++++++++++++--- .../utils/FastByteOperationsTest.java | 16 +++++++++++++ 2 files changed, 37 insertions(+), 3 deletions(-) diff --git a/src/java/org/apache/cassandra/utils/FastByteOperations.java b/src/java/org/apache/cassandra/utils/FastByteOperations.java index 2a86712951..b1514543d2 100644 --- a/src/java/org/apache/cassandra/utils/FastByteOperations.java +++ b/src/java/org/apache/cassandra/utils/FastByteOperations.java @@ -163,6 +163,7 @@ public class FastByteOperations */ static final long BYTE_ARRAY_BASE_OFFSET; static final long DIRECT_BUFFER_ADDRESS_OFFSET; + static final long HEAP_HB_FIELD; static { @@ -195,6 +196,8 @@ public class FastByteOperations { BYTE_ARRAY_BASE_OFFSET = theUnsafe.arrayBaseOffset(byte[].class); DIRECT_BUFFER_ADDRESS_OFFSET = theUnsafe.objectFieldOffset(Buffer.class.getDeclaredField("address")); + + HEAP_HB_FIELD = theUnsafe.objectFieldOffset(ByteBuffer.class.getDeclaredField("hb")); } catch (Exception e) { @@ -269,16 +272,31 @@ public class FastByteOperations { Object src; long srcOffset; - if (srcBuf.hasArray()) + + // Heap ByteBuffer (Mutable) + if (srcBuf.hasArray() && !srcBuf.isReadOnly()) { - src = srcBuf.array(); - srcOffset = BYTE_ARRAY_BASE_OFFSET + srcBuf.arrayOffset(); + src = theUnsafe.getObject(srcBuf, HEAP_HB_FIELD); + srcOffset = BYTE_ARRAY_BASE_OFFSET; } + // Read-Only Heap ByteBuffer (Still has hb but read-only) + else if (srcBuf.isReadOnly() && !srcBuf.isDirect()) + { + src = theUnsafe.getObject(srcBuf, HEAP_HB_FIELD); + srcOffset = BYTE_ARRAY_BASE_OFFSET; + + if (src == null) + { + throw new IllegalArgumentException("Unsupported ByteBuffer type: No backing array and not direct."); + } + } + // Direct ByteBuffer else { src = null; srcOffset = theUnsafe.getLong(srcBuf, DIRECT_BUFFER_ADDRESS_OFFSET); } + copy(src, srcOffset + srcPosition, trgBuf, trgPosition, length); } diff --git a/test/unit/org/apache/cassandra/utils/FastByteOperationsTest.java b/test/unit/org/apache/cassandra/utils/FastByteOperationsTest.java index 4f6d6523f8..e2bc4d7d71 100644 --- a/test/unit/org/apache/cassandra/utils/FastByteOperationsTest.java +++ b/test/unit/org/apache/cassandra/utils/FastByteOperationsTest.java @@ -50,6 +50,22 @@ public class FastByteOperationsTest testCopy(bytes1, wrap1(bytes1, false), wrap2(empty, false), UO); } + @Test + public void testFastByteCopyReadOnly() + { + byte[] bytes1 = new byte[128]; + byte[] empty = new byte[128]; + rand.nextBytes(bytes1); + testCopy(bytes1, wrap1(bytes1, true).asReadOnlyBuffer(), wrap2(empty, true), PJO); + testCopy(bytes1, wrap1(bytes1, true).asReadOnlyBuffer(), wrap2(empty, false), PJO); + testCopy(bytes1, wrap1(bytes1, false).asReadOnlyBuffer(), wrap2(empty, true), PJO); + testCopy(bytes1, wrap1(bytes1, false).asReadOnlyBuffer(), wrap2(empty, false), PJO); + testCopy(bytes1, wrap1(bytes1, true).asReadOnlyBuffer(), wrap2(empty, true), UO); + testCopy(bytes1, wrap1(bytes1, true).asReadOnlyBuffer(), wrap2(empty, false), UO); + testCopy(bytes1, wrap1(bytes1, false).asReadOnlyBuffer(), wrap2(empty, true), UO); + testCopy(bytes1, wrap1(bytes1, false).asReadOnlyBuffer(), wrap2(empty, false), UO); + } + private void testCopy(byte[] canon, ByteBuffer src, ByteBuffer trg, FastByteOperations.ByteOperations ops) { byte[] result = new byte[src.remaining()]; From b9ebbfb2682e42e43fe9d657c04a346152bfcadc Mon Sep 17 00:00:00 2001 From: Sunil Ramchandra Pawar Date: Thu, 27 Mar 2025 23:34:22 +0530 Subject: [PATCH 2/7] nit changes, reverting to orginal condition and adding READ_ONLY_HEAP to Generators. --- src/java/org/apache/cassandra/utils/FastByteOperations.java | 5 ++--- test/unit/org/apache/cassandra/utils/Generators.java | 2 +- 2 files changed, 3 insertions(+), 4 deletions(-) diff --git a/src/java/org/apache/cassandra/utils/FastByteOperations.java b/src/java/org/apache/cassandra/utils/FastByteOperations.java index b1514543d2..41f084d842 100644 --- a/src/java/org/apache/cassandra/utils/FastByteOperations.java +++ b/src/java/org/apache/cassandra/utils/FastByteOperations.java @@ -196,7 +196,6 @@ public class FastByteOperations { BYTE_ARRAY_BASE_OFFSET = theUnsafe.arrayBaseOffset(byte[].class); DIRECT_BUFFER_ADDRESS_OFFSET = theUnsafe.objectFieldOffset(Buffer.class.getDeclaredField("address")); - HEAP_HB_FIELD = theUnsafe.objectFieldOffset(ByteBuffer.class.getDeclaredField("hb")); } catch (Exception e) @@ -276,8 +275,8 @@ public class FastByteOperations // Heap ByteBuffer (Mutable) if (srcBuf.hasArray() && !srcBuf.isReadOnly()) { - src = theUnsafe.getObject(srcBuf, HEAP_HB_FIELD); - srcOffset = BYTE_ARRAY_BASE_OFFSET; + src = srcBuf.array(); + srcOffset = BYTE_ARRAY_BASE_OFFSET + srcBuf.arrayOffset(); } // Read-Only Heap ByteBuffer (Still has hb but read-only) else if (srcBuf.isReadOnly() && !srcBuf.isDirect()) diff --git a/test/unit/org/apache/cassandra/utils/Generators.java b/test/unit/org/apache/cassandra/utils/Generators.java index 5f99421240..41f3d99f0d 100644 --- a/test/unit/org/apache/cassandra/utils/Generators.java +++ b/test/unit/org/apache/cassandra/utils/Generators.java @@ -365,7 +365,7 @@ public final class Generators public static Gen bytes(int min, int max) { - return bytes(min, max, SourceDSL.arbitrary().constant(BBCases.HEAP)); + return bytes(min, max, SourceDSL.arbitrary().pick(BBCases.HEAP, BBCases.READ_ONLY_HEAP)); } public static Gen directBytes(int min, int max) From f429810c8f3858721589feb6e10d36c043a71f5c Mon Sep 17 00:00:00 2001 From: Sunil Ramchandra Pawar Date: Thu, 27 Mar 2025 23:51:01 +0530 Subject: [PATCH 3/7] nit, removing unnecessary brackets. --- src/java/org/apache/cassandra/utils/FastByteOperations.java | 2 -- 1 file changed, 2 deletions(-) diff --git a/src/java/org/apache/cassandra/utils/FastByteOperations.java b/src/java/org/apache/cassandra/utils/FastByteOperations.java index 41f084d842..b4c12de738 100644 --- a/src/java/org/apache/cassandra/utils/FastByteOperations.java +++ b/src/java/org/apache/cassandra/utils/FastByteOperations.java @@ -285,9 +285,7 @@ public class FastByteOperations srcOffset = BYTE_ARRAY_BASE_OFFSET; if (src == null) - { throw new IllegalArgumentException("Unsupported ByteBuffer type: No backing array and not direct."); - } } // Direct ByteBuffer else From 9f5af41c8d200b9939e6104a564e512d34946a6b Mon Sep 17 00:00:00 2001 From: Sunil Ramchandra Pawar Date: Tue, 1 Apr 2025 18:23:25 +0530 Subject: [PATCH 4/7] Added conditions of read-only BB for compare functions as well. --- .../cassandra/utils/FastByteOperations.java | 27 ++++++++++++++----- 1 file changed, 20 insertions(+), 7 deletions(-) diff --git a/src/java/org/apache/cassandra/utils/FastByteOperations.java b/src/java/org/apache/cassandra/utils/FastByteOperations.java index b4c12de738..eff3793d46 100644 --- a/src/java/org/apache/cassandra/utils/FastByteOperations.java +++ b/src/java/org/apache/cassandra/utils/FastByteOperations.java @@ -163,7 +163,7 @@ public class FastByteOperations */ static final long BYTE_ARRAY_BASE_OFFSET; static final long DIRECT_BUFFER_ADDRESS_OFFSET; - static final long HEAP_HB_FIELD; + static final long HEAP_HB_FIELD_OFFSET; static { @@ -196,7 +196,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 = theUnsafe.objectFieldOffset(ByteBuffer.class.getDeclaredField("hb")); + HEAP_HB_FIELD_OFFSET = theUnsafe.objectFieldOffset(ByteBuffer.class.getDeclaredField("hb")); } catch (Exception e) { @@ -232,6 +232,11 @@ public class FastByteOperations obj1 = buffer1.array(); offset1 = BYTE_ARRAY_BASE_OFFSET + buffer1.arrayOffset() + position1; } + else if (buffer1.isReadOnly() && !buffer1.isDirect()) + { + obj1 = theUnsafe.getObject(buffer1, HEAP_HB_FIELD_OFFSET); + offset1 = BYTE_ARRAY_BASE_OFFSET; + } else { obj1 = null; @@ -273,7 +278,7 @@ public class FastByteOperations long srcOffset; // Heap ByteBuffer (Mutable) - if (srcBuf.hasArray() && !srcBuf.isReadOnly()) + if (srcBuf.hasArray()) { src = srcBuf.array(); srcOffset = BYTE_ARRAY_BASE_OFFSET + srcBuf.arrayOffset(); @@ -281,11 +286,8 @@ public class FastByteOperations // Read-Only Heap ByteBuffer (Still has hb but read-only) else if (srcBuf.isReadOnly() && !srcBuf.isDirect()) { - src = theUnsafe.getObject(srcBuf, HEAP_HB_FIELD); + src = theUnsafe.getObject(srcBuf, HEAP_HB_FIELD_OFFSET); srcOffset = BYTE_ARRAY_BASE_OFFSET; - - if (src == null) - throw new IllegalArgumentException("Unsupported ByteBuffer type: No backing array and not direct."); } // Direct ByteBuffer else @@ -346,11 +348,17 @@ public class FastByteOperations obj1 = buffer1.array(); offset1 = BYTE_ARRAY_BASE_OFFSET + buffer1.arrayOffset(); } + else if (buffer1.isReadOnly() && !buffer1.isDirect()) + { + obj1 = theUnsafe.getObject(buffer1, HEAP_HB_FIELD_OFFSET); + offset1 = BYTE_ARRAY_BASE_OFFSET; + } else { obj1 = null; offset1 = theUnsafe.getLong(buffer1, DIRECT_BUFFER_ADDRESS_OFFSET); } + offset1 += buffer1.position(); length1 = buffer1.remaining(); return compareTo(obj1, offset1, length1, buffer2); @@ -369,6 +377,11 @@ public class FastByteOperations obj2 = buffer.array(); offset2 = BYTE_ARRAY_BASE_OFFSET + buffer.arrayOffset(); } + else if (buffer.isReadOnly() && !buffer.isDirect()) + { + obj2 = theUnsafe.getObject(buffer, HEAP_HB_FIELD_OFFSET); + offset2 = BYTE_ARRAY_BASE_OFFSET; + } else { obj2 = null; From d9d1b8586b4e8af1502c00e35d3dc36690e516ef Mon Sep 17 00:00:00 2001 From: Sunil Ramchandra Pawar Date: Mon, 7 Apr 2025 18:05:40 +0530 Subject: [PATCH 5/7] 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); From cec1534a7f432785bf6aeb1265113226c16c324a Mon Sep 17 00:00:00 2001 From: Sunil Ramchandra Pawar Date: Tue, 29 Jul 2025 20:59:33 +0530 Subject: [PATCH 6/7] moving the direct BB condition first. --- .../cassandra/utils/FastByteOperations.java | 49 ++++++++++--------- 1 file changed, 25 insertions(+), 24 deletions(-) diff --git a/src/java/org/apache/cassandra/utils/FastByteOperations.java b/src/java/org/apache/cassandra/utils/FastByteOperations.java index 8d64a5f2af..1bd52a0bc9 100644 --- a/src/java/org/apache/cassandra/utils/FastByteOperations.java +++ b/src/java/org/apache/cassandra/utils/FastByteOperations.java @@ -230,24 +230,24 @@ public class FastByteOperations Object obj1; long offset1; + // Direct ByteBuffer + if (buffer1.isDirect()) + { + obj1 = null; + offset1 = theUnsafe.getLong(buffer1, DIRECT_BUFFER_ADDRESS_OFFSET) + position1; + } // Heap ByteBuffer (Mutable) - if (buffer1.hasArray()) + else 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()) + else { obj1 = theUnsafe.getObject(buffer1, HEAP_HB_FIELD_OFFSET); offset1 = BYTE_ARRAY_BASE_OFFSET + position1; } - // Direct ByteBuffer - else - { - obj1 = null; - offset1 = theUnsafe.getLong(buffer1, DIRECT_BUFFER_ADDRESS_OFFSET) + position1; - } return compareTo(obj1, offset1, length1, buffer2, BYTE_ARRAY_BASE_OFFSET + offset2, length2); } @@ -351,24 +351,24 @@ public class FastByteOperations long offset1; int length1; + // Direct ByteBuffer + if (buffer1.isDirect()) + { + obj1 = null; + offset1 = theUnsafe.getLong(buffer1, DIRECT_BUFFER_ADDRESS_OFFSET); + } // Heap ByteBuffer (Mutable) - if (buffer1.hasArray()) + else 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()) + else { obj1 = theUnsafe.getObject(buffer1, HEAP_HB_FIELD_OFFSET); offset1 = BYTE_ARRAY_BASE_OFFSET; } - // Direct ByteBuffer - else - { - obj1 = null; - offset1 = theUnsafe.getLong(buffer1, DIRECT_BUFFER_ADDRESS_OFFSET); - } offset1 += buffer1.position(); length1 = buffer1.remaining(); @@ -384,24 +384,25 @@ public class FastByteOperations int position = buffer.position(); int limit = buffer.limit(); + // Direct ByteBuffer + if (buffer.isDirect()) + { + obj2 = null; + offset2 = theUnsafe.getLong(buffer, DIRECT_BUFFER_ADDRESS_OFFSET); + } // Heap ByteBuffer (Mutable) - if (buffer.hasArray()) + else 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()) + else { obj2 = theUnsafe.getObject(buffer, HEAP_HB_FIELD_OFFSET); offset2 = BYTE_ARRAY_BASE_OFFSET; } - // Direct ByteBuffer - else - { - obj2 = null; - offset2 = theUnsafe.getLong(buffer, DIRECT_BUFFER_ADDRESS_OFFSET); - } + int length2 = limit - position; offset2 += position; From 57a0dbc89945e4e645bc57043efd46589d6f07a1 Mon Sep 17 00:00:00 2001 From: Sunil Ramchandra Pawar Date: Tue, 29 Jul 2025 21:17:33 +0530 Subject: [PATCH 7/7] Moving read only check condition at the end. --- .../cassandra/utils/FastByteOperations.java | 15 ++++++++------- 1 file changed, 8 insertions(+), 7 deletions(-) diff --git a/src/java/org/apache/cassandra/utils/FastByteOperations.java b/src/java/org/apache/cassandra/utils/FastByteOperations.java index 1bd52a0bc9..4e452c0efc 100644 --- a/src/java/org/apache/cassandra/utils/FastByteOperations.java +++ b/src/java/org/apache/cassandra/utils/FastByteOperations.java @@ -283,25 +283,26 @@ public class FastByteOperations Object src; long srcOffset; + // Direct ByteBuffer + if (srcBuf.isDirect()) + { + src = null; + srcOffset = theUnsafe.getLong(srcBuf, DIRECT_BUFFER_ADDRESS_OFFSET); + } // Heap ByteBuffer (Mutable) - if (srcBuf.hasArray()) + else if (srcBuf.hasArray()) { src = srcBuf.array(); srcOffset = BYTE_ARRAY_BASE_OFFSET + srcBuf.arrayOffset(); } // Read-Only Heap ByteBuffer (Still has hb but read-only) - else if (srcBuf.isReadOnly() && !srcBuf.isDirect()) + else { src = theUnsafe.getObject(srcBuf, HEAP_HB_FIELD_OFFSET); int arrayOffset = theUnsafe.getInt(srcBuf, HEAP_ARRAY_FIELD_OFFSET); srcOffset = BYTE_ARRAY_BASE_OFFSET + arrayOffset ; } // Direct ByteBuffer - else - { - src = null; - srcOffset = theUnsafe.getLong(srcBuf, DIRECT_BUFFER_ADDRESS_OFFSET); - } copy(src, srcOffset + srcPosition, trgBuf, trgPosition, length); }