This is an automated email from the ASF dual-hosted git repository. bdeggleston pushed a commit to branch trunk in repository https://gitbox.apache.org/repos/asf/cassandra.git
The following commit(s) were added to refs/heads/trunk by this push: new 8be1cbe Use unsigned short in ValueAccessor.sliceWithShortLength 8be1cbe is described below commit 8be1cbe9ab14155773bfab765a3567df9ff9833f Author: Blake Eggleston <bdeggles...@gmail.com> AuthorDate: Tue Sep 29 14:20:05 2020 -0700 Use unsigned short in ValueAccessor.sliceWithShortLength Patch by Blake Eggleston; Reviewed by Caleb Rackliffe and David Capwell for CASSANDRA-16147 --- .circleci/config.yml | 98 +++++++++++----------- CHANGES.txt | 1 + .../cassandra/db/marshal/ByteArrayAccessor.java | 53 ++++++++++++ .../cassandra/db/marshal/ByteBufferAccessor.java | 53 ++++++++++++ .../apache/cassandra/db/marshal/CompositeType.java | 2 +- .../apache/cassandra/db/marshal/ValueAccessor.java | 14 +--- .../org/apache/cassandra/utils/ByteArrayUtil.java | 4 + .../org/apache/cassandra/utils/ByteBufferUtil.java | 8 +- .../cassandra/db/marshal/CompositeTypeTest.java | 22 +++++ .../cassandra/db/marshal/ValueAccessorTest.java | 54 ++++++++++++ 10 files changed, 247 insertions(+), 62 deletions(-) diff --git a/.circleci/config.yml b/.circleci/config.yml index 8ba8949..45c8820 100644 --- a/.circleci/config.yml +++ b/.circleci/config.yml @@ -3,10 +3,10 @@ jobs: j8_jvm_upgrade_dtests: docker: - image: nastra/cassandra-testing-ubuntu1910-java11-w-dependencies:20200603 - resource_class: medium + resource_class: xlarge working_directory: ~/ shell: /bin/bash -eo pipefail -l - parallelism: 1 + parallelism: 2 steps: - attach_workspace: at: /home/cassandra @@ -94,10 +94,10 @@ jobs: j8_cqlsh-dtests-py2-with-vnodes: docker: - image: nastra/cassandra-testing-ubuntu1910-java11-w-dependencies:20200603 - resource_class: medium + resource_class: xlarge working_directory: ~/ shell: /bin/bash -eo pipefail -l - parallelism: 4 + parallelism: 100 steps: - attach_workspace: at: /home/cassandra @@ -171,10 +171,10 @@ jobs: j11_unit_tests: docker: - image: nastra/cassandra-testing-ubuntu1910-java11:20200603 - resource_class: medium + resource_class: xlarge working_directory: ~/ shell: /bin/bash -eo pipefail -l - parallelism: 4 + parallelism: 100 steps: - attach_workspace: at: /home/cassandra @@ -263,10 +263,10 @@ jobs: j8_cqlsh-dtests-py38-no-vnodes: docker: - image: nastra/cassandra-testing-ubuntu1910-java11-w-dependencies:20200603 - resource_class: medium + resource_class: xlarge working_directory: ~/ shell: /bin/bash -eo pipefail -l - parallelism: 4 + parallelism: 100 steps: - attach_workspace: at: /home/cassandra @@ -340,10 +340,10 @@ jobs: j11_cqlsh-dtests-py3-with-vnodes: docker: - image: nastra/cassandra-testing-ubuntu1910-java11:20200603 - resource_class: medium + resource_class: xlarge working_directory: ~/ shell: /bin/bash -eo pipefail -l - parallelism: 4 + parallelism: 100 steps: - attach_workspace: at: /home/cassandra @@ -418,10 +418,10 @@ jobs: j11_cqlsh-dtests-py3-no-vnodes: docker: - image: nastra/cassandra-testing-ubuntu1910-java11:20200603 - resource_class: medium + resource_class: xlarge working_directory: ~/ shell: /bin/bash -eo pipefail -l - parallelism: 4 + parallelism: 100 steps: - attach_workspace: at: /home/cassandra @@ -496,10 +496,10 @@ jobs: j11_cqlsh-dtests-py38-with-vnodes: docker: - image: nastra/cassandra-testing-ubuntu1910-java11:20200603 - resource_class: medium + resource_class: xlarge working_directory: ~/ shell: /bin/bash -eo pipefail -l - parallelism: 4 + parallelism: 100 steps: - attach_workspace: at: /home/cassandra @@ -574,10 +574,10 @@ jobs: j8_cqlsh-dtests-py3-with-vnodes: docker: - image: nastra/cassandra-testing-ubuntu1910-java11-w-dependencies:20200603 - resource_class: medium + resource_class: xlarge working_directory: ~/ shell: /bin/bash -eo pipefail -l - parallelism: 4 + parallelism: 100 steps: - attach_workspace: at: /home/cassandra @@ -651,10 +651,10 @@ jobs: j8_cqlsh-dtests-py2-no-vnodes: docker: - image: nastra/cassandra-testing-ubuntu1910-java11-w-dependencies:20200603 - resource_class: medium + resource_class: xlarge working_directory: ~/ shell: /bin/bash -eo pipefail -l - parallelism: 4 + parallelism: 100 steps: - attach_workspace: at: /home/cassandra @@ -728,10 +728,10 @@ jobs: j11_cqlsh-dtests-py2-with-vnodes: docker: - image: nastra/cassandra-testing-ubuntu1910-java11:20200603 - resource_class: medium + resource_class: xlarge working_directory: ~/ shell: /bin/bash -eo pipefail -l - parallelism: 4 + parallelism: 100 steps: - attach_workspace: at: /home/cassandra @@ -806,10 +806,10 @@ jobs: j11_dtests-with-vnodes: docker: - image: nastra/cassandra-testing-ubuntu1910-java11:20200603 - resource_class: medium + resource_class: xlarge working_directory: ~/ shell: /bin/bash -eo pipefail -l - parallelism: 4 + parallelism: 100 steps: - attach_workspace: at: /home/cassandra @@ -887,10 +887,10 @@ jobs: j8_dtests-no-vnodes: docker: - image: nastra/cassandra-testing-ubuntu1910-java11-w-dependencies:20200603 - resource_class: medium + resource_class: xlarge working_directory: ~/ shell: /bin/bash -eo pipefail -l - parallelism: 4 + parallelism: 100 steps: - attach_workspace: at: /home/cassandra @@ -945,10 +945,10 @@ jobs: j8_upgradetests-no-vnodes: docker: - image: nastra/cassandra-testing-ubuntu1910-java11-w-dependencies:20200603 - resource_class: medium + resource_class: xlarge working_directory: ~/ shell: /bin/bash -eo pipefail -l - parallelism: 4 + parallelism: 100 steps: - attach_workspace: at: /home/cassandra @@ -1044,7 +1044,7 @@ jobs: utests_stress: docker: - image: nastra/cassandra-testing-ubuntu1910-java11-w-dependencies:20200603 - resource_class: medium + resource_class: xlarge working_directory: ~/ shell: /bin/bash -eo pipefail -l parallelism: 1 @@ -1089,10 +1089,10 @@ jobs: j8_unit_tests: docker: - image: nastra/cassandra-testing-ubuntu1910-java11-w-dependencies:20200603 - resource_class: medium + resource_class: xlarge working_directory: ~/ shell: /bin/bash -eo pipefail -l - parallelism: 4 + parallelism: 100 steps: - attach_workspace: at: /home/cassandra @@ -1180,10 +1180,10 @@ jobs: j11_jvm_dtests: docker: - image: nastra/cassandra-testing-ubuntu1910-java11:20200603 - resource_class: medium + resource_class: xlarge working_directory: ~/ shell: /bin/bash -eo pipefail -l - parallelism: 1 + parallelism: 2 steps: - attach_workspace: at: /home/cassandra @@ -1353,10 +1353,10 @@ jobs: j11_cqlsh-dtests-py2-no-vnodes: docker: - image: nastra/cassandra-testing-ubuntu1910-java11:20200603 - resource_class: medium + resource_class: xlarge working_directory: ~/ shell: /bin/bash -eo pipefail -l - parallelism: 4 + parallelism: 100 steps: - attach_workspace: at: /home/cassandra @@ -1431,10 +1431,10 @@ jobs: j8_dtests-with-vnodes: docker: - image: nastra/cassandra-testing-ubuntu1910-java11-w-dependencies:20200603 - resource_class: medium + resource_class: xlarge working_directory: ~/ shell: /bin/bash -eo pipefail -l - parallelism: 4 + parallelism: 100 steps: - attach_workspace: at: /home/cassandra @@ -1489,10 +1489,10 @@ jobs: j11_cqlsh-dtests-py38-no-vnodes: docker: - image: nastra/cassandra-testing-ubuntu1910-java11:20200603 - resource_class: medium + resource_class: xlarge working_directory: ~/ shell: /bin/bash -eo pipefail -l - parallelism: 4 + parallelism: 100 steps: - attach_workspace: at: /home/cassandra @@ -1567,10 +1567,10 @@ jobs: j8_jvm_dtests: docker: - image: nastra/cassandra-testing-ubuntu1910-java11-w-dependencies:20200603 - resource_class: medium + resource_class: xlarge working_directory: ~/ shell: /bin/bash -eo pipefail -l - parallelism: 1 + parallelism: 5 steps: - attach_workspace: at: /home/cassandra @@ -1738,10 +1738,10 @@ jobs: j8_cqlsh-dtests-py3-no-vnodes: docker: - image: nastra/cassandra-testing-ubuntu1910-java11-w-dependencies:20200603 - resource_class: medium + resource_class: xlarge working_directory: ~/ shell: /bin/bash -eo pipefail -l - parallelism: 4 + parallelism: 100 steps: - attach_workspace: at: /home/cassandra @@ -1815,10 +1815,10 @@ jobs: j8_cqlsh-dtests-py38-with-vnodes: docker: - image: nastra/cassandra-testing-ubuntu1910-java11-w-dependencies:20200603 - resource_class: medium + resource_class: xlarge working_directory: ~/ shell: /bin/bash -eo pipefail -l - parallelism: 4 + parallelism: 100 steps: - attach_workspace: at: /home/cassandra @@ -1892,7 +1892,7 @@ jobs: utests_long: docker: - image: nastra/cassandra-testing-ubuntu1910-java11-w-dependencies:20200603 - resource_class: medium + resource_class: xlarge working_directory: ~/ shell: /bin/bash -eo pipefail -l parallelism: 1 @@ -1937,7 +1937,7 @@ jobs: utests_fqltool: docker: - image: nastra/cassandra-testing-ubuntu1910-java11-w-dependencies:20200603 - resource_class: medium + resource_class: xlarge working_directory: ~/ shell: /bin/bash -eo pipefail -l parallelism: 1 @@ -1982,10 +1982,10 @@ jobs: j11_dtests-no-vnodes: docker: - image: nastra/cassandra-testing-ubuntu1910-java11:20200603 - resource_class: medium + resource_class: xlarge working_directory: ~/ shell: /bin/bash -eo pipefail -l - parallelism: 4 + parallelism: 100 steps: - attach_workspace: at: /home/cassandra @@ -2063,10 +2063,10 @@ jobs: utests_compression: docker: - image: nastra/cassandra-testing-ubuntu1910-java11-w-dependencies:20200603 - resource_class: medium + resource_class: xlarge working_directory: ~/ shell: /bin/bash -eo pipefail -l - parallelism: 4 + parallelism: 100 steps: - attach_workspace: at: /home/cassandra diff --git a/CHANGES.txt b/CHANGES.txt index d1fa00e..d66bcad 100644 --- a/CHANGES.txt +++ b/CHANGES.txt @@ -1,4 +1,5 @@ 4.0-beta3 + * Use unsigned short in ValueAccessor.sliceWithShortLength (CASSANDRA-16147) * Abort repairs when getting a truncation request (CASSANDRA-15854) * Remove bad assert when getting active compactions for an sstable (CASSANDRA-15457) * Avoid failing compactions with very large partitions (CASSANDRA-15164) diff --git a/src/java/org/apache/cassandra/db/marshal/ByteArrayAccessor.java b/src/java/org/apache/cassandra/db/marshal/ByteArrayAccessor.java index 92f18a2..7d13844 100644 --- a/src/java/org/apache/cassandra/db/marshal/ByteArrayAccessor.java +++ b/src/java/org/apache/cassandra/db/marshal/ByteArrayAccessor.java @@ -43,49 +43,58 @@ public class ByteArrayAccessor implements ValueAccessor<byte[]> private ByteArrayAccessor() {} + @Override public int size(byte[] value) { return value.length; } + @Override public byte[][] createArray(int length) { return new byte[length][]; } + @Override public void write(byte[] value, DataOutputPlus out) throws IOException { out.write(value); } + @Override public void write(byte[] value, ByteBuffer out) { out.put(value); } + @Override public <V2> int copyTo(byte[] src, int srcOffset, V2 dst, ValueAccessor<V2> dstAccessor, int dstOffset, int size) { dstAccessor.copyByteArrayTo(src, srcOffset, dst, dstOffset, size); return size; } + @Override public int copyByteArrayTo(byte[] src, int srcOffset, byte[] dst, int dstOffset, int size) { FastByteOperations.copy(src, srcOffset, dst, dstOffset, size); return size; } + @Override public int copyByteBufferTo(ByteBuffer src, int srcOffset, byte[] dst, int dstOffset, int size) { FastByteOperations.copy(src, src.position() + srcOffset, dst, dstOffset, size); return size; } + @Override public void digest(byte[] value, int offset, int size, Digest digest) { digest.update(value, offset, size); } + @Override public byte[] read(DataInputPlus in, int length) throws IOException { byte[] b = new byte[length]; @@ -93,26 +102,31 @@ public class ByteArrayAccessor implements ValueAccessor<byte[]> return b; } + @Override public byte[] slice(byte[] input, int offset, int length) { return Arrays.copyOfRange(input, offset, offset + length); } + @Override public <V2> int compare(byte[] left, V2 right, ValueAccessor<V2> accessorR) { return accessorR.compareByteArrayTo(left, right); } + @Override public int compareByteArrayTo(byte[] left, byte[] right) { return ByteArrayUtil.compareUnsigned(left, right); } + @Override public int compareByteBufferTo(ByteBuffer left, byte[] right) { return ByteBufferUtil.compare(left, right); } + @Override public ByteBuffer toBuffer(byte[] value) { if (value == null) @@ -120,11 +134,13 @@ public class ByteArrayAccessor implements ValueAccessor<byte[]> return ByteBuffer.wrap(value); } + @Override public byte[] toArray(byte[] value) { return value; } + @Override public byte[] toArray(byte[] value, int offset, int length) { if (value == null) @@ -134,159 +150,196 @@ public class ByteArrayAccessor implements ValueAccessor<byte[]> return slice(value, offset, length); } + @Override public String toString(byte[] value, Charset charset) throws CharacterCodingException { return new String(value, charset); } + @Override public String toHex(byte[] value) { return Hex.bytesToHex(value); } + @Override public byte toByte(byte[] value) { return value[0]; } + @Override public byte getByte(byte[] value, int offset) { return value[offset]; } + @Override public short toShort(byte[] value) { return getShort(value, 0); } + @Override public short getShort(byte[] value, int offset) { return ByteArrayUtil.getShort(value, offset); } + @Override + public int getUnsignedShort(byte[] value, int offset) + { + return ByteArrayUtil.getUnsignedShort(value, offset); + } + + @Override public int toInt(byte[] value) { return getInt(value, 0); } + @Override public int getInt(byte[] value, int offset) { return ByteArrayUtil.getInt(value, offset); } + @Override public long toLong(byte[] value) { return getLong(value, 0); } + @Override public long getLong(byte[] value, int offset) { return ByteArrayUtil.getLong(value, offset); } + @Override public float toFloat(byte[] value) { return ByteArrayUtil.getFloat(value, 0); } + @Override public double toDouble(byte[] value) { return ByteArrayUtil.getDouble(value, 0); } + @Override public UUID toUUID(byte[] value) { return new UUID(getLong(value, 0), getLong(value, 8)); } + @Override public int putShort(byte[] dst, int offset, short value) { ByteArrayUtil.putShort(dst, offset, value); return TypeSizes.SHORT_SIZE; } + @Override public int putInt(byte[] dst, int offset, int value) { ByteArrayUtil.putInt(dst, offset, value); return TypeSizes.INT_SIZE; } + @Override public int putLong(byte[] dst, int offset, long value) { ByteArrayUtil.putLong(dst, offset, value); return TypeSizes.LONG_SIZE; } + @Override public byte[] empty() { return EMPTY; } + @Override public byte[] valueOf(byte[] bytes) { return bytes; } + @Override public byte[] valueOf(ByteBuffer bytes) { return ByteBufferUtil.getArray(bytes); } + @Override public byte[] valueOf(String s, Charset charset) { return ByteArrayUtil.bytes(s, charset); } + @Override public byte[] valueOf(UUID v) { return UUIDGen.decompose(v); } + @Override public byte[] valueOf(boolean v) { return v ? new byte[] {1} : new byte[] {0}; } + @Override public byte[] valueOf(byte v) { return ByteArrayUtil.bytes(v); } + @Override public byte[] valueOf(short v) { return ByteArrayUtil.bytes(v); } + @Override public byte[] valueOf(int v) { return ByteArrayUtil.bytes(v); } + @Override public byte[] valueOf(long v) { return ByteArrayUtil.bytes(v); } + @Override public byte[] valueOf(float v) { return ByteArrayUtil.bytes(v); } + @Override public byte[] valueOf(double v) { return ByteArrayUtil.bytes(v); } + @Override public <V2> byte[] convert(V2 src, ValueAccessor<V2> accessor) { return accessor.toArray(src); } + @Override public byte[] allocate(int size) { return new byte[size]; } + @Override public ObjectFactory<byte[]> factory() { return factory; diff --git a/src/java/org/apache/cassandra/db/marshal/ByteBufferAccessor.java b/src/java/org/apache/cassandra/db/marshal/ByteBufferAccessor.java index df27d8b..b7dfce6 100644 --- a/src/java/org/apache/cassandra/db/marshal/ByteBufferAccessor.java +++ b/src/java/org/apache/cassandra/db/marshal/ByteBufferAccessor.java @@ -42,54 +42,64 @@ public class ByteBufferAccessor implements ValueAccessor<ByteBuffer> private ByteBufferAccessor() {} + @Override public int size(ByteBuffer value) { return value.remaining(); } + @Override public ByteBuffer[] createArray(int length) { return new ByteBuffer[length]; } + @Override public void write(ByteBuffer value, DataOutputPlus out) throws IOException { out.write(value); } + @Override public void write(ByteBuffer value, ByteBuffer out) { out.put(value.duplicate()); } + @Override public <V2> int copyTo(ByteBuffer src, int srcOffset, V2 dst, ValueAccessor<V2> dstAccessor, int dstOffset, int size) { dstAccessor.copyByteBufferTo(src, srcOffset, dst, dstOffset, size); return size; } + @Override public int copyByteArrayTo(byte[] src, int srcOffset, ByteBuffer dst, int dstOffset, int size) { FastByteOperations.copy(src, srcOffset, dst, dst.position() + dstOffset, size); return size; } + @Override public int copyByteBufferTo(ByteBuffer src, int srcOffset, ByteBuffer dst, int dstOffset, int size) { FastByteOperations.copy(src, src.position() + srcOffset, dst, dst.position() + dstOffset, size); return size; } + @Override public void digest(ByteBuffer value, int offset, int size, Digest digest) { digest.update(value, value.position() + offset, size); } + @Override public ByteBuffer read(DataInputPlus in, int length) throws IOException { return ByteBufferUtil.read(in, length); } + @Override public ByteBuffer slice(ByteBuffer input, int offset, int length) { ByteBuffer copy = input.duplicate(); @@ -98,26 +108,31 @@ public class ByteBufferAccessor implements ValueAccessor<ByteBuffer> return copy; } + @Override public <V2> int compare(ByteBuffer left, V2 right, ValueAccessor<V2> accessorR) { return accessorR.compareByteBufferTo(left, right); } + @Override public int compareByteArrayTo(byte[] left, ByteBuffer right) { return ByteBufferUtil.compare(left, right); } + @Override public int compareByteBufferTo(ByteBuffer left, ByteBuffer right) { return ByteBufferUtil.compareUnsigned(left, right); } + @Override public ByteBuffer toBuffer(ByteBuffer value) { return value; } + @Override public byte[] toArray(ByteBuffer value) { if (value == null) @@ -125,6 +140,7 @@ public class ByteBufferAccessor implements ValueAccessor<ByteBuffer> return ByteBufferUtil.getArray(value); } + @Override public byte[] toArray(ByteBuffer value, int offset, int length) { if (value == null) @@ -132,159 +148,196 @@ public class ByteBufferAccessor implements ValueAccessor<ByteBuffer> return ByteBufferUtil.getArray(value, value.position() + offset, length); } + @Override public String toString(ByteBuffer value, Charset charset) throws CharacterCodingException { return ByteBufferUtil.string(value, charset); } + @Override public ByteBuffer valueOf(UUID v) { return UUIDGen.toByteBuffer(v); } + @Override public String toHex(ByteBuffer value) { return ByteBufferUtil.bytesToHex(value); } + @Override public byte toByte(ByteBuffer value) { return ByteBufferUtil.toByte(value); } + @Override public byte getByte(ByteBuffer value, int offset) { return value.get(value.position() + offset); } + @Override public short toShort(ByteBuffer value) { return ByteBufferUtil.toShort(value); } + @Override public short getShort(ByteBuffer value, int offset) { return value.getShort(value.position() + offset); } + @Override + public int getUnsignedShort(ByteBuffer value, int offset) + { + return ByteBufferUtil.getUnsignedShort(value, offset); + } + + @Override public int toInt(ByteBuffer value) { return ByteBufferUtil.toInt(value); } + @Override public int getInt(ByteBuffer value, int offset) { return value.getInt(value.position() + offset); } + @Override public long toLong(ByteBuffer value) { return ByteBufferUtil.toLong(value); } + @Override public long getLong(ByteBuffer value, int offset) { return value.getLong(value.position() + offset); } + @Override public float toFloat(ByteBuffer value) { return ByteBufferUtil.toFloat(value); } + @Override public double toDouble(ByteBuffer value) { return ByteBufferUtil.toDouble(value); } + @Override public UUID toUUID(ByteBuffer value) { return UUIDGen.getUUID(value); } + @Override public int putShort(ByteBuffer dst, int offset, short value) { dst.putShort(dst.position() + offset, value); return TypeSizes.SHORT_SIZE; } + @Override public int putInt(ByteBuffer dst, int offset, int value) { dst.putInt(dst.position() + offset, value); return TypeSizes.INT_SIZE; } + @Override public int putLong(ByteBuffer dst, int offset, long value) { dst.putLong(dst.position() + offset, value); return TypeSizes.LONG_SIZE; } + @Override public ByteBuffer empty() { return ByteBufferUtil.EMPTY_BYTE_BUFFER; } + @Override public ByteBuffer valueOf(byte[] bytes) { return ByteBuffer.wrap(bytes); } + @Override public ByteBuffer valueOf(ByteBuffer bytes) { return bytes; } + @Override public ByteBuffer valueOf(String v, Charset charset) { return ByteBufferUtil.bytes(v, charset); } + @Override public ByteBuffer valueOf(boolean v) { return v ? ByteBuffer.wrap(new byte[] {1}) : ByteBuffer.wrap(new byte[] {0}); } + @Override public ByteBuffer valueOf(byte v) { return ByteBufferUtil.bytes(v); } + @Override public ByteBuffer valueOf(short v) { return ByteBufferUtil.bytes(v); } + @Override public ByteBuffer valueOf(int v) { return ByteBufferUtil.bytes(v); } + @Override public ByteBuffer valueOf(long v) { return ByteBufferUtil.bytes(v); } + @Override public ByteBuffer valueOf(float v) { return ByteBufferUtil.bytes(v); } + @Override public ByteBuffer valueOf(double v) { return ByteBufferUtil.bytes(v); } + @Override public <V2> ByteBuffer convert(V2 src, ValueAccessor<V2> accessor) { return accessor.toBuffer(src); } + @Override public ByteBuffer allocate(int size) { return ByteBuffer.allocate(size); } + @Override public ObjectFactory<ByteBuffer> factory() { return ByteBufferObjectFactory.instance; diff --git a/src/java/org/apache/cassandra/db/marshal/CompositeType.java b/src/java/org/apache/cassandra/db/marshal/CompositeType.java index d7041b8..bf5e914a 100644 --- a/src/java/org/apache/cassandra/db/marshal/CompositeType.java +++ b/src/java/org/apache/cassandra/db/marshal/CompositeType.java @@ -247,7 +247,7 @@ public class CompositeType extends AbstractCompositeType public static <V> boolean isStaticName(V value, ValueAccessor<V> accessor) { - return accessor.size(value) >= 2 && (accessor.getShortLength(value, 0) & 0xFFFF) == STATIC_MARKER; + return accessor.size(value) >= 2 && (accessor.getUnsignedShort(value, 0) & 0xFFFF) == STATIC_MARKER; } @Override diff --git a/src/java/org/apache/cassandra/db/marshal/ValueAccessor.java b/src/java/org/apache/cassandra/db/marshal/ValueAccessor.java index 8ab1569..10532ff 100644 --- a/src/java/org/apache/cassandra/db/marshal/ValueAccessor.java +++ b/src/java/org/apache/cassandra/db/marshal/ValueAccessor.java @@ -216,24 +216,16 @@ public interface ValueAccessor<V> V slice(V input, int offset, int length); /** - * same as {@link ValueAccessor#slice(Object, int, int)}, except the length is taked from the first + * same as {@link ValueAccessor#slice(Object, int, int)}, except the length is taken from the first * 2 bytes from the given offset (and not included in the return value) */ default V sliceWithShortLength(V input, int offset) { - int size = getShort(input, offset); + int size = getUnsignedShort(input, offset); return slice(input, offset + 2, size); } /** - * @return a short length prefix starting at {@param offset} - */ - default int getShortLength(V v, int offset) - { - return getShort(v, offset); - } - - /** * lexicographically compare {@param left} to {@param right} * @param <VR> backing type of */ @@ -311,6 +303,8 @@ public interface ValueAccessor<V> short toShort(V value); /** returns a short from offset {@param offset} */ short getShort(V value, int offset); + /** returns an unsigned short from offset {@param offset} */ + int getUnsignedShort(V value, int offset); /** returns an int from offset 0 */ int toInt(V value); /** returns an int from offset {@param offset} */ diff --git a/src/java/org/apache/cassandra/utils/ByteArrayUtil.java b/src/java/org/apache/cassandra/utils/ByteArrayUtil.java index 559607c..75734ad 100644 --- a/src/java/org/apache/cassandra/utils/ByteArrayUtil.java +++ b/src/java/org/apache/cassandra/utils/ByteArrayUtil.java @@ -111,6 +111,10 @@ public class ByteArrayUtil (b[off] << 8)); } + public static int getUnsignedShort(byte[] b, int off) { + return ((b[off] & 0xFF) << 8) | (b[off + 1] & 0xFF); + } + public static int getInt(byte[] b, int off) { return ((b[off + 3] & 0xFF) ) + ((b[off + 2] & 0xFF) << 8) + diff --git a/src/java/org/apache/cassandra/utils/ByteBufferUtil.java b/src/java/org/apache/cassandra/utils/ByteBufferUtil.java index fca989f..d0ab6b2 100644 --- a/src/java/org/apache/cassandra/utils/ByteBufferUtil.java +++ b/src/java/org/apache/cassandra/utils/ByteBufferUtil.java @@ -701,11 +701,15 @@ public class ByteBufferUtil return false; } + public static int getUnsignedShort(ByteBuffer bb, int position) + { + return ((bb.get(position) & 0xFF) << 8) | (bb.get(position + 1) & 0xFF); + } + // Doesn't change bb position public static int getShortLength(ByteBuffer bb, int position) { - int length = (bb.get(position) & 0xFF) << 8; - return length | (bb.get(position + 1) & 0xFF); + return getUnsignedShort(bb, position); } // changes bb position diff --git a/test/unit/org/apache/cassandra/db/marshal/CompositeTypeTest.java b/test/unit/org/apache/cassandra/db/marshal/CompositeTypeTest.java index e79b90e..eb838d3 100644 --- a/test/unit/org/apache/cassandra/db/marshal/CompositeTypeTest.java +++ b/test/unit/org/apache/cassandra/db/marshal/CompositeTypeTest.java @@ -22,6 +22,8 @@ import java.nio.ByteBuffer; import java.nio.charset.CharacterCodingException; import java.util.*; +import com.google.common.collect.Lists; +import org.junit.Assert; import org.junit.BeforeClass; import org.junit.Test; import static org.junit.Assert.fail; @@ -321,4 +323,24 @@ public class CompositeTypeTest bb.rewind(); return bb; } + + private static <V> void testToFromString(ByteBuffer bytes, ValueAccessor<V> accessor, CompositeType type) + { + V value = accessor.valueOf(bytes); + String s = type.getString(value, accessor); + ByteBuffer fromString = type.fromString(s); + Assert.assertEquals(bytes, fromString); + } + + + @Test + public void testLargeValues() + { + CompositeType type = CompositeType.getInstance(Lists.newArrayList(BytesType.instance)); + ByteBuffer expected = ByteBuffer.allocate(0xFFFE); + new Random(0).nextBytes(expected.array()); + ByteBuffer serialized = CompositeType.build(ByteBufferAccessor.instance, expected); + for (ValueAccessor<?> accessor : ValueAccessors.ACCESSORS) + testToFromString(serialized, accessor, type); + } } diff --git a/test/unit/org/apache/cassandra/db/marshal/ValueAccessorTest.java b/test/unit/org/apache/cassandra/db/marshal/ValueAccessorTest.java index 49851e9..566751b 100644 --- a/test/unit/org/apache/cassandra/db/marshal/ValueAccessorTest.java +++ b/test/unit/org/apache/cassandra/db/marshal/ValueAccessorTest.java @@ -18,6 +18,7 @@ package org.apache.cassandra.db.marshal; +import java.io.IOException; import java.nio.ByteBuffer; import java.util.Arrays; import java.util.Random; @@ -26,10 +27,15 @@ import com.google.common.primitives.Shorts; import org.junit.Assert; import org.junit.Test; +import org.apache.cassandra.io.util.DataOutputBuffer; import org.apache.cassandra.utils.ByteArrayUtil; import org.apache.cassandra.utils.ByteBufferUtil; +import org.assertj.core.api.Assertions; +import org.quicktheories.core.Gen; +import org.quicktheories.generators.SourceDSL; import static org.apache.cassandra.db.marshal.ValueAccessors.ACCESSORS; +import static org.quicktheories.QuickTheory.qt; public class ValueAccessorTest { @@ -129,4 +135,52 @@ public class ValueAccessorTest testTypeConversion(i, accessor, random); } } + + private static <V> void testReadWriteWithShortLength(ValueAccessor<V> accessor, int size) throws IOException + { + Random random = new Random(size); + byte[] bytes = new byte[size]; + random.nextBytes(bytes); + ByteBuffer buffer = ByteBuffer.wrap(bytes); + + try (DataOutputBuffer out = new DataOutputBuffer(size + 2)) + { + ByteBufferUtil.writeWithShortLength(buffer, out); + V flushed = accessor.valueOf(out.toByteArray()); + V value = accessor.sliceWithShortLength(flushed, 0); + Assert.assertArrayEquals(bytes, accessor.toArray(value)); + } + } + + @Test + public void testReadWriteWithShortLength() throws IOException + { + int[] lengths = new int[]{0, 1, 2, 256, 0x8001, 0xFFFF}; + for (int length : lengths) + { + for (ValueAccessor<?> accessor: ACCESSORS) + testReadWriteWithShortLength(accessor, length); + } + } + + @Test + public void testUnsignedShort() + { + Gen<Integer> gen = SourceDSL.integers().between(0, Short.MAX_VALUE * 2 + 1); + + qt().forAll(gen).checkAssert(jint -> { + int size = jint; + for (ValueAccessor<Object> accessor: ACCESSORS) + { + Object value = accessor.allocate(5); + for (int offset : Arrays.asList(0, 3)) + { + accessor.putShort(value, offset, (short) size); // testing signed + Assertions.assertThat(accessor.getUnsignedShort(value, offset)) + .as("getUnsignedShort(putShort(unsigned_short)) != unsigned_short for %s", accessor.getClass()) + .isEqualTo(size); + } + } + }); + } } --------------------------------------------------------------------- To unsubscribe, e-mail: commits-unsubscr...@cassandra.apache.org For additional commands, e-mail: commits-h...@cassandra.apache.org