added packWithVersionstamp to subspace ; some testing/javadocs tweaks

This commit is contained in:
Alec Grieser 2017-10-11 10:53:51 -07:00
parent f95553aca2
commit 9fd934e002
10 changed files with 105 additions and 37 deletions

View File

@ -28,6 +28,7 @@ import java.util.Arrays;
import com.apple.cie.foundationdb.Range; import com.apple.cie.foundationdb.Range;
import com.apple.cie.foundationdb.tuple.ByteArrayUtil; import com.apple.cie.foundationdb.tuple.ByteArrayUtil;
import com.apple.cie.foundationdb.tuple.Tuple; import com.apple.cie.foundationdb.tuple.Tuple;
import com.apple.cie.foundationdb.tuple.Versionstamp;
/** /**
* {@code Subspace} provide a convenient way to use {@link Tuple}s to define namespaces for * {@code Subspace} provide a convenient way to use {@link Tuple}s to define namespaces for
@ -60,8 +61,11 @@ public class Subspace
/** /**
* Constructor for a subspace formed with the specified prefix {@link Tuple}. * Constructor for a subspace formed with the specified prefix {@link Tuple}.
* Note that the {@link Tuple} {@code prefix} should not contain any incomplete
* {@link Versionstamp}s as any of its entries.
* *
* @param prefix a {@link Tuple} used to form the subspace * @param prefix a {@link Tuple} used to form the subspace
* @throws IllegalArgumentException if {@code prefix} contains any incomplete {@link Versionstamp}s
*/ */
public Subspace(Tuple prefix) { public Subspace(Tuple prefix) {
this(prefix, EMPTY_BYTES); this(prefix, EMPTY_BYTES);
@ -81,10 +85,12 @@ public class Subspace
* Constructor for a subspace formed with both a prefix {@link Tuple} and a * Constructor for a subspace formed with both a prefix {@link Tuple} and a
* prefix byte string. The prefix {@code Tuple} will be prepended to all * prefix byte string. The prefix {@code Tuple} will be prepended to all
* {@code Tuples} packed by the {@code Subspace}, and the byte string prefix * {@code Tuples} packed by the {@code Subspace}, and the byte string prefix
* will be prepended to the packed result. * will be prepended to the packed result. Note that the {@link Tuple} {@code prefix}
* should not contain any incomplete {@link Versionstamp}s as any of its entries.
* *
* @param prefix a {@code Tuple} used to form the subspace * @param prefix a {@code Tuple} used to form the subspace
* @param rawPrefix a byte array used as the prefix for all packed keys * @param rawPrefix a byte array used as the prefix for all packed keys
* @throws IllegalArgumentException if {@code prefix} contains any incomplete {@link Versionstamp}s
*/ */
public Subspace(Tuple prefix, byte[] rawPrefix) { public Subspace(Tuple prefix, byte[] rawPrefix) {
this.rawPrefix = join(rawPrefix, prefix.pack()); this.rawPrefix = join(rawPrefix, prefix.pack());
@ -181,6 +187,24 @@ public class Subspace
return join(rawPrefix, tuple.pack()); return join(rawPrefix, tuple.pack());
} }
/**
* Gets the key encoding the specified tuple in this {@code Subspace} for use with
* {@link com.apple.cie.foundationdb.MutationType#SET_VERSIONSTAMPED_KEY MutationType.SET_VERSIONSTAMPED_KEY}.
* There must be exactly one incomplete {@link Versionstamp} included in the given {@link Tuple}. It will
* create a key that is within this {@code Subspace} that can be provided as the {@code key} argument to
* {@link com.apple.cie.foundationdb.Transaction#mutate(com.apple.cie.foundationdb.MutationType, byte[], byte[]) Transaction.mutate()}
* with the {@link com.apple.cie.foundationdb.MutationType#SET_VERSIONSTAMPED_KEY SET_VERSIONSTAMPED_KEY}
* mutation. This will throw an {@link IllegalArgumentException} if the {@link Tuple} does not
* contain an incomplete {@link Versionstamp} or if it contains multiple.
*
* @param tuple the {@code Tuple} to be packed
* @return the key encoding the specified tuple in this {@code Subspace}
* @throws IllegalArgumentException if {@code tuple} does not contain exactly one incomplete {@link Versionstamp}
*/
public byte[] packWithVersionstamp(Tuple tuple) {
return tuple.packWithVersionstamp(rawPrefix);
}
/** /**
* Gets the {@link Tuple} encoded by the given key, with this {@code Subspace}'s prefix {@link Tuple} and * Gets the {@link Tuple} encoded by the given key, with this {@code Subspace}'s prefix {@link Tuple} and
* {@code raw prefix} removed. * {@code raw prefix} removed.

View File

@ -304,7 +304,7 @@ public class Tuple implements Comparable<Tuple>, Iterable<Object> {
public byte[] pack(byte[] prefix) { public byte[] pack(byte[] prefix) {
TupleUtil.EncodeResult encoded = TupleUtil.pack(elements, prefix); TupleUtil.EncodeResult encoded = TupleUtil.pack(elements, prefix);
if(encoded.versionPos > 0) { if(encoded.versionPos > 0) {
throw new IllegalStateException("Incomplete Versionstamp included in vanilla tuple pack"); throw new IllegalArgumentException("Incomplete Versionstamp included in vanilla tuple pack");
} }
return encoded.data; return encoded.data;
} }
@ -316,6 +316,7 @@ public class Tuple implements Comparable<Tuple>, Iterable<Object> {
* but it does not add any prefix to the array. * but it does not add any prefix to the array.
* *
* @return a serialized representation of this {@code Tuple} for use with versionstamp ops. * @return a serialized representation of this {@code Tuple} for use with versionstamp ops.
* @throws IllegalArgumentException if there is not exactly one incomplete {@link Versionstamp} included in this {@code Tuple}
*/ */
public byte[] packWithVersionstamp() { public byte[] packWithVersionstamp() {
return packWithVersionstamp(null); return packWithVersionstamp(null);
@ -330,17 +331,18 @@ public class Tuple implements Comparable<Tuple>, Iterable<Object> {
* is then prepended to the array, and then the index of the serialized incomplete * is then prepended to the array, and then the index of the serialized incomplete
* {@link Versionstamp} is appended as a little-endian integer. This can then be passed * {@link Versionstamp} is appended as a little-endian integer. This can then be passed
* as the key to * as the key to
* {@link com.apple.cie.foundationdb.Transaction#mutate(com.apple.cie.foundationdb.MutationType, byte[], byte[]) Transaction.mutate} * {@link com.apple.cie.foundationdb.Transaction#mutate(com.apple.cie.foundationdb.MutationType, byte[], byte[]) Transaction.mutate()}
* with the {@code SET_VERSIONSTAMPED_KEY} {@link com.apple.cie.foundationdb.MutationType}, and the transaction's * with the {@code SET_VERSIONSTAMPED_KEY} {@link com.apple.cie.foundationdb.MutationType}, and the transaction's
* version will then be filled in at commit time. * version will then be filled in at commit time.
* *
* @param prefix additional byte-array prefix to prepend to serialized bytes. * @param prefix additional byte-array prefix to prepend to serialized bytes.
* @return a serialized representation of this {@code Tuple} for use with versionstamp ops. * @return a serialized representation of this {@code Tuple} for use with versionstamp ops.
* @throws IllegalArgumentException if there is not exactly one incomplete {@link Versionstamp} included in this {@code Tuple}
*/ */
public byte[] packWithVersionstamp(byte[] prefix) { public byte[] packWithVersionstamp(byte[] prefix) {
TupleUtil.EncodeResult encoded = TupleUtil.pack(elements, prefix); TupleUtil.EncodeResult encoded = TupleUtil.pack(elements, prefix);
if(encoded.versionPos < 0) { if(encoded.versionPos < 0) {
throw new IllegalStateException("No incomplete Versionstamp included in tuple pack with versionstamp"); throw new IllegalArgumentException("No incomplete Versionstamp included in tuple pack with versionstamp");
} }
return ByteBuffer.allocate(encoded.data.length + 2).order(ByteOrder.LITTLE_ENDIAN) return ByteBuffer.allocate(encoded.data.length + 2).order(ByteOrder.LITTLE_ENDIAN)
.put(encoded.data) .put(encoded.data)

View File

@ -312,7 +312,7 @@ class TupleUtil {
EncodeResult childResult = encode(t, true); EncodeResult childResult = encode(t, true);
if(childResult.versionPos > 0) { if(childResult.versionPos > 0) {
if(versionPos > 0) { if(versionPos > 0) {
throw new IllegalStateException("Multiple incomplete Versionstamps included in Tuple"); throw new IllegalArgumentException("Multiple incomplete Versionstamps included in Tuple");
} }
versionPos = lenSoFar + childResult.versionPos; versionPos = lenSoFar + childResult.versionPos;
} }
@ -529,7 +529,7 @@ class TupleUtil {
EncodeResult result = encode(t); EncodeResult result = encode(t);
if(result.versionPos > 0) { if(result.versionPos > 0) {
if(versionPos > 0) { if(versionPos > 0) {
throw new IllegalStateException("Multiple incomplete Versionstamps included in Tuple"); throw new IllegalArgumentException("Multiple incomplete Versionstamps included in Tuple");
} }
versionPos = result.versionPos + lenSoFar; versionPos = result.versionPos + lenSoFar;
} }

View File

@ -488,11 +488,16 @@ public class AsyncStackTester {
return inst.popParams(tupleSize).thenApplyAsync(new Function<List<Object>, Void>() { return inst.popParams(tupleSize).thenApplyAsync(new Function<List<Object>, Void>() {
@Override @Override
public Void apply(List<Object> elements) { public Void apply(List<Object> elements) {
Tuple tuple = Tuple.fromItems(elements);
if(!tuple.hasIncompleteVersionstamp() && Math.random() < 0.5) {
inst.push("ERROR: NONE".getBytes());
return null;
}
try { try {
byte[] coded = Tuple.fromItems(elements).packWithVersionstamp(prefix); byte[] coded = tuple.packWithVersionstamp(prefix);
inst.push("OK".getBytes()); inst.push("OK".getBytes());
inst.push(coded); inst.push(coded);
} catch(IllegalStateException e) { } catch(IllegalArgumentException e) {
if(e.getMessage().startsWith("No incomplete")) { if(e.getMessage().startsWith("No incomplete")) {
inst.push("ERROR: NONE".getBytes()); inst.push("ERROR: NONE".getBytes());
} else { } else {

View File

@ -342,16 +342,20 @@ public class StackTester {
byte[] prefix = (byte[])params.get(0); byte[] prefix = (byte[])params.get(0);
int tupleSize = StackUtils.getInt(params.get(1)); int tupleSize = StackUtils.getInt(params.get(1));
//System.out.println(inst.context.preStr + " - " + "Packing top " + tupleSize + " items from stack"); //System.out.println(inst.context.preStr + " - " + "Packing top " + tupleSize + " items from stack");
List<Object> elements = inst.popParams(tupleSize).join(); Tuple tuple = Tuple.fromItems(inst.popParams(tupleSize).join());
try { if(!tuple.hasIncompleteVersionstamp() && Math.random() < 0.5) {
byte[] coded = Tuple.fromItems(elements).packWithVersionstamp(prefix); inst.push("ERROR: NONE".getBytes());
inst.push("OK".getBytes()); } else {
inst.push(coded); try {
} catch(IllegalStateException e) { byte[] coded = tuple.packWithVersionstamp(prefix);
if(e.getMessage().startsWith("No incomplete")) { inst.push("OK".getBytes());
inst.push("ERROR: NONE".getBytes()); inst.push(coded);
} else { } catch (IllegalArgumentException e) {
inst.push("ERROR: MULTIPLE".getBytes()); if (e.getMessage().startsWith("No incomplete")) {
inst.push("ERROR: NONE".getBytes());
} else {
inst.push("ERROR: MULTIPLE".getBytes());
}
} }
} }
} }

View File

@ -28,6 +28,7 @@ import java.util.Arrays;
import com.apple.cie.foundationdb.Range; import com.apple.cie.foundationdb.Range;
import com.apple.cie.foundationdb.tuple.ByteArrayUtil; import com.apple.cie.foundationdb.tuple.ByteArrayUtil;
import com.apple.cie.foundationdb.tuple.Tuple; import com.apple.cie.foundationdb.tuple.Tuple;
import com.apple.cie.foundationdb.tuple.Versionstamp;
/** /**
* {@code Subspace} provide a convenient way to use {@link Tuple}s to define namespaces for * {@code Subspace} provide a convenient way to use {@link Tuple}s to define namespaces for
@ -60,8 +61,11 @@ public class Subspace
/** /**
* Constructor for a subspace formed with the specified prefix {@link Tuple}. * Constructor for a subspace formed with the specified prefix {@link Tuple}.
* Note that the {@link Tuple} {@code prefix} should not contain any incomplete
* {@link Versionstamp}s as any of its entries.
* *
* @param prefix a {@link Tuple} used to form the subspace * @param prefix a {@link Tuple} used to form the subspace
* @throws IllegalArgumentException if {@code prefix} contains any incomplete {@link Versionstamp}s
*/ */
public Subspace(Tuple prefix) { public Subspace(Tuple prefix) {
this(prefix, EMPTY_BYTES); this(prefix, EMPTY_BYTES);
@ -81,10 +85,12 @@ public class Subspace
* Constructor for a subspace formed with both a prefix {@link Tuple} and a * Constructor for a subspace formed with both a prefix {@link Tuple} and a
* prefix byte string. The prefix {@code Tuple} will be prepended to all * prefix byte string. The prefix {@code Tuple} will be prepended to all
* {@code Tuples} packed by the {@code Subspace}, and the byte string prefix * {@code Tuples} packed by the {@code Subspace}, and the byte string prefix
* will be prepended to the packed result. * will be prepended to the packed result. Note that the {@link Tuple} {@code prefix}
* should not contain any incomplete {@link Versionstamp}s as any of its entries.
* *
* @param prefix a {@code Tuple} used to form the subspace * @param prefix a {@code Tuple} used to form the subspace
* @param rawPrefix a byte array used as the prefix for all packed keys * @param rawPrefix a byte array used as the prefix for all packed keys
* @throws IllegalArgumentException if {@code prefix} contains any incomplete {@link Versionstamp}s
*/ */
public Subspace(Tuple prefix, byte[] rawPrefix) { public Subspace(Tuple prefix, byte[] rawPrefix) {
this.rawPrefix = join(rawPrefix, prefix.pack()); this.rawPrefix = join(rawPrefix, prefix.pack());
@ -178,7 +184,25 @@ public class Subspace
* @return the key encoding the specified tuple in this {@code Subspace} * @return the key encoding the specified tuple in this {@code Subspace}
*/ */
public byte[] pack(Tuple tuple) { public byte[] pack(Tuple tuple) {
return join(rawPrefix, tuple.pack()); return tuple.pack(rawPrefix);
}
/**
* Gets the key encoding the specified tuple in this {@code Subspace} for use with
* {@link com.apple.cie.foundationdb.MutationType#SET_VERSIONSTAMPED_KEY MutationType.SET_VERSIONSTAMPED_KEY}.
* There must be exactly one incomplete {@link Versionstamp} included in the given {@link Tuple}. It will
* create a key that is within this {@code Subspace} that can be provided as the {@code key} argument to
* {@link com.apple.cie.foundationdb.Transaction#mutate(com.apple.cie.foundationdb.MutationType, byte[], byte[]) Transaction.mutate()}
* with the {@link com.apple.cie.foundationdb.MutationType#SET_VERSIONSTAMPED_KEY SET_VERSIONSTAMPED_KEY}
* mutation. This will throw an {@link IllegalArgumentException} if the {@link Tuple} does not
* contain an incomplete {@link Versionstamp} or if it contains multiple.
*
* @param tuple the {@code Tuple} to be packed
* @return the key encoding the specified tuple in this {@code Subspace}
* @throws IllegalArgumentException if {@code tuple} does not contain exactly one incomplete {@link Versionstamp}
*/
public byte[] packWithVersionstamp(Tuple tuple) {
return tuple.packWithVersionstamp(rawPrefix);
} }
/** /**

View File

@ -301,7 +301,7 @@ public class Tuple implements Comparable<Tuple>, Iterable<Object> {
public byte[] pack(byte[] prefix) { public byte[] pack(byte[] prefix) {
TupleUtil.EncodeResult encoded = TupleUtil.pack(elements, prefix); TupleUtil.EncodeResult encoded = TupleUtil.pack(elements, prefix);
if(encoded.versionPos > 0) { if(encoded.versionPos > 0) {
throw new IllegalStateException("Incomplete Versionstamp included in vanilla tuple pack"); throw new IllegalArgumentException("Incomplete Versionstamp included in vanilla tuple pack");
} }
return encoded.data; return encoded.data;
} }
@ -328,7 +328,7 @@ public class Tuple implements Comparable<Tuple>, Iterable<Object> {
* is then prepended to the array, and then the index of the serialized incomplete * is then prepended to the array, and then the index of the serialized incomplete
* {@link Versionstamp} is appended as a little-endian integer. This can then be passed * {@link Versionstamp} is appended as a little-endian integer. This can then be passed
* as the key to * as the key to
* {@link com.apple.cie.foundationdb.Transaction#mutate(com.apple.cie.foundationdb.MutationType, byte[], byte[]) Transaction.mutate} * {@link com.apple.cie.foundationdb.Transaction#mutate(com.apple.cie.foundationdb.MutationType, byte[], byte[]) Transaction.mutate()}
* with the {@code SET_VERSIONSTAMPED_KEY} {@link com.apple.cie.foundationdb.MutationType}, and the transaction's * with the {@code SET_VERSIONSTAMPED_KEY} {@link com.apple.cie.foundationdb.MutationType}, and the transaction's
* version will then be filled in at commit time. * version will then be filled in at commit time.
* *
@ -339,7 +339,7 @@ public class Tuple implements Comparable<Tuple>, Iterable<Object> {
public byte[] packWithVersionstamp(byte[] prefix) { public byte[] packWithVersionstamp(byte[] prefix) {
TupleUtil.EncodeResult encoded = TupleUtil.pack(elements, prefix); TupleUtil.EncodeResult encoded = TupleUtil.pack(elements, prefix);
if(encoded.versionPos < 0) { if(encoded.versionPos < 0) {
throw new IllegalStateException("No incomplete Versionstamp included in tuple pack with versionstamp"); throw new IllegalArgumentException("No incomplete Versionstamp included in tuple pack with versionstamp");
} }
return ByteBuffer.allocate(encoded.data.length + 2).order(ByteOrder.LITTLE_ENDIAN) return ByteBuffer.allocate(encoded.data.length + 2).order(ByteOrder.LITTLE_ENDIAN)
.put(encoded.data) .put(encoded.data)

View File

@ -535,7 +535,7 @@ class TupleUtil {
EncodeResult result = encode(t); EncodeResult result = encode(t);
if(result.versionPos > 0) { if(result.versionPos > 0) {
if(versionPos > 0) { if(versionPos > 0) {
throw new IllegalStateException("Multiple incomplete Versionstamps included in Tuple"); throw new IllegalArgumentException("Multiple incomplete Versionstamps included in Tuple");
} }
versionPos = result.versionPos + lenSoFar; versionPos = result.versionPos + lenSoFar;
} }

View File

@ -36,6 +36,7 @@ import com.apple.cie.foundationdb.Range;
import com.apple.cie.foundationdb.ReadTransaction; import com.apple.cie.foundationdb.ReadTransaction;
import com.apple.cie.foundationdb.StreamingMode; import com.apple.cie.foundationdb.StreamingMode;
import com.apple.cie.foundationdb.Transaction; import com.apple.cie.foundationdb.Transaction;
import com.apple.cie.foundationdb.async.AsyncUtil;
import com.apple.cie.foundationdb.async.Function; import com.apple.cie.foundationdb.async.Function;
import com.apple.cie.foundationdb.async.Future; import com.apple.cie.foundationdb.async.Future;
import com.apple.cie.foundationdb.async.ReadyFuture; import com.apple.cie.foundationdb.async.ReadyFuture;
@ -525,12 +526,17 @@ public class AsyncStackTester {
return inst.popParams(tupleSize).flatMap(new Function<List<Object>, Future<Void>>() { return inst.popParams(tupleSize).flatMap(new Function<List<Object>, Future<Void>>() {
@Override @Override
public Future<Void> apply(List<Object> elements) { public Future<Void> apply(List<Object> elements) {
Tuple tuple = Tuple.fromItems(elements);
if(!tuple.hasIncompleteVersionstamp() && Math.random() < 0.5) {
inst.push("ERROR: NONE".getBytes());
return ReadyFuture.DONE;
}
try { try {
byte[] coded = Tuple.fromItems(elements).packWithVersionstamp(prefix); byte[] coded = tuple.packWithVersionstamp(prefix);
//System.out.println(inst.context.preStr + " - " + " -> result '" + ByteArrayUtil.printable(coded) + "'"); //System.out.println(inst.context.preStr + " - " + " -> result '" + ByteArrayUtil.printable(coded) + "'");
inst.push("OK".getBytes()); inst.push("OK".getBytes());
inst.push(coded); inst.push(coded);
} catch(IllegalStateException e) { } catch(IllegalArgumentException e) {
//System.out.println(inst.context.preStr + " - " + " -> result '" + e.getMessage() + "'"); //System.out.println(inst.context.preStr + " - " + " -> result '" + e.getMessage() + "'");
if(e.getMessage().startsWith("No incomplete")) if(e.getMessage().startsWith("No incomplete"))
inst.push("ERROR: NONE".getBytes()); inst.push("ERROR: NONE".getBytes());
@ -737,7 +743,6 @@ public class AsyncStackTester {
} }
}); });
} }
} }
return logStack(inst.context.db, entries, prefix); return logStack(inst.context.db, entries, prefix);

View File

@ -371,16 +371,20 @@ public class StackTester {
byte[] prefix = (byte[])params.get(0); byte[] prefix = (byte[])params.get(0);
int tupleSize = StackUtils.getInt(params.get(1)); int tupleSize = StackUtils.getInt(params.get(1));
//System.out.println(inst.context.preStr + " - " + "Packing top " + tupleSize + " items from stack"); //System.out.println(inst.context.preStr + " - " + "Packing top " + tupleSize + " items from stack");
List<Object> elements = inst.popParams(tupleSize).get(); Tuple tuple = Tuple.fromItems(inst.popParams(tupleSize).get());
try { if(!tuple.hasIncompleteVersionstamp() && Math.random() < 0.5) {
byte[] coded = Tuple.fromItems(elements).packWithVersionstamp(prefix); inst.push("ERROR: NONE".getBytes());
inst.push("OK".getBytes()); } else {
inst.push(coded); try {
} catch(IllegalStateException e) { byte[] coded = tuple.packWithVersionstamp(prefix);
if(e.getMessage().startsWith("No incomplete")) { inst.push("OK".getBytes());
inst.push("ERROR: NONE".getBytes()); inst.push(coded);
} else { } catch (IllegalArgumentException e) {
inst.push("ERROR: MULTIPLE".getBytes()); if (e.getMessage().startsWith("No incomplete")) {
inst.push("ERROR: NONE".getBytes());
} else {
inst.push("ERROR: MULTIPLE".getBytes());
}
} }
} }
//System.out.println(inst.context.preStr + " - " + " -> result '" + ByteArrayUtil.printable(coded) + "'"); //System.out.println(inst.context.preStr + " - " + " -> result '" + ByteArrayUtil.printable(coded) + "'");