mirror of
https://github.com/microsoft/HybridRow.git
synced 2026-01-19 17:33:13 +00:00
Progressed on RowReader
This commit is contained in:
@@ -1215,7 +1215,7 @@ public final class RowBuffer {
|
||||
* Produce a new scope from the current iterator position.
|
||||
*
|
||||
* @param edit An initialized iterator pointing at a scope.
|
||||
* @param immutable True if the new scope should be marked immutable (read-only).
|
||||
* @param immutable {@code true} if the new scope should be marked immutable (read-only).
|
||||
* @return A new scope beginning at the current iterator position.
|
||||
*/
|
||||
public RowCursor sparseIteratorReadScope(@Nonnull final RowCursor edit, boolean immutable) {
|
||||
|
||||
@@ -108,13 +108,17 @@ public final class RowCursors {
|
||||
}
|
||||
|
||||
public static void skip(
|
||||
@Nonnull final RowCursor edit, @Nonnull final RowBuffer row, @Nonnull final RowCursor childScope) {
|
||||
@Nonnull final RowCursor edit, @Nonnull final RowBuffer buffer, @Nonnull final RowCursor childScope) {
|
||||
|
||||
checkNotNull(edit, "expected non-null edit");
|
||||
checkNotNull(buffer, "expected non-null buffer");
|
||||
checkNotNull(childScope, "expected non-null childScope");
|
||||
|
||||
checkArgument(childScope.start() == edit.valueOffset());
|
||||
|
||||
if (!(childScope.cellType() instanceof LayoutEndScope)) {
|
||||
//noinspection StatementWithEmptyBody
|
||||
while (row.sparseIteratorMoveNext(childScope)) {
|
||||
while (buffer.sparseIteratorMoveNext(childScope)) {
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -3,6 +3,7 @@
|
||||
|
||||
package com.azure.data.cosmos.serialization.hybridrow.io;
|
||||
|
||||
import com.azure.data.cosmos.core.Json;
|
||||
import com.azure.data.cosmos.core.Out;
|
||||
import com.azure.data.cosmos.core.Utf8String;
|
||||
import com.azure.data.cosmos.serialization.hybridrow.Float128;
|
||||
@@ -41,10 +42,15 @@ import com.azure.data.cosmos.serialization.hybridrow.layouts.LayoutVarInt;
|
||||
import com.azure.data.cosmos.serialization.hybridrow.layouts.LayoutVarUInt;
|
||||
import com.azure.data.cosmos.serialization.hybridrow.layouts.TypeArgumentList;
|
||||
import com.azure.data.cosmos.serialization.hybridrow.schemas.StorageKind;
|
||||
import com.fasterxml.jackson.core.JsonGenerator;
|
||||
import com.fasterxml.jackson.databind.SerializerProvider;
|
||||
import com.fasterxml.jackson.databind.annotation.JsonSerialize;
|
||||
import com.fasterxml.jackson.databind.ser.std.StdSerializer;
|
||||
import io.netty.buffer.ByteBuf;
|
||||
|
||||
import javax.annotation.Nonnull;
|
||||
import javax.annotation.Nullable;
|
||||
import java.io.IOException;
|
||||
import java.math.BigDecimal;
|
||||
import java.time.OffsetDateTime;
|
||||
import java.util.List;
|
||||
@@ -65,6 +71,7 @@ import static com.google.common.base.Strings.lenientFormat;
|
||||
* Modifying a {@link RowBuffer} invalidates any reader or child reader associated with it. In general{@link RowBuffer}s
|
||||
* should not be mutated while being enumerated.
|
||||
*/
|
||||
@JsonSerialize(using = RowReader.JsonSerializer.class)
|
||||
public final class RowReader {
|
||||
|
||||
private int columnIndex;
|
||||
@@ -818,7 +825,10 @@ public final class RowReader {
|
||||
* @param value On success, receives the value, undefined otherwise.
|
||||
* @return {@link Result#SUCCESS} if the read is successful, an error {@link Result} otherwise.
|
||||
*/
|
||||
public Result readUInt8(Out<Short> value) {
|
||||
@Nonnull
|
||||
public Result readUInt8(@Nonnull Out<Short> value) {
|
||||
|
||||
checkNotNull(value, "expected non-null value");
|
||||
|
||||
switch (this.state) {
|
||||
|
||||
@@ -839,6 +849,32 @@ public final class RowReader {
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns a string representation of the object. In general, the
|
||||
* {@code toString} method returns a string that
|
||||
* "textually represents" this object. The result should
|
||||
* be a concise but informative representation that is easy for a
|
||||
* person to read.
|
||||
* It is recommended that all subclasses override this method.
|
||||
* <p>
|
||||
* The {@code toString} method for class {@code Object}
|
||||
* returns a string consisting of the name of the class of which the
|
||||
* object is an instance, the at-sign character `{@code @}', and
|
||||
* the unsigned hexadecimal representation of the hash code of the
|
||||
* object. In other words, this method returns a string equal to the
|
||||
* value of:
|
||||
* <blockquote>
|
||||
* <pre>
|
||||
* getClass().getName() + '@' + Integer.toHexString(hashCode())
|
||||
* </pre></blockquote>
|
||||
*
|
||||
* @return a string representation of the object.
|
||||
*/
|
||||
@Override
|
||||
public String toString() {
|
||||
return Json.toString(this);
|
||||
}
|
||||
|
||||
/**
|
||||
* Read the current field as a fixed length {@link UnixDateTime} value.
|
||||
*
|
||||
@@ -999,7 +1035,8 @@ public final class RowReader {
|
||||
* @param value On success, receives the value, undefined otherwise
|
||||
* @return {@link Result#SUCCESS} if the read is successful, an error {@link Result} otherwise.
|
||||
*/
|
||||
private <TValue> Result readPrimitiveValue(Out<TValue> value) {
|
||||
@Nonnull
|
||||
private <TValue> Result readPrimitiveValue(@Nonnull Out<TValue> value) {
|
||||
|
||||
final LayoutColumn column = this.columns.get(this.columnIndex);
|
||||
final LayoutType type = this.columns.get(this.columnIndex).type();
|
||||
@@ -1017,9 +1054,8 @@ public final class RowReader {
|
||||
case VARIABLE:
|
||||
return type.<LayoutTypePrimitive<TValue>>typeAs().readVariable(this.row, this.cursor, column, value);
|
||||
default:
|
||||
assert false : lenientFormat("expected FIXED or VARIABLE column storage, not %s", storage);
|
||||
value.set(null);
|
||||
return Result.FAILURE;
|
||||
String message = lenientFormat("expected FIXED or VARIABLE column storage, not %s", storage);
|
||||
throw new IllegalStateException(message);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1115,11 +1151,30 @@ public final class RowReader {
|
||||
DONE;
|
||||
|
||||
public static final int BYTES = Byte.BYTES;
|
||||
private final String friendlyName;
|
||||
|
||||
States() {
|
||||
this.friendlyName = this.name().toLowerCase();
|
||||
}
|
||||
|
||||
public String friendlyName() {
|
||||
return this.friendlyName;
|
||||
}
|
||||
|
||||
public static States from(byte value) {
|
||||
return values()[value];
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the friendly name of this enum constant, as returned by {@link #friendlyName()}.
|
||||
*
|
||||
* @return the friendly name of this enum constant
|
||||
*/
|
||||
@Override
|
||||
public String toString() {
|
||||
return this.friendlyName;
|
||||
}
|
||||
|
||||
public byte value() {
|
||||
return (byte) this.ordinal();
|
||||
}
|
||||
@@ -1186,4 +1241,30 @@ public final class RowReader {
|
||||
return this;
|
||||
}
|
||||
}
|
||||
|
||||
static final class JsonSerializer extends StdSerializer<RowReader> {
|
||||
|
||||
JsonSerializer() {
|
||||
super(RowReader.class);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void serialize(RowReader value, JsonGenerator generator, SerializerProvider provider) throws IOException {
|
||||
generator.writeStartObject();
|
||||
generator.writeStringField("path", value.path().toUtf16());
|
||||
generator.writeStringField("state", value.state == null ? null : value.state.friendlyName);
|
||||
generator.writeObjectFieldStart("span");
|
||||
generator.writeNumberField("start", value.cursor.start());
|
||||
generator.writeNumberField("end", value.cursor.endOffset());
|
||||
generator.writeEndObject();
|
||||
LayoutColumn column = value.columns.get(value.columnIndex);
|
||||
generator.writeObjectFieldStart("column");
|
||||
generator.writeStringField("fullPath", column.fullPath().toUtf16());
|
||||
generator.writeStringField("type", column.type().name());
|
||||
generator.writeNumberField("index", column.index());
|
||||
generator.writeNumberField("offset", column.offset());
|
||||
generator.writeEndObject();
|
||||
generator.writeEndObject();
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -6,10 +6,12 @@ package com.azure.data.cosmos.serialization.hybridrow.layouts;
|
||||
import com.azure.data.cosmos.serialization.hybridrow.SchemaId;
|
||||
import com.azure.data.cosmos.serialization.hybridrow.schemas.StorageKind;
|
||||
|
||||
import javax.annotation.Nonnull;
|
||||
import java.util.ArrayList;
|
||||
import java.util.Stack;
|
||||
|
||||
import static com.google.common.base.Preconditions.checkArgument;
|
||||
import static com.google.common.base.Preconditions.checkNotNull;
|
||||
|
||||
public final class LayoutBuilder {
|
||||
private LayoutBit.Allocator bitAllocator;
|
||||
@@ -36,27 +38,37 @@ public final class LayoutBuilder {
|
||||
this.reset();
|
||||
}
|
||||
|
||||
public void addFixedColumn(String path, LayoutType type, boolean nullable, int length) {
|
||||
public void addFixedColumn(@Nonnull String path, @Nonnull LayoutType type, boolean nullable, int length) {
|
||||
|
||||
checkNotNull(path, "expected non-null path");
|
||||
checkNotNull(type, "expected non-null type");
|
||||
checkArgument(length >= 0);
|
||||
checkArgument(!type.isVarint());
|
||||
|
||||
LayoutColumn column;
|
||||
final LayoutColumn column;
|
||||
|
||||
if (type.isNull()) {
|
||||
checkArgument(nullable);
|
||||
LayoutBit nullBit = this.bitAllocator.allocate();
|
||||
column = new LayoutColumn(path, type, TypeArgumentList.EMPTY, StorageKind.FIXED, this.parent(),
|
||||
this.fixedCount, 0, nullBit, LayoutBit.INVALID, 0);
|
||||
LayoutBit boolBit = this.bitAllocator.allocate();
|
||||
LayoutBit nullBit = LayoutBit.INVALID;
|
||||
int offset = 0;
|
||||
column = new LayoutColumn(
|
||||
path, type, TypeArgumentList.EMPTY, StorageKind.FIXED, this.parent(), this.fixedCount, offset,
|
||||
boolBit, nullBit, 0);
|
||||
} else if (type.isBoolean()) {
|
||||
LayoutBit nullBit = nullable ? this.bitAllocator.allocate() : LayoutBit.INVALID;
|
||||
LayoutBit boolbit = this.bitAllocator.allocate();
|
||||
column = new LayoutColumn(path, type, TypeArgumentList.EMPTY, StorageKind.FIXED, this.parent(),
|
||||
this.fixedCount, 0, nullBit, boolbit, 0);
|
||||
LayoutBit boolBit = this.bitAllocator.allocate();
|
||||
int offset = 0;
|
||||
column = new LayoutColumn(
|
||||
path, type, TypeArgumentList.EMPTY, StorageKind.FIXED, this.parent(), this.fixedCount, offset,
|
||||
nullBit, boolBit, 0);
|
||||
} else {
|
||||
LayoutBit boolBit = LayoutBit.INVALID;
|
||||
LayoutBit nullBit = nullable ? this.bitAllocator.allocate() : LayoutBit.INVALID;
|
||||
column = new LayoutColumn(path, type, TypeArgumentList.EMPTY, StorageKind.FIXED, this.parent(),
|
||||
this.fixedCount, this.fixedSize, nullBit, LayoutBit.INVALID, length);
|
||||
|
||||
int offset = this.fixedSize;
|
||||
column = new LayoutColumn(
|
||||
path, type, TypeArgumentList.EMPTY, StorageKind.FIXED, this.parent(), this.fixedCount, offset,
|
||||
nullBit, boolBit, length);
|
||||
this.fixedSize += type.isFixed() ? type.size() : length;
|
||||
}
|
||||
|
||||
@@ -74,31 +86,40 @@ public final class LayoutBuilder {
|
||||
this.scope.push(column);
|
||||
}
|
||||
|
||||
public void addSparseColumn(String path, LayoutType type) {
|
||||
public void addSparseColumn(@Nonnull final String path, @Nonnull final LayoutType type) {
|
||||
|
||||
LayoutColumn column = new LayoutColumn(path, type, TypeArgumentList.EMPTY, StorageKind.SPARSE, this.parent(),
|
||||
this.sparseCount, -1, LayoutBit.INVALID, LayoutBit.INVALID, 0);
|
||||
checkNotNull(path, "expected non-null path");
|
||||
checkNotNull(type, "expected non-null type");
|
||||
|
||||
final LayoutColumn column = new LayoutColumn(
|
||||
path, type, TypeArgumentList.EMPTY, StorageKind.SPARSE, this.parent(), this.sparseCount, -1,
|
||||
LayoutBit.INVALID, LayoutBit.INVALID, 0);
|
||||
|
||||
this.sparseCount++;
|
||||
this.sparseColumns.add(column);
|
||||
}
|
||||
|
||||
public void addTypedScope(String path, LayoutType type, TypeArgumentList typeArgs) {
|
||||
public void addTypedScope(
|
||||
@Nonnull final String path, @Nonnull final LayoutType type, @Nonnull final TypeArgumentList typeArgs) {
|
||||
|
||||
LayoutColumn col = new LayoutColumn(path, type, typeArgs, StorageKind.SPARSE, this.parent(), this.sparseCount,
|
||||
-1, LayoutBit.INVALID, LayoutBit.INVALID, 0);
|
||||
final LayoutColumn column = new LayoutColumn(
|
||||
path, type, typeArgs, StorageKind.SPARSE, this.parent(), this.sparseCount, -1, LayoutBit.INVALID,
|
||||
LayoutBit.INVALID, 0);
|
||||
|
||||
this.sparseCount++;
|
||||
this.sparseColumns.add(col);
|
||||
this.sparseColumns.add(column);
|
||||
}
|
||||
|
||||
public void addVariableColumn(String path, LayoutType type, int length) {
|
||||
|
||||
checkNotNull(path, "expected non-null path");
|
||||
checkNotNull(type, "expected non-null type");
|
||||
checkArgument(length >= 0);
|
||||
checkArgument(type.allowVariable());
|
||||
|
||||
LayoutColumn column = new LayoutColumn(path, type, TypeArgumentList.EMPTY, StorageKind.VARIABLE, this.parent(),
|
||||
this.varCount, this.varCount, this.bitAllocator.allocate(), LayoutBit.INVALID, length);
|
||||
final LayoutColumn column = new LayoutColumn(
|
||||
path, type, TypeArgumentList.EMPTY, StorageKind.VARIABLE, this.parent(), this.varCount, this.varCount,
|
||||
this.bitAllocator.allocate(), LayoutBit.INVALID, length);
|
||||
|
||||
this.varCount++;
|
||||
this.varColumns.add(column);
|
||||
|
||||
@@ -15,7 +15,7 @@ import static com.google.common.base.Preconditions.checkArgument;
|
||||
public final class LayoutFloat64 extends LayoutTypePrimitive<Double> {
|
||||
|
||||
public LayoutFloat64() {
|
||||
super(LayoutCode.FLOAT_64, Double.BYTES / Byte.SIZE);
|
||||
super(LayoutCode.FLOAT_64, Double.BYTES);
|
||||
}
|
||||
|
||||
public boolean isFixed() {
|
||||
|
||||
@@ -15,7 +15,7 @@ import static com.google.common.base.Preconditions.checkArgument;
|
||||
public final class LayoutInt64 extends LayoutTypePrimitive<Long> {
|
||||
|
||||
public LayoutInt64() {
|
||||
super(LayoutCode.INT_64, Long.BYTES / Byte.SIZE);
|
||||
super(LayoutCode.INT_64, Long.BYTES);
|
||||
}
|
||||
|
||||
public boolean isFixed() {
|
||||
|
||||
@@ -33,9 +33,9 @@ public final class LayoutUDT extends LayoutPropertyScope {
|
||||
|
||||
@Override
|
||||
@Nonnull
|
||||
public TypeArgumentList readTypeArgumentList(@Nonnull RowBuffer row, int offset, @Nonnull Out<Integer> lenInBytes) {
|
||||
public TypeArgumentList readTypeArgumentList(@Nonnull RowBuffer row, int offset, @Nonnull Out<Integer> lengthInBytes) {
|
||||
SchemaId schemaId = row.readSchemaId(offset);
|
||||
lenInBytes.set(SchemaId.BYTES);
|
||||
lengthInBytes.set(SchemaId.BYTES);
|
||||
return new TypeArgumentList(schemaId);
|
||||
}
|
||||
|
||||
|
||||
@@ -11,6 +11,7 @@ import com.azure.data.cosmos.serialization.hybridrow.RowCursor;
|
||||
import javax.annotation.Nonnull;
|
||||
|
||||
import static com.google.common.base.Preconditions.checkArgument;
|
||||
import static com.google.common.base.Preconditions.checkNotNull;
|
||||
|
||||
public final class LayoutUInt32 extends LayoutTypePrimitive<Long> {
|
||||
|
||||
@@ -31,6 +32,11 @@ public final class LayoutUInt32 extends LayoutTypePrimitive<Long> {
|
||||
@Nonnull
|
||||
public Result readFixed(@Nonnull RowBuffer buffer, @Nonnull RowCursor scope, @Nonnull LayoutColumn column, @Nonnull Out<Long> value) {
|
||||
|
||||
checkNotNull(buffer, "expected non-null buffer");
|
||||
checkNotNull(scope, "expected non-null scope");
|
||||
checkNotNull(column, "expected non-null column");
|
||||
checkNotNull(value, "expected non-null value");
|
||||
|
||||
checkArgument(scope.scopeType() instanceof LayoutUDT);
|
||||
|
||||
if (!buffer.readBit(scope.start(), column.nullBit())) {
|
||||
|
||||
@@ -11,6 +11,7 @@ import com.azure.data.cosmos.serialization.hybridrow.RowCursor;
|
||||
import javax.annotation.Nonnull;
|
||||
|
||||
import static com.google.common.base.Preconditions.checkArgument;
|
||||
import static com.google.common.base.Preconditions.checkNotNull;
|
||||
|
||||
public final class LayoutUInt8 extends LayoutTypePrimitive<Short> {
|
||||
|
||||
@@ -31,6 +32,11 @@ public final class LayoutUInt8 extends LayoutTypePrimitive<Short> {
|
||||
@Nonnull
|
||||
public Result readFixed(@Nonnull RowBuffer buffer, @Nonnull RowCursor scope, @Nonnull LayoutColumn column, @Nonnull Out<Short> value) {
|
||||
|
||||
checkNotNull(buffer, "expected non-null buffer");
|
||||
checkNotNull(scope, "expected non-null scope");
|
||||
checkNotNull(column, "expected non-null column");
|
||||
checkNotNull(value, "expected non-null value");
|
||||
|
||||
checkArgument(scope.scopeType() instanceof LayoutUDT);
|
||||
|
||||
if (!buffer.readBit(scope.start(), column.nullBit())) {
|
||||
|
||||
@@ -73,21 +73,45 @@ public class RowReaderTest {
|
||||
|
||||
private static Result visitFields(RowReader reader, int level) {
|
||||
|
||||
Out out = new Out();
|
||||
|
||||
while (reader.read()) {
|
||||
|
||||
final Utf8String path = reader.path();
|
||||
Utf8String path = reader.path();
|
||||
LayoutType type = reader.type();
|
||||
|
||||
if (type == null) {
|
||||
fail(lenientFormat("path: %s, type: null", path));
|
||||
if (path.isNull() || type == null) {
|
||||
fail(lenientFormat("path: %s, type: %s", path, type));
|
||||
}
|
||||
|
||||
System.out.println(lenientFormat("%s%s:\"%s\"", Strings.repeat(" ", level), path, type.layoutCode()));
|
||||
Out out = new Out();
|
||||
System.out.println(lenientFormat("%s%s : %s", Strings.repeat(" ", level), path, type.name()));
|
||||
|
||||
Result result = Result.SUCCESS;
|
||||
out.set(null);
|
||||
|
||||
switch (type.layoutCode()) {
|
||||
case INT_32: {
|
||||
result = reader.readInt32(out);
|
||||
break;
|
||||
}
|
||||
case INT_64: {
|
||||
result = reader.readInt64(out);
|
||||
break;
|
||||
}
|
||||
case UINT_8: {
|
||||
result = reader.readUInt8(out);
|
||||
break;
|
||||
}
|
||||
case UINT_32: {
|
||||
result = reader.readUInt32(out);
|
||||
break;
|
||||
}
|
||||
case UINT_64: {
|
||||
Result result = reader.readUInt64(out);
|
||||
result = reader.readUInt64(out);
|
||||
break;
|
||||
}
|
||||
case GUID: {
|
||||
result = reader.readGuid(out);
|
||||
break;
|
||||
}
|
||||
case NULL:
|
||||
@@ -95,11 +119,7 @@ public class RowReaderTest {
|
||||
case BOOLEAN_FALSE:
|
||||
case INT_8:
|
||||
case INT_16:
|
||||
case INT_32:
|
||||
case INT_64:
|
||||
case UINT_8:
|
||||
case UINT_16:
|
||||
case UINT_32:
|
||||
case VAR_INT:
|
||||
case VAR_UINT:
|
||||
case FLOAT_32:
|
||||
@@ -108,7 +128,6 @@ public class RowReaderTest {
|
||||
case DECIMAL:
|
||||
case DATE_TIME:
|
||||
case UNIX_DATE_TIME:
|
||||
case GUID:
|
||||
case UTF_8:
|
||||
case BINARY: {
|
||||
break;
|
||||
@@ -155,11 +174,7 @@ public class RowReaderTest {
|
||||
case TYPED_TUPLE_SCOPE:
|
||||
case IMMUTABLE_TYPED_TUPLE_SCOPE: {
|
||||
|
||||
Result result = reader.readScope(null, (RowReader child, Object ignored) -> visitFields(child, level + 1));
|
||||
|
||||
if (result != Result.SUCCESS) {
|
||||
return result;
|
||||
}
|
||||
result = reader.readScope(null, (RowReader child, Object ignored) -> visitFields(child, level + 1));
|
||||
break;
|
||||
}
|
||||
case END_SCOPE:
|
||||
@@ -173,6 +188,9 @@ public class RowReaderTest {
|
||||
break;
|
||||
}
|
||||
}
|
||||
if (result != Result.SUCCESS) {
|
||||
return result;
|
||||
}
|
||||
}
|
||||
|
||||
return Result.SUCCESS;
|
||||
|
||||
Reference in New Issue
Block a user