mirror of https://github.com/apache/cassandra
Compare commits
8 Commits
266a21aa38
...
63958f87cf
| Author | SHA1 | Date |
|---|---|---|
|
|
63958f87cf | |
|
|
57a0dbc899 | |
|
|
cec1534a7f | |
|
|
d9d1b8586b | |
|
|
9f5af41c8d | |
|
|
f429810c8f | |
|
|
b9ebbfb268 | |
|
|
6f413eef87 |
|
|
@ -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;
|
||||
|
||||
|
|
|
|||
|
|
@ -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);
|
||||
|
|
|
|||
|
|
@ -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)
|
||||
|
|
|
|||
Loading…
Reference in New Issue