Compare commits

...

8 Commits

Author SHA1 Message Date
Sunil Ramchandra Pawar 63958f87cf
Merge 57a0dbc899 into bdbdf8d710 2026-07-29 13:36:33 +08:00
Sunil Ramchandra Pawar 57a0dbc899 Moving read only check condition at the end. 2025-07-29 21:17:33 +05:30
Sunil Ramchandra Pawar cec1534a7f moving the direct BB condition first. 2025-07-29 20:59:33 +05:30
Sunil Ramchandra Pawar d9d1b8586b Addding a test cases for specific position BB. 2025-04-07 18:05:40 +05:30
Sunil Ramchandra Pawar 9f5af41c8d Added conditions of read-only BB for compare functions as well. 2025-04-01 18:23:25 +05:30
Sunil Ramchandra Pawar f429810c8f nit, removing unnecessary brackets. 2025-03-27 23:51:01 +05:30
Sunil Ramchandra Pawar b9ebbfb268 nit changes, reverting to orginal condition and adding READ_ONLY_HEAP to Generators. 2025-03-27 23:34:22 +05:30
Sunil Ramchandra Pawar 6f413eef87 Adding a case to handle read-only BB. 2025-03-27 13:04:59 +05:30
3 changed files with 193 additions and 22 deletions

View File

@ -186,6 +186,8 @@ 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
{
@ -218,6 +220,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_OFFSET = theUnsafe.objectFieldOffset(ByteBuffer.class.getDeclaredField("hb"));
HEAP_ARRAY_FIELD_OFFSET = theUnsafe.objectFieldOffset(ByteBuffer.class.getDeclaredField("offset"));
}
catch (Exception e)
{
@ -286,15 +290,24 @@ public class FastByteOperations
{
Object obj1;
long offset1;
if (buffer1.hasArray())
// Direct ByteBuffer
if (buffer1.isDirect())
{
obj1 = null;
offset1 = theUnsafe.getLong(buffer1, DIRECT_BUFFER_ADDRESS_OFFSET) + position1;
}
// Heap ByteBuffer (Mutable)
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
{
obj1 = null;
offset1 = theUnsafe.getLong(buffer1, DIRECT_BUFFER_ADDRESS_OFFSET) + position1;
obj1 = theUnsafe.getObject(buffer1, HEAP_HB_FIELD_OFFSET);
offset1 = BYTE_ARRAY_BASE_OFFSET + position1;
}
return compareTo(obj1, offset1, length1, buffer2, BYTE_ARRAY_BASE_OFFSET + offset2, length2);
@ -330,16 +343,28 @@ public class FastByteOperations
{
Object src;
long srcOffset;
if (srcBuf.hasArray())
{
src = srcBuf.array();
srcOffset = BYTE_ARRAY_BASE_OFFSET + srcBuf.arrayOffset();
}
else
// Direct ByteBuffer
if (srcBuf.isDirect())
{
src = null;
srcOffset = theUnsafe.getLong(srcBuf, DIRECT_BUFFER_ADDRESS_OFFSET);
}
// Heap ByteBuffer (Mutable)
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
{
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
copy(src, srcOffset + srcPosition, trgBuf, trgPosition, length);
}
@ -387,16 +412,26 @@ public class FastByteOperations
Object obj1;
long offset1;
int length1;
if (buffer1.hasArray())
{
obj1 = buffer1.array();
offset1 = BYTE_ARRAY_BASE_OFFSET + buffer1.arrayOffset();
}
else
// Direct ByteBuffer
if (buffer1.isDirect())
{
obj1 = null;
offset1 = theUnsafe.getLong(buffer1, DIRECT_BUFFER_ADDRESS_OFFSET);
}
// Heap ByteBuffer (Mutable)
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
{
obj1 = theUnsafe.getObject(buffer1, HEAP_HB_FIELD_OFFSET);
offset1 = BYTE_ARRAY_BASE_OFFSET;
}
offset1 += buffer1.position();
length1 = buffer1.remaining();
return compareTo(obj1, offset1, length1, buffer2);
@ -410,16 +445,26 @@ public class FastByteOperations
int position = buffer.position();
int limit = buffer.limit();
if (buffer.hasArray())
{
obj2 = buffer.array();
offset2 = BYTE_ARRAY_BASE_OFFSET + buffer.arrayOffset();
}
else
// Direct ByteBuffer
if (buffer.isDirect())
{
obj2 = null;
offset2 = theUnsafe.getLong(buffer, DIRECT_BUFFER_ADDRESS_OFFSET);
}
// Heap ByteBuffer (Mutable)
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
{
obj2 = theUnsafe.getObject(buffer, HEAP_HB_FIELD_OFFSET);
offset2 = BYTE_ARRAY_BASE_OFFSET;
}
int length2 = limit - position;
offset2 += position;

View File

@ -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;
@ -50,6 +51,60 @@ 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);
}
@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()];
@ -86,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++)
@ -116,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);

View File

@ -370,7 +370,7 @@ public final class Generators
public static Gen<ByteBuffer> 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<ByteBuffer> directBytes(int min, int max)