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.
*
* @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) {

View File

@@ -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)) {
}
}

View File

@@ -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();
}
}
}

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.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);

View File

@@ -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() {

View File

@@ -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() {

View File

@@ -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);
}

View File

@@ -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())) {

View File

@@ -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())) {

View File

@@ -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;