Progressed on RowReader

This commit is contained in:
David Noble
2019-09-21 15:32:54 -07:00
parent 66a6d20a30
commit 8255a58d17
11 changed files with 184 additions and 48 deletions

View File

@@ -1215,7 +1215,7 @@ public final class RowBuffer {
* Produce a new scope from the current iterator position. * Produce a new scope from the current iterator position.
* *
* @param edit An initialized iterator pointing at a scope. * @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. * @return A new scope beginning at the current iterator position.
*/ */
public RowCursor sparseIteratorReadScope(@Nonnull final RowCursor edit, boolean immutable) { public RowCursor sparseIteratorReadScope(@Nonnull final RowCursor edit, boolean immutable) {

View File

@@ -108,13 +108,17 @@ public final class RowCursors {
} }
public static void skip( 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()); checkArgument(childScope.start() == edit.valueOffset());
if (!(childScope.cellType() instanceof LayoutEndScope)) { if (!(childScope.cellType() instanceof LayoutEndScope)) {
//noinspection StatementWithEmptyBody //noinspection StatementWithEmptyBody
while (row.sparseIteratorMoveNext(childScope)) { while (buffer.sparseIteratorMoveNext(childScope)) {
} }
} }

View File

@@ -3,6 +3,7 @@
package com.azure.data.cosmos.serialization.hybridrow.io; 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.Out;
import com.azure.data.cosmos.core.Utf8String; import com.azure.data.cosmos.core.Utf8String;
import com.azure.data.cosmos.serialization.hybridrow.Float128; 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.LayoutVarUInt;
import com.azure.data.cosmos.serialization.hybridrow.layouts.TypeArgumentList; import com.azure.data.cosmos.serialization.hybridrow.layouts.TypeArgumentList;
import com.azure.data.cosmos.serialization.hybridrow.schemas.StorageKind; 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 io.netty.buffer.ByteBuf;
import javax.annotation.Nonnull; import javax.annotation.Nonnull;
import javax.annotation.Nullable; import javax.annotation.Nullable;
import java.io.IOException;
import java.math.BigDecimal; import java.math.BigDecimal;
import java.time.OffsetDateTime; import java.time.OffsetDateTime;
import java.util.List; 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 * 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. * should not be mutated while being enumerated.
*/ */
@JsonSerialize(using = RowReader.JsonSerializer.class)
public final class RowReader { public final class RowReader {
private int columnIndex; private int columnIndex;
@@ -818,7 +825,10 @@ public final class RowReader {
* @param value On success, receives the value, undefined otherwise. * @param value On success, receives the value, undefined otherwise.
* @return {@link Result#SUCCESS} if the read is successful, an error {@link Result} 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) { 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. * 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 * @param value On success, receives the value, undefined otherwise
* @return {@link Result#SUCCESS} if the read is successful, an error {@link Result} 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 LayoutColumn column = this.columns.get(this.columnIndex);
final LayoutType type = this.columns.get(this.columnIndex).type(); final LayoutType type = this.columns.get(this.columnIndex).type();
@@ -1017,9 +1054,8 @@ public final class RowReader {
case VARIABLE: case VARIABLE:
return type.<LayoutTypePrimitive<TValue>>typeAs().readVariable(this.row, this.cursor, column, value); return type.<LayoutTypePrimitive<TValue>>typeAs().readVariable(this.row, this.cursor, column, value);
default: default:
assert false : lenientFormat("expected FIXED or VARIABLE column storage, not %s", storage); String message = lenientFormat("expected FIXED or VARIABLE column storage, not %s", storage);
value.set(null); throw new IllegalStateException(message);
return Result.FAILURE;
} }
} }
@@ -1115,11 +1151,30 @@ public final class RowReader {
DONE; DONE;
public static final int BYTES = Byte.BYTES; 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) { public static States from(byte value) {
return values()[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() { public byte value() {
return (byte) this.ordinal(); return (byte) this.ordinal();
} }
@@ -1186,4 +1241,30 @@ public final class RowReader {
return this; 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();
}
}
} }

View File

@@ -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.SchemaId;
import com.azure.data.cosmos.serialization.hybridrow.schemas.StorageKind; import com.azure.data.cosmos.serialization.hybridrow.schemas.StorageKind;
import javax.annotation.Nonnull;
import java.util.ArrayList; import java.util.ArrayList;
import java.util.Stack; import java.util.Stack;
import static com.google.common.base.Preconditions.checkArgument; import static com.google.common.base.Preconditions.checkArgument;
import static com.google.common.base.Preconditions.checkNotNull;
public final class LayoutBuilder { public final class LayoutBuilder {
private LayoutBit.Allocator bitAllocator; private LayoutBit.Allocator bitAllocator;
@@ -36,27 +38,37 @@ public final class LayoutBuilder {
this.reset(); 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(length >= 0);
checkArgument(!type.isVarint()); checkArgument(!type.isVarint());
LayoutColumn column; final LayoutColumn column;
if (type.isNull()) { if (type.isNull()) {
checkArgument(nullable); checkArgument(nullable);
LayoutBit nullBit = this.bitAllocator.allocate(); LayoutBit boolBit = this.bitAllocator.allocate();
column = new LayoutColumn(path, type, TypeArgumentList.EMPTY, StorageKind.FIXED, this.parent(), LayoutBit nullBit = LayoutBit.INVALID;
this.fixedCount, 0, nullBit, LayoutBit.INVALID, 0); int offset = 0;
column = new LayoutColumn(
path, type, TypeArgumentList.EMPTY, StorageKind.FIXED, this.parent(), this.fixedCount, offset,
boolBit, nullBit, 0);
} else if (type.isBoolean()) { } else if (type.isBoolean()) {
LayoutBit nullBit = nullable ? this.bitAllocator.allocate() : LayoutBit.INVALID; LayoutBit nullBit = nullable ? this.bitAllocator.allocate() : LayoutBit.INVALID;
LayoutBit boolbit = this.bitAllocator.allocate(); LayoutBit boolBit = this.bitAllocator.allocate();
column = new LayoutColumn(path, type, TypeArgumentList.EMPTY, StorageKind.FIXED, this.parent(), int offset = 0;
this.fixedCount, 0, nullBit, boolbit, 0); column = new LayoutColumn(
path, type, TypeArgumentList.EMPTY, StorageKind.FIXED, this.parent(), this.fixedCount, offset,
nullBit, boolBit, 0);
} else { } else {
LayoutBit boolBit = LayoutBit.INVALID;
LayoutBit nullBit = nullable ? this.bitAllocator.allocate() : LayoutBit.INVALID; LayoutBit nullBit = nullable ? this.bitAllocator.allocate() : LayoutBit.INVALID;
column = new LayoutColumn(path, type, TypeArgumentList.EMPTY, StorageKind.FIXED, this.parent(), int offset = this.fixedSize;
this.fixedCount, this.fixedSize, nullBit, LayoutBit.INVALID, length); column = new LayoutColumn(
path, type, TypeArgumentList.EMPTY, StorageKind.FIXED, this.parent(), this.fixedCount, offset,
nullBit, boolBit, length);
this.fixedSize += type.isFixed() ? type.size() : length; this.fixedSize += type.isFixed() ? type.size() : length;
} }
@@ -74,31 +86,40 @@ public final class LayoutBuilder {
this.scope.push(column); 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(), checkNotNull(path, "expected non-null path");
this.sparseCount, -1, LayoutBit.INVALID, LayoutBit.INVALID, 0); 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.sparseCount++;
this.sparseColumns.add(column); 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, final LayoutColumn column = new LayoutColumn(
-1, LayoutBit.INVALID, LayoutBit.INVALID, 0); path, type, typeArgs, StorageKind.SPARSE, this.parent(), this.sparseCount, -1, LayoutBit.INVALID,
LayoutBit.INVALID, 0);
this.sparseCount++; this.sparseCount++;
this.sparseColumns.add(col); this.sparseColumns.add(column);
} }
public void addVariableColumn(String path, LayoutType type, int length) { 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(length >= 0);
checkArgument(type.allowVariable()); checkArgument(type.allowVariable());
LayoutColumn column = new LayoutColumn(path, type, TypeArgumentList.EMPTY, StorageKind.VARIABLE, this.parent(), final LayoutColumn column = new LayoutColumn(
this.varCount, this.varCount, this.bitAllocator.allocate(), LayoutBit.INVALID, length); path, type, TypeArgumentList.EMPTY, StorageKind.VARIABLE, this.parent(), this.varCount, this.varCount,
this.bitAllocator.allocate(), LayoutBit.INVALID, length);
this.varCount++; this.varCount++;
this.varColumns.add(column); this.varColumns.add(column);

View File

@@ -15,7 +15,7 @@ import static com.google.common.base.Preconditions.checkArgument;
public final class LayoutFloat64 extends LayoutTypePrimitive<Double> { public final class LayoutFloat64 extends LayoutTypePrimitive<Double> {
public LayoutFloat64() { public LayoutFloat64() {
super(LayoutCode.FLOAT_64, Double.BYTES / Byte.SIZE); super(LayoutCode.FLOAT_64, Double.BYTES);
} }
public boolean isFixed() { public boolean isFixed() {

View File

@@ -15,7 +15,7 @@ import static com.google.common.base.Preconditions.checkArgument;
public final class LayoutInt64 extends LayoutTypePrimitive<Long> { public final class LayoutInt64 extends LayoutTypePrimitive<Long> {
public LayoutInt64() { public LayoutInt64() {
super(LayoutCode.INT_64, Long.BYTES / Byte.SIZE); super(LayoutCode.INT_64, Long.BYTES);
} }
public boolean isFixed() { public boolean isFixed() {

View File

@@ -33,9 +33,9 @@ public final class LayoutUDT extends LayoutPropertyScope {
@Override @Override
@Nonnull @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); SchemaId schemaId = row.readSchemaId(offset);
lenInBytes.set(SchemaId.BYTES); lengthInBytes.set(SchemaId.BYTES);
return new TypeArgumentList(schemaId); return new TypeArgumentList(schemaId);
} }

View File

@@ -11,6 +11,7 @@ import com.azure.data.cosmos.serialization.hybridrow.RowCursor;
import javax.annotation.Nonnull; import javax.annotation.Nonnull;
import static com.google.common.base.Preconditions.checkArgument; import static com.google.common.base.Preconditions.checkArgument;
import static com.google.common.base.Preconditions.checkNotNull;
public final class LayoutUInt32 extends LayoutTypePrimitive<Long> { public final class LayoutUInt32 extends LayoutTypePrimitive<Long> {
@@ -31,6 +32,11 @@ public final class LayoutUInt32 extends LayoutTypePrimitive<Long> {
@Nonnull @Nonnull
public Result readFixed(@Nonnull RowBuffer buffer, @Nonnull RowCursor scope, @Nonnull LayoutColumn column, @Nonnull Out<Long> value) { 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); checkArgument(scope.scopeType() instanceof LayoutUDT);
if (!buffer.readBit(scope.start(), column.nullBit())) { if (!buffer.readBit(scope.start(), column.nullBit())) {

View File

@@ -11,6 +11,7 @@ import com.azure.data.cosmos.serialization.hybridrow.RowCursor;
import javax.annotation.Nonnull; import javax.annotation.Nonnull;
import static com.google.common.base.Preconditions.checkArgument; import static com.google.common.base.Preconditions.checkArgument;
import static com.google.common.base.Preconditions.checkNotNull;
public final class LayoutUInt8 extends LayoutTypePrimitive<Short> { public final class LayoutUInt8 extends LayoutTypePrimitive<Short> {
@@ -31,6 +32,11 @@ public final class LayoutUInt8 extends LayoutTypePrimitive<Short> {
@Nonnull @Nonnull
public Result readFixed(@Nonnull RowBuffer buffer, @Nonnull RowCursor scope, @Nonnull LayoutColumn column, @Nonnull Out<Short> value) { 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); checkArgument(scope.scopeType() instanceof LayoutUDT);
if (!buffer.readBit(scope.start(), column.nullBit())) { if (!buffer.readBit(scope.start(), column.nullBit())) {

View File

@@ -73,21 +73,45 @@ public class RowReaderTest {
private static Result visitFields(RowReader reader, int level) { private static Result visitFields(RowReader reader, int level) {
Out out = new Out();
while (reader.read()) { while (reader.read()) {
final Utf8String path = reader.path(); Utf8String path = reader.path();
LayoutType type = reader.type(); LayoutType type = reader.type();
if (type == null) { if (path.isNull() || type == null) {
fail(lenientFormat("path: %s, type: null", path)); fail(lenientFormat("path: %s, type: %s", path, type));
} }
System.out.println(lenientFormat("%s%s:\"%s\"", Strings.repeat(" ", level), path, type.layoutCode())); System.out.println(lenientFormat("%s%s : %s", Strings.repeat(" ", level), path, type.name()));
Out out = new Out();
Result result = Result.SUCCESS;
out.set(null);
switch (type.layoutCode()) { 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: { case UINT_64: {
Result result = reader.readUInt64(out); result = reader.readUInt64(out);
break;
}
case GUID: {
result = reader.readGuid(out);
break; break;
} }
case NULL: case NULL:
@@ -95,11 +119,7 @@ public class RowReaderTest {
case BOOLEAN_FALSE: case BOOLEAN_FALSE:
case INT_8: case INT_8:
case INT_16: case INT_16:
case INT_32:
case INT_64:
case UINT_8:
case UINT_16: case UINT_16:
case UINT_32:
case VAR_INT: case VAR_INT:
case VAR_UINT: case VAR_UINT:
case FLOAT_32: case FLOAT_32:
@@ -108,7 +128,6 @@ public class RowReaderTest {
case DECIMAL: case DECIMAL:
case DATE_TIME: case DATE_TIME:
case UNIX_DATE_TIME: case UNIX_DATE_TIME:
case GUID:
case UTF_8: case UTF_8:
case BINARY: { case BINARY: {
break; break;
@@ -155,11 +174,7 @@ public class RowReaderTest {
case TYPED_TUPLE_SCOPE: case TYPED_TUPLE_SCOPE:
case IMMUTABLE_TYPED_TUPLE_SCOPE: { case IMMUTABLE_TYPED_TUPLE_SCOPE: {
Result result = reader.readScope(null, (RowReader child, Object ignored) -> visitFields(child, level + 1)); result = reader.readScope(null, (RowReader child, Object ignored) -> visitFields(child, level + 1));
if (result != Result.SUCCESS) {
return result;
}
break; break;
} }
case END_SCOPE: case END_SCOPE:
@@ -173,6 +188,9 @@ public class RowReaderTest {
break; break;
} }
} }
if (result != Result.SUCCESS) {
return result;
}
} }
return Result.SUCCESS; return Result.SUCCESS;

BIN
layout.xlsx Normal file

Binary file not shown.