expose second versionstamp value type through vexillographer and add support in bindings and bindingtester

This commit is contained in:
Alec Grieser 2018-03-02 16:58:51 -08:00
parent 2167012d83
commit 6ee14bbb93
No known key found for this signature in database
GPG Key ID: CAF63551C60D3462
12 changed files with 226 additions and 44 deletions

View File

@ -40,6 +40,7 @@ class ApiTest(Test):
self.stack_subspace = self.subspace['stack']
self.versionstamped_values = self.scratch['versionstamped_values']
self.versionstamped_values_2 = self.scratch['versionstamped_values_2']
self.versionstamped_keys = self.scratch['versionstamped_keys']
def setup(self, args):
@ -150,7 +151,7 @@ class ApiTest(Test):
snapshot_versions = ['GET_READ_VERSION_SNAPSHOT']
tuples = ['TUPLE_PACK', 'TUPLE_UNPACK', 'TUPLE_RANGE', 'TUPLE_SORT', 'SUB', 'ENCODE_FLOAT', 'ENCODE_DOUBLE', 'DECODE_DOUBLE', 'DECODE_FLOAT']
if 'versionstamp' in args.types:
tuples.append('TUPLE_PACK_WITH_VERSIONSTAMP')
tuples += ['TUPLE_PACK_VERSIONSTAMPED_KEY', 'TUPLE_PACK_VERSIONSTAMPED_VALUE']
resets = ['ON_ERROR', 'RESET', 'CANCEL']
read_conflicts = ['READ_CONFLICT_RANGE', 'READ_CONFLICT_KEY']
write_conflicts = ['WRITE_CONFLICT_RANGE', 'WRITE_CONFLICT_KEY', 'DISABLE_WRITE_CONFLICT']
@ -349,17 +350,27 @@ class ApiTest(Test):
elif op == 'VERSIONSTAMP':
rand_str1 = self.random.random_string(100)
key1 = self.versionstamped_values.pack((rand_str1,))
key2 = self.versionstamped_values_2.pack((rand_str1,))
split = random.randint(0, 70)
rand_str2 = self.random.random_string(20 + split) + fdb.tuple.Versionstamp._UNSET_TR_VERSION + self.random.random_string(70 - split)
key2 = self.versionstamped_keys.pack() + rand_str2
index = key2.find(fdb.tuple.Versionstamp._UNSET_TR_VERSION)
key2 += chr(index % 256) + chr(index / 256)
prefix = self.random.random_string(20 + split)
if prefix.endswith('\xff'):
# Necessary to make sure that the SET_VERSIONSTAMPED_VALUE check
# correctly finds where the version is supposed to fit in.
prefix += '\x00'
suffix = self.random.random_string(70 - split)
rand_str2 = prefix + fdb.tuple.Versionstamp._UNSET_TR_VERSION + suffix
key3 = self.versionstamped_keys.pack() + rand_str2
index = len(self.versionstamped_keys.pack()) + len(prefix)
key3 += chr(index % 256) + chr(index / 256)
instructions.push_args(u'SET_VERSIONSTAMPED_VALUE', key1, fdb.tuple.Versionstamp._UNSET_TR_VERSION + rand_str2)
instructions.append('ATOMIC_OP')
instructions.push_args(u'SET_VERSIONSTAMPED_KEY', key2, rand_str1)
instructions.push_args(u'SET_VERSIONSTAMPED_VALUE_POS', key2, rand_str2 + struct.pack('<L', len(prefix)))
instructions.append('ATOMIC_OP')
instructions.push_args(u'SET_VERSIONSTAMPED_KEY', key3, rand_str1)
instructions.append('ATOMIC_OP')
self.can_use_key_selectors = False
@ -428,25 +439,42 @@ class ApiTest(Test):
else:
self.add_strings(2)
elif op == 'TUPLE_PACK_WITH_VERSIONSTAMP':
elif op == 'TUPLE_PACK_VERSIONSTAMPED_KEY' or op == 'TUPLE_PACK_VERSIONSTAMPED_VALUE':
tup = (self.random.random_string(20),) + self.random.random_tuple(10, incomplete_versionstamps=True)
instructions.push_args(self.versionstamped_keys.pack(), len(tup), *tup)
prefix = self.versionstamped_keys.pack() if op == 'TUPLE_PACK_VERSIONSTAMPED_KEY' else ''
instructions.push_args(prefix, len(tup), *tup)
instructions.append(op)
self.add_strings(1)
version_key = self.versionstamped_keys.pack(tup)
first_incomplete = version_key.find(fdb.tuple.Versionstamp._UNSET_TR_VERSION)
versionstamp_param = prefix + fdb.tuple.pack(tup)
first_incomplete = versionstamp_param.find(fdb.tuple.Versionstamp._UNSET_TR_VERSION)
second_incomplete = -1 if first_incomplete < 0 else \
version_key.find(fdb.tuple.Versionstamp._UNSET_TR_VERSION, first_incomplete + len(fdb.tuple.Versionstamp._UNSET_TR_VERSION) + 1)
versionstamp_param.find(fdb.tuple.Versionstamp._UNSET_TR_VERSION, first_incomplete + len(fdb.tuple.Versionstamp._UNSET_TR_VERSION) + 1)
# If there is exactly one incomplete versionstamp, perform the versionstamped key operation.
# If there is exactly one incomplete versionstamp, perform the versionstamp operation.
if first_incomplete >= 0 and second_incomplete < 0:
rand_str = self.random.random_string(100)
instructions.push_args(rand_str)
test_util.to_front(instructions, 1)
instructions.push_args(u'SET_VERSIONSTAMPED_KEY')
instructions.append('ATOMIC_OP')
if op == 'TUPLE_PACK_VERSIONSTAMPED_KEY':
instructions.push_args(rand_str)
test_util.to_front(instructions, 1)
instructions.push_args(u'SET_VERSIONSTAMPED_KEY')
instructions.append('ATOMIC_OP')
version_value_key_2 = self.versionstamped_values_2.pack((rand_str,))
versionstamped_value = fdb.tuple.pack(tup) + struct.pack('<L', first_incomplete - len(prefix))
instructions.push_args(u'SET_VERSIONSTAMPED_VALUE_POS', version_value_key_2, versionstamped_value)
instructions.append('ATOMIC_OP')
else:
instructions.push_args(self.versionstamped_values_2.pack((rand_str,)))
instructions.push_args(u'SET_VERSIONSTAMPED_VALUE_POS')
instructions.append('ATOMIC_OP')
versionstamped_key = self.versionstamped_keys.pack() + versionstamp_param \
+ struct.pack('<H', first_incomplete + len(self.versionstamped_keys.pack()))
instructions.push_args(u'SET_VERSIONSTAMPED_KEY', versionstamped_key, rand_str)
instructions.append('ATOMIC_OP')
version_value_key = self.versionstamped_values.pack((rand_str,))
instructions.push_args(u'SET_VERSIONSTAMPED_VALUE', version_value_key,
@ -539,11 +567,19 @@ class ApiTest(Test):
incorrect_versionstamps = 0
for k, v in tr.get_range(begin_key, self.versionstamped_values.range().stop, limit=limit):
next_begin = k + '\x00'
tup = fdb.tuple.unpack(k)
key = self.versionstamped_keys.pack() + v[10:].replace(fdb.tuple.Versionstamp._UNSET_TR_VERSION, v[:10], 1)
if tr[key] != tup[-1]:
random_id = self.versionstamped_values.unpack(k)[0]
versioned_value = v[10:].replace(fdb.tuple.Versionstamp._UNSET_TR_VERSION, v[:10], 1)
versioned_key = self.versionstamped_keys.pack() + versioned_value
if tr[versioned_key] != random_id:
util.get_logger().error(' INCORRECT VERSIONSTAMP:')
util.get_logger().error(' %s != %s', repr(tr[key]), repr(tup[-1]))
util.get_logger().error(' %s != %s', repr(tr[versioned_key]), repr(random_id))
incorrect_versionstamps += 1
k2 = self.versionstamped_values_2.pack((random_id,))
if tr[k2] != versioned_value:
util.get_logger().error(' INCORRECT VERSIONSTAMP:')
util.get_logger().error(' %s != %s', repr(tr[k2]), repr(versioned_value))
incorrect_versionstamps += 1
return (next_begin, incorrect_versionstamps)

View File

@ -1676,6 +1676,7 @@ void populateAtomicOpMap() {
optionInfo["MIN"] = FDBMutationType::FDB_MUTATION_TYPE_MIN;
optionInfo["SET_VERSIONSTAMPED_KEY"] = FDBMutationType::FDB_MUTATION_TYPE_SET_VERSIONSTAMPED_KEY;
optionInfo["SET_VERSIONSTAMPED_VALUE"] = FDBMutationType::FDB_MUTATION_TYPE_SET_VERSIONSTAMPED_VALUE;
optionInfo["SET_VERSIONSTAMPED_VALUE_POS"] = FDBMutationType::FDB_MUTATION_TYPE_SET_VERSIONSTAMPED_VALUE_POS;
optionInfo["BYTE_MIN"] = FDBMutationType::FDB_MUTATION_TYPE_BYTE_MIN;
optionInfo["BYTE_MAX"] = FDBMutationType::FDB_MUTATION_TYPE_BYTE_MAX;
}

View File

@ -199,6 +199,23 @@ public class Subspace {
return tuple.pack(rawPrefix);
}
/**
* Deprecated. Use {@link #packVersionstampedKey(Tuple) packVersionstampedKey()} instead. Because
* the serialization formats are different for versionstamped keys and values, this method was
* deprecated to encourage developers to choose appropriately between
* {@link #packVersionstampedKey(Tuple) packVersionstampedKey()} and
* {@link #packVersionstampedValue(Tuple)} packVersionstampedValue()}.
*
* @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}
* @deprecated Since 5.2.0, replaced with {@link #packVersionstampedKey(Tuple) packVersionstampedKey()}
*/
@Deprecated
public byte[] packWithVersionstamp(Tuple tuple) {
return packVersionstampedKey(tuple);
}
/**
* Gets the key encoding the specified tuple in this {@code Subspace} for use with
* {@link com.apple.foundationdb.MutationType#SET_VERSIONSTAMPED_KEY MutationType.SET_VERSIONSTAMPED_KEY}.
@ -213,8 +230,22 @@ public class Subspace {
* @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);
public byte[] packVersionstampedKey(Tuple tuple) {
return tuple.packVersionstampedKey(rawPrefix);
}
/**
* Gets the key encoding the specified tuple in this {@code Subspace} for use with
* {@link com.apple.foundationdb.MutationType#SET_VERSIONSTAMPED_VALUE MutationType.SET_VERSIONSTAMPED_VALUE}.
* This works just like {@link #packVersionstampedKey(Tuple) packVersionstampedKey()} except that
* the final serialization format is different.
*
* @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[] packVersionstampedValue(Tuple tuple) {
return tuple.packVersionstampedValue(rawPrefix);
}
/**

View File

@ -302,17 +302,50 @@ public class Tuple implements Comparable<Tuple>, Iterable<Object> {
return TupleUtil.pack(elements, prefix);
}
/**
* Deprecated. Use {@link #packVersionstampedKey() packVersionstampedKey()} instead. Because
* versionstamped keys and versionstamped values are serialized differently, this method was deprecated
* to encourage developers to choose appropriately between
* {@link #packVersionstampedKey() packVersionstampedKey()} and
* {@link #packVersionstampedValue() packVersionstampedValue}.
*
* @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}
* @deprecated Since 5.2.0, replaced with {@link #packVersionstampedKey() packVersionstampedKey()}
*/
@Deprecated
public byte[] packWithVersionstamp() {
return packWithVersionstamp(null);
}
/**
* Deprecated. Use {@link #packVersionstampedKey(byte[]) packVersionstampedKey()} instead. Because
* versionstamped keys and versionstamped values are serialized differently, this method was deprecated
* to encourage developers to choose appropriately between
* {@link #packVersionstampedKey(byte[]) packVersionstampedKey()} and
* {@link #packVersionstampedValue(byte[]) packVersionstampedValue}.
*
* @param prefix additional byte-array prefix to prepend to serialized bytes.
* @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}
* @deprecated Since 5.2.0, replaced with {@link #packVersionstampedValue(byte[]) packVersionstampedKey()}
*/
@Deprecated
public byte[] packWithVersionstamp(byte[] prefix) {
return packVersionstampedKey(prefix);
}
/**
* Get an encoded representation of this {@code Tuple} for use with
* {@link com.apple.foundationdb.MutationType#SET_VERSIONSTAMPED_KEY MutationType.SET_VERSIONSTAMPED_KEY}.
* This works the same as the {@link #packWithVersionstamp(byte[]) one-paramter version of this method},
* This works the same as the {@link #packVersionstampedKey(byte[]) one-paramter version of this method},
* but it does not add any prefix to the array.
*
* @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() {
return packWithVersionstamp(null);
public byte[] packVersionstampedKey() {
return packVersionstampedKey(null);
}
/**
@ -332,8 +365,42 @@ public class Tuple implements Comparable<Tuple>, Iterable<Object> {
* @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) {
return TupleUtil.packWithVersionstamp(elements, prefix);
public byte[] packVersionstampedKey(byte[] prefix) {
return TupleUtil.packWithVersionstamp(elements, prefix, false);
}
/**
* Get an encoded representation of this {@code Tuple} for use with
* {@link com.apple.foundationdb.MutationType#SET_VERSIONSTAMPED_VALUE_POS MutationType.SET_VERSIONSTAMPED_VALUE_POS}.
* This works the same as the {@link #packVersionstampedValue(byte[]) one-paramter version of this method},
* but it does not add any prefix to the array.
*
* @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[] packVersionstampedValue() {
return packVersionstampedValue(null);
}
/**
* Get an encoded representation of this {@code Tuple} for use with
* {@link com.apple.foundationdb.MutationType#SET_VERSIONSTAMPED_VALUE_POS MutationType.SET_VERSIONSTAMPED_VALUE_POS}.
* There must be exactly one incomplete {@link Versionstamp} instance within this
* {@code Tuple} or this will throw an {@link IllegalArgumentException}.
* Each element is encoded to {@code byte}s and concatenated, the prefix
* 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
* as the value to
* {@link com.apple.foundationdb.Transaction#mutate(com.apple.foundationdb.MutationType, byte[], byte[]) Transaction.mutate()}
* with the {@code SET_VERSIONSTAMPED_VALUE_POS} {@link com.apple.foundationdb.MutationType}, and the transaction's
* version will then be filled in at commit time.
*
* @param prefix additional byte-array prefix to prepend to serialized bytes.
* @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[] packVersionstampedValue(byte[] prefix) {
return TupleUtil.packWithVersionstamp(elements, prefix, true);
}
/**

View File

@ -578,7 +578,7 @@ class TupleUtil {
}
}
static byte[] packWithVersionstamp(List<Object> items, byte[] prefix) {
static byte[] packWithVersionstamp(List<Object> items, byte[] prefix, boolean forValue) {
List<byte[]> encoded = new ArrayList<byte[]>(2 * items.size() + (prefix == null ? 1 : 2));
EncodeResult result = encodeAll(items, prefix, encoded);
if(result.versionPos < 0) {
@ -587,7 +587,11 @@ class TupleUtil {
if(result.versionPos > 0xffff) {
throw new IllegalArgumentException("Tuple has incomplete version at position " + result.versionPos + " which is greater than the maximum " + 0xffff);
}
encoded.add(ByteBuffer.allocate(2).order(ByteOrder.LITTLE_ENDIAN).putShort((short)result.versionPos).array());
if (forValue) {
encoded.add(ByteBuffer.allocate(4).order(ByteOrder.LITTLE_ENDIAN).putInt(result.versionPos).array());
} else {
encoded.add(ByteBuffer.allocate(2).order(ByteOrder.LITTLE_ENDIAN).putShort((short)result.versionPos).array());
}
return ByteArrayUtil.join(null, encoded);
}
}

View File

@ -360,7 +360,7 @@ public class AsyncStackTester {
}, FDB.DEFAULT_EXECUTOR);
}, FDB.DEFAULT_EXECUTOR);
}
else if(op == StackOperation.TUPLE_PACK_WITH_VERSIONSTAMP) {
else if(op == StackOperation.TUPLE_PACK_VERSIONSTAMPED_KEY || op == StackOperation.TUPLE_PACK_VERSIONSTAMPED_VALUE) {
return inst.popParams(2).thenComposeAsync(params -> {
byte[] prefix = (byte[])params.get(0);
int tupleSize = StackUtils.getInt(params.get(1));
@ -372,7 +372,12 @@ public class AsyncStackTester {
return;
}
try {
byte[] coded = tuple.packWithVersionstamp(prefix);
byte[] coded;
if(op == StackOperation.TUPLE_PACK_VERSIONSTAMPED_KEY) {
coded = tuple.packVersionstampedKey(prefix);
} else {
coded = tuple.packVersionstampedValue(prefix);
}
inst.push("OK".getBytes());
inst.push(coded);
} catch(IllegalArgumentException e) {

View File

@ -60,7 +60,8 @@ enum StackOperation {
SUB,
CONCAT,
TUPLE_PACK,
TUPLE_PACK_WITH_VERSIONSTAMP,
TUPLE_PACK_VERSIONSTAMPED_KEY,
TUPLE_PACK_VERSIONSTAMPED_VALUE,
TUPLE_UNPACK,
TUPLE_RANGE,
TUPLE_SORT,

View File

@ -321,7 +321,7 @@ public class StackTester {
//System.out.println(inst.context.preStr + " - " + " -> result '" + ByteArrayUtil.printable(coded) + "'");
inst.push(coded);
}
else if(op == StackOperation.TUPLE_PACK_WITH_VERSIONSTAMP) {
else if(op == StackOperation.TUPLE_PACK_VERSIONSTAMPED_KEY || op == StackOperation.TUPLE_PACK_VERSIONSTAMPED_VALUE) {
List<Object> params = inst.popParams(2).join();
byte[] prefix = (byte[])params.get(0);
int tupleSize = StackUtils.getInt(params.get(1));
@ -331,7 +331,12 @@ public class StackTester {
inst.push("ERROR: NONE".getBytes());
} else {
try {
byte[] coded = tuple.packWithVersionstamp(prefix);
byte[] coded;
if(op == StackOperation.TUPLE_PACK_VERSIONSTAMPED_KEY) {
coded = tuple.packVersionstampedKey(prefix);
} else {
coded = tuple.packVersionstampedValue(prefix);
}
inst.push("OK".getBytes());
inst.push(coded);
} catch (IllegalArgumentException e) {

View File

@ -42,7 +42,7 @@ public class VersionstampSmokeTest {
CompletableFuture<byte[]> trVersionFuture = db.run((Transaction tr) -> {
// The incomplete Versionstamp will have tr's version information when committed.
Tuple t = Tuple.from("prefix", Versionstamp.incomplete());
tr.mutate(MutationType.SET_VERSIONSTAMPED_KEY, t.packWithVersionstamp(), new byte[0]);
tr.mutate(MutationType.SET_VERSIONSTAMPED_KEY, t.packVersionstampedKey(), new byte[0]);
return tr.getVersionstamp();
});

View File

@ -374,7 +374,7 @@ def _encode(value, nested=False):
# * if there is exactly one incomplete versionstamp member, it returns the tuple with the
# two extra version bytes and the position of the version start
# * if there is more than one incomplete versionstamp member, it throws an error
def _pack_maybe_with_versionstamp(t, prefix=None):
def _pack_maybe_with_versionstamp(t, prefix=None, for_value=False):
if not isinstance(t, tuple):
raise Exception("fdbtuple pack() expects a tuple, got a " + str(type(t)))
@ -384,7 +384,10 @@ def _pack_maybe_with_versionstamp(t, prefix=None):
if version_pos >= 0:
version_pos += len(prefix) if prefix is not None else 0
bytes_list.extend(child_bytes)
bytes_list.append(struct.pack('<H', version_pos))
if for_value:
bytes_list.append(struct.pack('<L', version_pos))
else:
bytes_list.append(struct.pack('<H', version_pos))
else:
bytes_list.extend(child_bytes)
@ -399,14 +402,24 @@ def pack(t, prefix=None):
return res
# packs the specified tuple into a key for versionstamp operations
def pack_with_versionstamp(t, prefix=None):
res, version_pos = _pack_maybe_with_versionstamp(t, prefix)
# packs the specified tuple into a key or value for versionstamp operations
def pack_with_versionstamp(t, prefix=None, for_value=False):
res, version_pos = _pack_maybe_with_versionstamp(t, prefix=prefix, for_value=for_value)
if version_pos < 0:
raise ValueError("No incomplete versionstamp included in tuple pack with versionstamp")
return res
# packs the specified tuple into a key for versionstamp operations
def pack_versionstamped_key(t, prefix=None):
return pack_with_versionstamp(t, prefix, for_value=False)
# packs the specified tuple into a value for versionstamp operations
def pack_versionstamped_value(t, prefix=None):
return pack_with_versionstamp(t, prefix, for_value=True)
# unpacks the specified key into a tuple
def unpack(key, prefix_len=0):
pos = prefix_len

View File

@ -467,7 +467,7 @@ class Tester:
count = inst.pop()
items = inst.pop(count)
inst.push(fdb.tuple.pack(tuple(items)))
elif inst.op == six.u("TUPLE_PACK_WITH_VERSIONSTAMP"):
elif inst.op == six.u("TUPLE_PACK_VERSIONSTAMPED_KEY"):
prefix = inst.pop()
count = inst.pop()
items = inst.pop(count)
@ -475,7 +475,23 @@ class Tester:
inst.push(b"ERROR: NONE")
else:
try:
packed = fdb.tuple.pack_with_versionstamp(tuple(items), prefix=prefix)
packed = fdb.tuple.pack_versionstamped_key(tuple(items), prefix=prefix)
inst.push(b"OK")
inst.push(packed)
except ValueError as e:
if str(e).startswith("No incomplete"):
inst.push(b"ERROR: NONE")
else:
inst.push(b"ERROR: MULTIPLE")
elif inst.op == six.u("TUPLE_PACK_VERSIONSTAMPED_VALUE"):
prefix = inst.pop()
count = inst.pop()
items = inst.pop(count)
if not fdb.tuple.has_incomplete_versionstamp(items) and random.random() < 0.5:
inst.push(b"ERROR: NONE")
else:
try:
packed = fdb.tuple.pack_versionstamped_value(tuple(items), prefix=prefix)
inst.push(b"OK")
inst.push(packed)
except ValueError as e:

View File

@ -230,16 +230,19 @@ description is not currently required but encouraged.
description="Performs a little-endian comparison of byte strings. If the existing value in the database is not present, then ``param`` is stored in the database. If the existing value in the database is shorter than ``param``, it is first extended to the length of ``param`` with zero bytes. If ``param`` is shorter than the existing value in the database, the existing value is truncated to match the length of ``param``. The smaller of the two values is then stored in the database."/>
<Option name="set_versionstamped_key" code="14"
paramType="Bytes" paramDescription="value to which to set the transformed key"
description="Transforms ``key`` using a versionstamp for the transaction. Sets the transformed key in the database to ``param``. A versionstamp is a 10 byte, unique, monotonically (but not sequentially) increasing value for each committed transaction. The first 8 bytes are the committed version of the database. The last 2 bytes are monotonic in the serialization order for transactions. WARNING: At this time versionstamps are compatible with the Tuple layer only in the Java and Python bindings. Note that this implies versionstamped keys may not be used with the Subspace and Directory layers except in those languages." />
description="Transforms ``key`` using a versionstamp for the transaction. Sets the transformed key in the database to ``param``. The key is transformed by removing the final two bytes from the key and reading those as a little-Endian 16-bit integer to get a position ``pos``. The 10 bytes of the key from ``pos`` to ``pos + 10`` are replaced with the versionstamp of the transaction used. The first byte of the key is position 0, and note that this strips the final two bytes fromt the end of the key, in contrast to versionstamp value operations, which either replace the first 10 bytes or strip the last four bytes, depending on the variant used. A versionstamp is a 10 byte, unique, monotonically (but not sequentially) increasing value for each committed transaction. The first 8 bytes are the committed version of the database (serialized in big-Endian order). The last 2 bytes are monotonic in the serialization order for transactions. WARNING: At this time versionstamps are compatible with the Tuple layer only in the Java and Python bindings. They are also not currently compatible with the Subspace and Directory layer except in those languages and only in instances where they have already been set." />
<Option name="set_versionstamped_value" code="15"
paramType="Bytes" paramDescription="value to versionstamp and set"
description="Transforms ``param`` using a versionstamp for the transaction. Sets ``key`` in the database to the transformed parameter. A versionstamp is a 10 byte, unique, monotonically (but not sequentially) increasing value for each committed transaction. The first 8 bytes are the committed version of the database. The last 2 bytes are monotonic in the serialization order for transactions. WARNING: At this time versionstamped values are not compatible with the Tuple layer." />
description="Transforms ``param`` using a versionstamp for the transaction. Sets the ``key`` given to the transformed ``param``. The parameter is transformed by replacing the first 10 bytes of the value with the versionstamp of the transaction used. Note that this does not let the user insert a versionstamp at an arbitrary place in the value, in contrast to versionstamp key operations. This can be done using the other versionstamp value variant. A versionstamp is a 10 byte, unique, monotonically (but not sequentially) increasing value for each committed transaction. The first 8 bytes are the committed version of the database (serialized in big-Endian order). The last 2 bytes are monotonic in the serialization order for transactions. WARNING: At this time versionstamped values are not compatible with the Tuple layer." />
<Option name="byte_min" code="16"
paramType="Bytes" paramDescription="value to check against database value"
description="Performs lexicographic comparison of byte strings. If the existing value in the database is not present, then ``param`` is stored. Otherwise the smaller of the two values is then stored in the database."/>
<Option name="byte_max" code="17"
paramType="Bytes" paramDescription="value to check against database value"
description="Performs lexicographic comparison of byte strings. If the existing value in the database is not present, then ``param`` is stored. Otherwise the larger of the two values is then stored in the database."/>
<Option name="set_versionstamped_value_pos" code="20"
paramType="Bytes" paramDescription="value to versionstamp and set"
description="Transforms ``param`` using a versionstamp for the transaction. Sets the ``key`` given to the transformed ``param``. The parameter is transformed by removing the final four bytes from the key and reading those as a little-Endian 32-bit integer to get a position ``pos``. The 10 bytes of the parameter from ``pos`` to ``pos + 10`` are replaced with the versionstamp of the transaction used. The first byte of the parameter is position 0, and note that this strips the final four bytes from the end of parameter, in contrast to versionstamp key operations, which only strip the two bytes. A versionstamp is a 10 byte, unique, monotonically (but not sequentially) increasing value for each committed transaction. The first 8 bytes are the committed version of the database (serialized in big-Endian order). The last 2 bytes are monotonic in the serialization order for transactions. WARNING: At this time versionstamped values are compatible with the Tuple layer only in the Java and Python bindings." />
</Scope>
<Scope name="ConflictRangeType">