From b79174292c397ba5a24c5b5df4960d0b98a633ba Mon Sep 17 00:00:00 2001 From: Vincent Guilpain Date: Wed, 9 Oct 2024 14:33:07 +0900 Subject: [PATCH] Refactor KeyBytesEncoder to use ColumnVisitor (#2270) --- .../dynamo/bytes/BigIntBytesEncoder.java | 12 +++--- .../dynamo/bytes/BlobBytesEncoder.java | 21 +++++----- .../dynamo/bytes/BooleanBytesEncoder.java | 12 +++--- .../db/storage/dynamo/bytes/BytesEncoder.java | 16 ++++---- .../dynamo/bytes/DoubleBytesEncoder.java | 11 +++--- .../dynamo/bytes/FloatBytesEncoder.java | 11 +++--- .../storage/dynamo/bytes/IntBytesEncoder.java | 12 +++--- .../KeyBytesEncodedLengthCalculator.java | 38 +++++++++---------- .../storage/dynamo/bytes/KeyBytesEncoder.java | 36 +++++++++--------- .../dynamo/bytes/TextBytesEncoder.java | 22 ++++++----- 10 files changed, 103 insertions(+), 88 deletions(-) diff --git a/core/src/main/java/com/scalar/db/storage/dynamo/bytes/BigIntBytesEncoder.java b/core/src/main/java/com/scalar/db/storage/dynamo/bytes/BigIntBytesEncoder.java index 0793a6e563..85bd126ea5 100644 --- a/core/src/main/java/com/scalar/db/storage/dynamo/bytes/BigIntBytesEncoder.java +++ b/core/src/main/java/com/scalar/db/storage/dynamo/bytes/BigIntBytesEncoder.java @@ -3,23 +3,25 @@ import static com.scalar.db.storage.dynamo.bytes.BytesUtils.mask; import com.scalar.db.api.Scan.Ordering.Order; -import com.scalar.db.io.BigIntValue; +import com.scalar.db.io.BigIntColumn; import java.nio.ByteBuffer; import javax.annotation.concurrent.ThreadSafe; @ThreadSafe -public class BigIntBytesEncoder implements BytesEncoder { +public class BigIntBytesEncoder implements BytesEncoder { BigIntBytesEncoder() {} @Override - public int encodedLength(BigIntValue value, Order order) { + public int encodedLength(BigIntColumn column, Order order) { return 8; } @Override - public void encode(BigIntValue value, Order order, ByteBuffer dst) { - long v = value.getAsLong(); + public void encode(BigIntColumn column, Order order, ByteBuffer dst) { + assert !column.hasNullValue(); + + long v = column.getBigIntValue(); dst.put(mask((byte) ((v >> 56) ^ 0x80), order)); // Flip a sign bit to make it binary comparable dst.put(mask((byte) (v >> 48), order)); dst.put(mask((byte) (v >> 40), order)); diff --git a/core/src/main/java/com/scalar/db/storage/dynamo/bytes/BlobBytesEncoder.java b/core/src/main/java/com/scalar/db/storage/dynamo/bytes/BlobBytesEncoder.java index 473c9d3830..066c1e8e2d 100644 --- a/core/src/main/java/com/scalar/db/storage/dynamo/bytes/BlobBytesEncoder.java +++ b/core/src/main/java/com/scalar/db/storage/dynamo/bytes/BlobBytesEncoder.java @@ -4,12 +4,12 @@ import com.scalar.db.api.Scan.Ordering.Order; import com.scalar.db.common.error.CoreError; -import com.scalar.db.io.BlobValue; +import com.scalar.db.io.BlobColumn; import java.nio.ByteBuffer; import javax.annotation.concurrent.ThreadSafe; @ThreadSafe -public class BlobBytesEncoder implements BytesEncoder { +public class BlobBytesEncoder implements BytesEncoder { private static final byte TERM = (byte) 0x00; private static final byte MASKED_TERM = (byte) 0xff; @@ -17,17 +17,20 @@ public class BlobBytesEncoder implements BytesEncoder { BlobBytesEncoder() {} @Override - public int encodedLength(BlobValue value, Order order) { - assert value.getAsBytes().isPresent(); - return value.getAsBytes().get().length + (order == Order.ASC ? 0 : 1); + public int encodedLength(BlobColumn column, Order order) { + assert column.getBlobValueAsBytes() != null; + + return column.getBlobValueAsBytes().length + (order == Order.ASC ? 0 : 1); } @Override - public void encode(BlobValue value, Order order, ByteBuffer dst) { - assert value.getAsBytes().isPresent(); + public void encode(BlobColumn column, Order order, ByteBuffer dst) { + assert column.getBlobValueAsBytes() != null; + + byte[] value = column.getBlobValueAsBytes(); if (order == Order.DESC) { - for (byte b : value.getAsBytes().get()) { + for (byte b : value) { if (b == TERM) { throw new IllegalArgumentException( CoreError.DYNAMO_ENCODER_0X00_BYTES_NOT_ACCEPTED_IN_BLOB_VALUES_IN_DESC_ORDER @@ -36,7 +39,7 @@ public void encode(BlobValue value, Order order, ByteBuffer dst) { } } - for (byte b : value.getAsBytes().get()) { + for (byte b : value) { dst.put(mask(b, order)); } if (order == Order.DESC) { diff --git a/core/src/main/java/com/scalar/db/storage/dynamo/bytes/BooleanBytesEncoder.java b/core/src/main/java/com/scalar/db/storage/dynamo/bytes/BooleanBytesEncoder.java index 0bf44e0968..5869648af3 100644 --- a/core/src/main/java/com/scalar/db/storage/dynamo/bytes/BooleanBytesEncoder.java +++ b/core/src/main/java/com/scalar/db/storage/dynamo/bytes/BooleanBytesEncoder.java @@ -3,25 +3,27 @@ import static com.scalar.db.storage.dynamo.bytes.BytesUtils.mask; import com.scalar.db.api.Scan.Ordering.Order; -import com.scalar.db.io.BooleanValue; +import com.scalar.db.io.BooleanColumn; import java.nio.ByteBuffer; import javax.annotation.concurrent.ThreadSafe; @ThreadSafe -public class BooleanBytesEncoder implements BytesEncoder { +public class BooleanBytesEncoder implements BytesEncoder { private static final byte FALSE = 0x00; private static final byte TRUE = 0x01; BooleanBytesEncoder() {} @Override - public int encodedLength(BooleanValue value, Order order) { + public int encodedLength(BooleanColumn column, Order order) { return 1; } @Override - public void encode(BooleanValue value, Order order, ByteBuffer dst) { - boolean b = value.getAsBoolean(); + public void encode(BooleanColumn column, Order order, ByteBuffer dst) { + assert !column.hasNullValue(); + + boolean b = column.getBooleanValue(); dst.put(mask(b ? TRUE : FALSE, order)); } } diff --git a/core/src/main/java/com/scalar/db/storage/dynamo/bytes/BytesEncoder.java b/core/src/main/java/com/scalar/db/storage/dynamo/bytes/BytesEncoder.java index 79f9338816..33f024865a 100644 --- a/core/src/main/java/com/scalar/db/storage/dynamo/bytes/BytesEncoder.java +++ b/core/src/main/java/com/scalar/db/storage/dynamo/bytes/BytesEncoder.java @@ -1,31 +1,31 @@ package com.scalar.db.storage.dynamo.bytes; import com.scalar.db.api.Scan.Ordering.Order; -import com.scalar.db.io.Value; +import com.scalar.db.io.Column; import java.nio.ByteBuffer; /** - * A bytes-encoder that encodes a value to bytes while preserving the sort order. + * A bytes-encoder that encodes a column to bytes while preserving the sort order. * * @param the value type */ -public interface BytesEncoder> { +public interface BytesEncoder> { /** * Calculates the encoded bytes length. * - * @param value a value + * @param column a column * @param order an order * @return the encoded bytes length */ - int encodedLength(T value, Order order); + int encodedLength(T column, Order order); /** - * Encodes the value to bytes + * Encodes the column to bytes * - * @param value a value + * @param column a column * @param order an order * @param dst a ByteBuffer to write the encoded bytes */ - void encode(T value, Order order, ByteBuffer dst); + void encode(T column, Order order, ByteBuffer dst); } diff --git a/core/src/main/java/com/scalar/db/storage/dynamo/bytes/DoubleBytesEncoder.java b/core/src/main/java/com/scalar/db/storage/dynamo/bytes/DoubleBytesEncoder.java index e343520110..d03adf6e26 100644 --- a/core/src/main/java/com/scalar/db/storage/dynamo/bytes/DoubleBytesEncoder.java +++ b/core/src/main/java/com/scalar/db/storage/dynamo/bytes/DoubleBytesEncoder.java @@ -3,22 +3,23 @@ import static com.scalar.db.storage.dynamo.bytes.BytesUtils.mask; import com.scalar.db.api.Scan.Ordering.Order; -import com.scalar.db.io.DoubleValue; +import com.scalar.db.io.DoubleColumn; import java.nio.ByteBuffer; import javax.annotation.concurrent.ThreadSafe; @ThreadSafe -public class DoubleBytesEncoder implements BytesEncoder { +public class DoubleBytesEncoder implements BytesEncoder { DoubleBytesEncoder() {} @Override - public int encodedLength(DoubleValue value, Order order) { + public int encodedLength(DoubleColumn column, Order order) { return 8; } @Override - public void encode(DoubleValue value, Order order, ByteBuffer dst) { + public void encode(DoubleColumn column, Order order, ByteBuffer dst) { + assert !column.hasNullValue(); /* * The IEE754 floating point format already preserves sort ordering for positive floating point * numbers when the raw bytes are compared in most significant byte order. @@ -30,7 +31,7 @@ public void encode(DoubleValue value, Order order, ByteBuffer dst) { */ // store the floating point bits into a 64-bit long - long l = Double.doubleToLongBits(value.getAsDouble()); + long l = Double.doubleToLongBits(column.getDoubleValue()); // invert the sign bit and XOR's all other bits with the sign bit itself l ^= ((l >> (Long.SIZE - 1)) | Long.MIN_VALUE); diff --git a/core/src/main/java/com/scalar/db/storage/dynamo/bytes/FloatBytesEncoder.java b/core/src/main/java/com/scalar/db/storage/dynamo/bytes/FloatBytesEncoder.java index a9c8a5950c..fb89055058 100644 --- a/core/src/main/java/com/scalar/db/storage/dynamo/bytes/FloatBytesEncoder.java +++ b/core/src/main/java/com/scalar/db/storage/dynamo/bytes/FloatBytesEncoder.java @@ -3,22 +3,23 @@ import static com.scalar.db.storage.dynamo.bytes.BytesUtils.mask; import com.scalar.db.api.Scan.Ordering.Order; -import com.scalar.db.io.FloatValue; +import com.scalar.db.io.FloatColumn; import java.nio.ByteBuffer; import javax.annotation.concurrent.ThreadSafe; @ThreadSafe -public class FloatBytesEncoder implements BytesEncoder { +public class FloatBytesEncoder implements BytesEncoder { FloatBytesEncoder() {} @Override - public int encodedLength(FloatValue value, Order order) { + public int encodedLength(FloatColumn column, Order order) { return 4; } @Override - public void encode(FloatValue value, Order order, ByteBuffer dst) { + public void encode(FloatColumn column, Order order, ByteBuffer dst) { + assert !column.hasNullValue(); /* * The IEE754 floating point format already preserves sort ordering for positive floating point * numbers when the raw bytes are compared in most significant byte order. @@ -30,7 +31,7 @@ public void encode(FloatValue value, Order order, ByteBuffer dst) { */ // store the floating point bits into a 32-bit int - int i = Float.floatToIntBits(value.getAsFloat()); + int i = Float.floatToIntBits(column.getFloatValue()); // invert the sign bit and XOR's all other bits with the sign bit itself i ^= ((i >> (Integer.SIZE - 1)) | Integer.MIN_VALUE); diff --git a/core/src/main/java/com/scalar/db/storage/dynamo/bytes/IntBytesEncoder.java b/core/src/main/java/com/scalar/db/storage/dynamo/bytes/IntBytesEncoder.java index 54ded68a17..384d732d0f 100644 --- a/core/src/main/java/com/scalar/db/storage/dynamo/bytes/IntBytesEncoder.java +++ b/core/src/main/java/com/scalar/db/storage/dynamo/bytes/IntBytesEncoder.java @@ -3,23 +3,25 @@ import static com.scalar.db.storage.dynamo.bytes.BytesUtils.mask; import com.scalar.db.api.Scan.Ordering.Order; -import com.scalar.db.io.IntValue; +import com.scalar.db.io.IntColumn; import java.nio.ByteBuffer; import javax.annotation.concurrent.ThreadSafe; @ThreadSafe -public class IntBytesEncoder implements BytesEncoder { +public class IntBytesEncoder implements BytesEncoder { IntBytesEncoder() {} @Override - public int encodedLength(IntValue value, Order order) { + public int encodedLength(IntColumn column, Order order) { return 4; } @Override - public void encode(IntValue value, Order order, ByteBuffer dst) { - int v = value.getAsInt(); + public void encode(IntColumn column, Order order, ByteBuffer dst) { + assert !column.hasNullValue(); + + int v = column.getIntValue(); dst.put(mask((byte) ((v >> 24) ^ 0x80), order)); // Flip a sign bit to make it binary comparable dst.put(mask((byte) (v >> 16), order)); dst.put(mask((byte) (v >> 8), order)); diff --git a/core/src/main/java/com/scalar/db/storage/dynamo/bytes/KeyBytesEncodedLengthCalculator.java b/core/src/main/java/com/scalar/db/storage/dynamo/bytes/KeyBytesEncodedLengthCalculator.java index fc41bf20b2..3fb4d75211 100644 --- a/core/src/main/java/com/scalar/db/storage/dynamo/bytes/KeyBytesEncodedLengthCalculator.java +++ b/core/src/main/java/com/scalar/db/storage/dynamo/bytes/KeyBytesEncodedLengthCalculator.java @@ -1,22 +1,22 @@ package com.scalar.db.storage.dynamo.bytes; import com.scalar.db.api.Scan.Ordering.Order; -import com.scalar.db.io.BigIntValue; -import com.scalar.db.io.BlobValue; -import com.scalar.db.io.BooleanValue; -import com.scalar.db.io.DoubleValue; -import com.scalar.db.io.FloatValue; -import com.scalar.db.io.IntValue; +import com.scalar.db.io.BigIntColumn; +import com.scalar.db.io.BlobColumn; +import com.scalar.db.io.BooleanColumn; +import com.scalar.db.io.Column; +import com.scalar.db.io.ColumnVisitor; +import com.scalar.db.io.DoubleColumn; +import com.scalar.db.io.FloatColumn; +import com.scalar.db.io.IntColumn; import com.scalar.db.io.Key; -import com.scalar.db.io.TextValue; -import com.scalar.db.io.Value; -import com.scalar.db.io.ValueVisitor; +import com.scalar.db.io.TextColumn; import edu.umd.cs.findbugs.annotations.SuppressFBWarnings; import java.util.Map; import javax.annotation.concurrent.NotThreadSafe; @NotThreadSafe -public class KeyBytesEncodedLengthCalculator implements ValueVisitor { +public class KeyBytesEncodedLengthCalculator implements ColumnVisitor { private int length; private Map keyOrders; @@ -24,54 +24,54 @@ public class KeyBytesEncodedLengthCalculator implements ValueVisitor { @SuppressFBWarnings("EI_EXPOSE_REP2") public int calculate(Key key, Map keyOrders) { this.keyOrders = keyOrders; - for (Value value : key) { - value.accept(this); + for (Column column : key.getColumns()) { + column.accept(this); } return length; } @Override - public void visit(BooleanValue value) { + public void visit(BooleanColumn value) { length += BytesEncoders.BOOLEAN.encodedLength( value, keyOrders.getOrDefault(value.getName(), Order.ASC)); } @Override - public void visit(IntValue value) { + public void visit(IntColumn value) { length += BytesEncoders.INT.encodedLength(value, keyOrders.getOrDefault(value.getName(), Order.ASC)); } @Override - public void visit(BigIntValue value) { + public void visit(BigIntColumn value) { length += BytesEncoders.BIGINT.encodedLength( value, keyOrders.getOrDefault(value.getName(), Order.ASC)); } @Override - public void visit(FloatValue value) { + public void visit(FloatColumn value) { length += BytesEncoders.FLOAT.encodedLength( value, keyOrders.getOrDefault(value.getName(), Order.ASC)); } @Override - public void visit(DoubleValue value) { + public void visit(DoubleColumn value) { length += BytesEncoders.DOUBLE.encodedLength( value, keyOrders.getOrDefault(value.getName(), Order.ASC)); } @Override - public void visit(TextValue value) { + public void visit(TextColumn value) { length += BytesEncoders.TEXT.encodedLength(value, keyOrders.getOrDefault(value.getName(), Order.ASC)); } @Override - public void visit(BlobValue value) { + public void visit(BlobColumn value) { length += BytesEncoders.BLOB.encodedLength(value, keyOrders.getOrDefault(value.getName(), Order.ASC)); } diff --git a/core/src/main/java/com/scalar/db/storage/dynamo/bytes/KeyBytesEncoder.java b/core/src/main/java/com/scalar/db/storage/dynamo/bytes/KeyBytesEncoder.java index 0cb510917b..3471aa59ba 100644 --- a/core/src/main/java/com/scalar/db/storage/dynamo/bytes/KeyBytesEncoder.java +++ b/core/src/main/java/com/scalar/db/storage/dynamo/bytes/KeyBytesEncoder.java @@ -1,16 +1,16 @@ package com.scalar.db.storage.dynamo.bytes; import com.scalar.db.api.Scan.Ordering.Order; -import com.scalar.db.io.BigIntValue; -import com.scalar.db.io.BlobValue; -import com.scalar.db.io.BooleanValue; -import com.scalar.db.io.DoubleValue; -import com.scalar.db.io.FloatValue; -import com.scalar.db.io.IntValue; +import com.scalar.db.io.BigIntColumn; +import com.scalar.db.io.BlobColumn; +import com.scalar.db.io.BooleanColumn; +import com.scalar.db.io.Column; +import com.scalar.db.io.ColumnVisitor; +import com.scalar.db.io.DoubleColumn; +import com.scalar.db.io.FloatColumn; +import com.scalar.db.io.IntColumn; import com.scalar.db.io.Key; -import com.scalar.db.io.TextValue; -import com.scalar.db.io.Value; -import com.scalar.db.io.ValueVisitor; +import com.scalar.db.io.TextColumn; import edu.umd.cs.findbugs.annotations.SuppressFBWarnings; import java.nio.ByteBuffer; import java.util.Collections; @@ -19,7 +19,7 @@ /** An encoder that converts a key to bytes while preserving the sort order. */ @NotThreadSafe -public class KeyBytesEncoder implements ValueVisitor { +public class KeyBytesEncoder implements ColumnVisitor { private ByteBuffer dst; private Map keyOrders; @@ -33,7 +33,7 @@ public ByteBuffer encode(Key key, Map keyOrders) { this.keyOrders = keyOrders; int length = new KeyBytesEncodedLengthCalculator().calculate(key, keyOrders); dst = ByteBuffer.allocate(length); - for (Value value : key) { + for (Column value : key.getColumns()) { value.accept(this); } dst.flip(); @@ -41,37 +41,37 @@ public ByteBuffer encode(Key key, Map keyOrders) { } @Override - public void visit(BooleanValue value) { + public void visit(BooleanColumn value) { BytesEncoders.BOOLEAN.encode(value, keyOrders.getOrDefault(value.getName(), Order.ASC), dst); } @Override - public void visit(IntValue value) { + public void visit(IntColumn value) { BytesEncoders.INT.encode(value, keyOrders.getOrDefault(value.getName(), Order.ASC), dst); } @Override - public void visit(BigIntValue value) { + public void visit(BigIntColumn value) { BytesEncoders.BIGINT.encode(value, keyOrders.getOrDefault(value.getName(), Order.ASC), dst); } @Override - public void visit(FloatValue value) { + public void visit(FloatColumn value) { BytesEncoders.FLOAT.encode(value, keyOrders.getOrDefault(value.getName(), Order.ASC), dst); } @Override - public void visit(DoubleValue value) { + public void visit(DoubleColumn value) { BytesEncoders.DOUBLE.encode(value, keyOrders.getOrDefault(value.getName(), Order.ASC), dst); } @Override - public void visit(TextValue value) { + public void visit(TextColumn value) { BytesEncoders.TEXT.encode(value, keyOrders.getOrDefault(value.getName(), Order.ASC), dst); } @Override - public void visit(BlobValue value) { + public void visit(BlobColumn value) { BytesEncoders.BLOB.encode(value, keyOrders.getOrDefault(value.getName(), Order.ASC), dst); } } diff --git a/core/src/main/java/com/scalar/db/storage/dynamo/bytes/TextBytesEncoder.java b/core/src/main/java/com/scalar/db/storage/dynamo/bytes/TextBytesEncoder.java index a0e356cc89..f99015f673 100644 --- a/core/src/main/java/com/scalar/db/storage/dynamo/bytes/TextBytesEncoder.java +++ b/core/src/main/java/com/scalar/db/storage/dynamo/bytes/TextBytesEncoder.java @@ -4,32 +4,36 @@ import com.scalar.db.api.Scan.Ordering.Order; import com.scalar.db.common.error.CoreError; -import com.scalar.db.io.TextValue; +import com.scalar.db.io.TextColumn; import java.nio.ByteBuffer; import java.nio.charset.StandardCharsets; import javax.annotation.concurrent.ThreadSafe; @ThreadSafe -public class TextBytesEncoder implements BytesEncoder { +public class TextBytesEncoder implements BytesEncoder { private static final byte TERM = 0x00; TextBytesEncoder() {} @Override - public int encodedLength(TextValue value, Order order) { - assert value.getAsString().isPresent(); - return value.getAsString().get().getBytes(StandardCharsets.UTF_8).length + 1; + public int encodedLength(TextColumn column, Order order) { + assert column.getValue().isPresent(); + + return column.getValue().get().getBytes(StandardCharsets.UTF_8).length + 1; } @Override - public void encode(TextValue value, Order order, ByteBuffer dst) { - assert value.getAsString().isPresent(); - if (value.getAsString().get().contains("\u0000")) { + public void encode(TextColumn column, Order order, ByteBuffer dst) { + assert column.getValue().isPresent(); + + String value = column.getValue().get(); + + if (value.contains("\u0000")) { throw new IllegalArgumentException( CoreError.DYNAMO_ENCODER_CANNOT_ENCODE_TEXT_VALUE_CONTAINING_0X0000.buildMessage()); } - byte[] bytes = value.getAsString().get().getBytes(StandardCharsets.UTF_8); + byte[] bytes = value.getBytes(StandardCharsets.UTF_8); for (byte b : bytes) { dst.put(mask(b, order)); }