use of io.pravega.client.tables.TableKey in project pravega by pravega.
the class KeyValueTableTestBase method testSingleKeyUnconditionalRemovals.
/**
* Tests the ability to perform single-key updates and removals (conditional and unconditional). These methods are exercised:
* - {@link KeyValueTable#update} with {@link Put} instances and with {@link Remove} instances.
* - {@link KeyValueTable#get} and {@link KeyValueTable#getAll}
*/
@Test
public void testSingleKeyUnconditionalRemovals() {
val versions = new Versions();
@Cleanup val kvt = createKeyValueTable();
// Put (unconditional update).
val iteration = new AtomicInteger(0);
forEveryKey((pk, sk) -> {
val value = getValue(pk, sk, iteration.get());
Version kv = kvt.update(new Put(new TableKey(pk, sk), value)).join();
versions.add(getUniqueKeyId(pk, sk), kv);
});
// Remove (both conditional and unconditional)
iteration.incrementAndGet();
forEveryKey((pk, sk) -> {
val keyId = getUniqueKeyId(pk, sk);
val existingVersion = versions.get(keyId);
// Verify that conditions are checked both for segment names and their versions.
val pkValue = Math.abs(PK_SERIALIZER.deserialize(pk));
boolean conditional = pkValue % 2 == 0;
if (conditional) {
// First check that a bad version will be checked.
Version badVersion = alterVersion(existingVersion, pkValue % 4 == 0, pkValue % 4 != 0);
AssertExtensions.assertSuppliedFutureThrows("update(Remove) did not throw for bad version.", () -> kvt.update(new Remove(new TableKey(pk, sk), badVersion)), ex -> ex instanceof BadKeyVersionException);
// Remove it.
kvt.update(new Remove(new TableKey(pk, sk), existingVersion)).join();
} else {
kvt.update(new Remove(new TableKey(pk, sk))).join();
}
versions.remove(keyId);
});
Assert.assertTrue("Expected all keys to have been removed.", versions.isEmpty());
checkValues(iteration.get(), versions, kvt);
// Re-insert (conditionally).
iteration.incrementAndGet();
forEveryKey((pk, sk) -> {
val value = getValue(pk, sk, iteration.get());
// First one should work.
Version kv = kvt.update(new Insert(new TableKey(pk, sk), value)).join();
versions.add(getUniqueKeyId(pk, sk), kv);
});
checkValues(iteration.get(), versions, kvt);
}
use of io.pravega.client.tables.TableKey in project pravega by pravega.
the class KeyValueTableIteratorImplTests method testPeekingIterator.
/**
* Tests the {@link KeyValueTableIteratorImpl.PeekingIterator} class.
*/
@Test
public void testPeekingIterator() {
val items = Arrays.asList(IntStream.range(0, 10).boxed().collect(Collectors.toList()), IntStream.range(10, 11).boxed().collect(Collectors.toList()), IntStream.range(11, 20).boxed().collect(Collectors.toList()));
val sourceIterator = createAsyncIterator(items);
Function<Integer, TableKey> toKey = i -> new TableKey(ByteBuffer.allocate(Integer.BYTES).putInt(0, i));
// Collect items via the flattened iterator.
val fi = new KeyValueTableIteratorImpl.PeekingIterator<>(sourceIterator, toKey);
val actualItems = new ArrayList<Integer>();
fi.advance().join();
while (fi.hasNext()) {
actualItems.add(fi.getCurrent().getItem());
val expectedKey = toKey.apply(fi.getCurrent().getItem());
Assert.assertEquals(expectedKey, fi.getCurrent().getKey());
fi.advance().join();
}
Assert.assertNull(fi.getCurrent());
// Compare against expected items (which we get by flattening the provided input ourselves).
val expectedItems = items.stream().flatMap(List::stream).collect(Collectors.toList());
AssertExtensions.assertListEquals("", expectedItems, actualItems, Integer::equals);
}
use of io.pravega.client.tables.TableKey in project pravega by pravega.
the class KeyValueTableTestBase method testLargeBatchUpdates.
/**
* Verifies that overflowing a single {@link TableSegment} limits are rejected. No batch updates, removals or retrievals
* may exceed the {@link TableSegment#MAXIMUM_BATCH_KEY_COUNT} or {@link TableSegment#MAXIMUM_BATCH_LENGTH} limits.
*/
@Test
public void testLargeBatchUpdates() {
val rnd = new Random(0);
@Cleanup val kvt = createKeyValueTable();
// Exceeding by batch count.
val keys = IntStream.range(0, TableSegment.MAXIMUM_BATCH_KEY_COUNT + 1).mapToObj(i -> new TableKey(ByteBuffer.allocate(getPrimaryKeyLength()).putLong(i), ByteBuffer.allocate(getSecondaryKeyLength()).putInt(i))).collect(Collectors.toList());
val getBatchCountExceeded = keys.stream().map(k -> new TableKey(k.getPrimaryKey().duplicate(), k.getSecondaryKey().duplicate())).collect(Collectors.toList());
AssertExtensions.assertSuppliedFutureThrows("Get batch exceeded max count.", () -> kvt.getAll(getBatchCountExceeded), ex -> ex instanceof IllegalArgumentException);
List<TableModification> putBatchCountExceeded = keys.stream().map(a -> new Put(new TableKey(a.getPrimaryKey().duplicate(), a.getSecondaryKey().duplicate()), a.getSecondaryKey().duplicate())).collect(Collectors.toList());
AssertExtensions.assertSuppliedFutureThrows("Update batch exceeded max count.", () -> kvt.update(putBatchCountExceeded), ex -> ex instanceof IllegalArgumentException);
List<TableModification> removeBatchCountExceeded = keys.stream().map(k -> new Remove(new TableKey(k.getPrimaryKey().duplicate(), k.getSecondaryKey().duplicate()))).collect(Collectors.toList());
AssertExtensions.assertSuppliedFutureThrows("Remove batch exceeded max count.", () -> kvt.update(removeBatchCountExceeded), ex -> ex instanceof IllegalArgumentException);
// Exceed by serialization size.
// It is impossible to exceed the serialization size for retrievals or removals (due to the max key constraint),
// so the only request we can verify is the update one.
val limitValue = new byte[KeyValueTable.MAXIMUM_VALUE_LENGTH];
rnd.nextBytes(limitValue);
val putBatchSizeExceeded = new ArrayList<TableModification>();
int estimatedSize = 0;
while (estimatedSize < TableSegment.MAXIMUM_BATCH_LENGTH) {
val pk = new byte[getPrimaryKeyLength()];
val sk = new byte[getSecondaryKeyLength()];
rnd.nextBytes(pk);
rnd.nextBytes(sk);
val e = new Put(new TableKey(ByteBuffer.wrap(pk), ByteBuffer.wrap(sk)), ByteBuffer.wrap(limitValue));
putBatchSizeExceeded.add(e);
estimatedSize += pk.length + sk.length + limitValue.length;
}
AssertExtensions.assertSuppliedFutureThrows("Put batch exceeded max size.", () -> kvt.update(putBatchSizeExceeded), ex -> ex instanceof IllegalArgumentException);
}
use of io.pravega.client.tables.TableKey in project pravega by pravega.
the class KeyValueTableTestBase method testIllegalEntrySizes.
/**
* Verifies that {@link TableEntry} or {@link TableKey} instances that have invalid key/value lengths are rejected.
*/
@Test
public void testIllegalEntrySizes() {
val rnd = new Random(0);
val limitPK = ByteBuffer.wrap(new byte[getPrimaryKeyLength()]);
val shortPK = ByteBuffer.allocate(getPrimaryKeyLength() - 1);
val longPK = ByteBuffer.allocate(getPrimaryKeyLength() + 1);
val limitSK = ByteBuffer.wrap(new byte[getSecondaryKeyLength()]);
val longSK = ByteBuffer.allocate(getSecondaryKeyLength() + 1);
val limitValue = ByteBuffer.wrap(new byte[KeyValueTable.MAXIMUM_VALUE_LENGTH]);
rnd.nextBytes(limitPK.array());
rnd.nextBytes(limitSK.array());
rnd.nextBytes(limitValue.array());
@Cleanup val kvt = createKeyValueTable();
kvt.update(new Insert(new TableKey(limitPK.duplicate(), limitSK.duplicate()), limitValue.duplicate())).join();
val resultValue = kvt.get(new TableKey(limitPK.duplicate(), limitSK.duplicate())).join().getValue();
Assert.assertEquals("Unexpected value returned.", limitValue.duplicate(), resultValue.duplicate());
// Wrong Key Length
AssertExtensions.assertSuppliedFutureThrows("Expected a rejection of a PK that is too long.", () -> kvt.update(new Put(new TableKey(longPK.duplicate(), limitSK.duplicate()), limitValue.duplicate())), ex -> ex instanceof IllegalArgumentException);
AssertExtensions.assertSuppliedFutureThrows("Expected a rejection of a PK that is too long.", () -> kvt.update(new Remove(new TableKey(longPK.duplicate(), limitSK.duplicate()))), ex -> ex instanceof IllegalArgumentException);
AssertExtensions.assertSuppliedFutureThrows("Expected a rejection of a PK that is too short.", () -> kvt.update(new Put(new TableKey(shortPK.duplicate(), limitSK.duplicate()), limitValue.duplicate())), ex -> ex instanceof IllegalArgumentException);
AssertExtensions.assertSuppliedFutureThrows("Expected a rejection of a PK that is too short.", () -> kvt.update(new Remove(new TableKey(shortPK.duplicate(), limitSK.duplicate()))), ex -> ex instanceof IllegalArgumentException);
AssertExtensions.assertSuppliedFutureThrows("Expected a rejection of a SK that is too long.", () -> kvt.update(new Put(new TableKey(limitPK.duplicate(), longSK.duplicate()), limitValue.duplicate())), ex -> ex instanceof IllegalArgumentException);
AssertExtensions.assertSuppliedFutureThrows("Expected a rejection of a SK that is too long.", () -> kvt.update(new Remove(new TableKey(limitPK.duplicate(), longSK.duplicate()))), ex -> ex instanceof IllegalArgumentException);
if (getSecondaryKeyLength() > 0) {
val shortSK = ByteBuffer.allocate(getSecondaryKeyLength() - 1);
AssertExtensions.assertSuppliedFutureThrows("Expected a rejection of a SK that is too short.", () -> kvt.update(new Put(new TableKey(limitPK.duplicate(), shortSK.duplicate()), limitValue.duplicate())), ex -> ex instanceof IllegalArgumentException);
AssertExtensions.assertSuppliedFutureThrows("Expected a rejection of a SK that is too short.", () -> kvt.update(new Remove(new TableKey(limitPK.duplicate(), shortSK.duplicate()))), ex -> ex instanceof IllegalArgumentException);
}
// Max Value Length exceeded.
AssertExtensions.assertSuppliedFutureThrows("Expected a rejection of a value that is too long.", () -> kvt.update(new Put(new TableKey(limitPK.duplicate(), limitSK.duplicate()), ByteBuffer.allocate(KeyValueTable.MAXIMUM_VALUE_LENGTH + 1))), ex -> ex instanceof IllegalArgumentException);
}
use of io.pravega.client.tables.TableKey in project pravega by pravega.
the class KeyValueTableTestBase method testMultiKeyOperations.
/**
* Tests the ability to perform multi-key updates, replacements and removals. These methods should be exercised:
* - {@link KeyValueTable#update(Iterable)} with {@link Insert} and {@link Put} instances.
* - {@link KeyValueTable#update(Iterable)} with {@link Remove}.
* - {@link KeyValueTable#getAll}
*/
@Test
public void testMultiKeyOperations() {
val versions = new Versions();
@Cleanup val kvt = createKeyValueTable();
// Conditional Insert.
val iteration = new AtomicInteger(0);
forEveryPrimaryKey((pk, secondaryKeys) -> {
List<TableModification> inserts = secondaryKeys.stream().map(sk -> new Insert(new TableKey(pk, sk), getValue(pk, sk, iteration.get()))).collect(Collectors.toList());
val keyVersions = kvt.update(inserts).join();
val hint = getUniqueKeyId(pk);
Assert.assertEquals("Unexpected result size" + hint, inserts.size(), keyVersions.size());
for (int i = 0; i < inserts.size(); i++) {
versions.add(getUniqueKeyId(pk, inserts.get(i).getKey().getSecondaryKey()), keyVersions.get(i));
}
});
checkValues(iteration.get(), versions, kvt);
// Unconditional update.
iteration.incrementAndGet();
forEveryPrimaryKey((pk, secondaryKeys) -> {
List<TableModification> puts = secondaryKeys.stream().map(sk -> new Put(new TableKey(pk, sk), getValue(pk, sk, iteration.get()))).collect(Collectors.toList());
val keyVersions = kvt.update(puts).join();
val hint = getUniqueKeyId(pk);
Assert.assertEquals("Unexpected result size" + hint, puts.size(), keyVersions.size());
for (int i = 0; i < puts.size(); i++) {
versions.add(getUniqueKeyId(pk, puts.get(i).getKey().getSecondaryKey()), keyVersions.get(i));
}
});
checkValues(iteration.get(), versions, kvt);
// Conditional replace.
iteration.incrementAndGet();
forEveryPrimaryKey((pk, secondaryKeys) -> {
// Failed update (bad version).
val pkValue = Math.abs(PK_SERIALIZER.deserialize(pk));
List<TableModification> badPuts = secondaryKeys.stream().map(sk -> new Put(new TableKey(pk, sk), getValue(pk, sk, iteration.get()), alterVersion(versions.get(getUniqueKeyId(pk, sk)), pkValue % 2 == 0, pkValue % 2 == 1))).collect(Collectors.toList());
AssertExtensions.assertSuppliedFutureThrows("update(Put) did not throw for bad version.", () -> kvt.update(badPuts), ex -> ex instanceof BadKeyVersionException);
// Correct update.
List<TableModification> puts = secondaryKeys.stream().map(sk -> new Put(new TableKey(pk, sk), getValue(pk, sk, iteration.get()), versions.get(getUniqueKeyId(pk, sk)))).collect(Collectors.toList());
val keyVersions = kvt.update(puts).join();
val hint = getUniqueKeyId(pk);
Assert.assertEquals("Unexpected result size" + hint, puts.size(), keyVersions.size());
for (int i = 0; i < puts.size(); i++) {
versions.add(getUniqueKeyId(pk, puts.get(i).getKey().getSecondaryKey()), keyVersions.get(i));
}
});
checkValues(iteration.get(), versions, kvt);
// Conditional removal.
iteration.incrementAndGet();
forEveryPrimaryKey((pk, secondaryKeys) -> {
val hint = getUniqueKeyId(pk);
// Failed update (bad version).
val pkValue = Math.abs(PK_SERIALIZER.deserialize(pk));
List<TableModification> badRemovals = secondaryKeys.stream().map(sk -> new Remove(new TableKey(pk, sk), alterVersion(versions.get(getUniqueKeyId(pk, sk)), pkValue % 2 == 0, pkValue % 2 == 1))).collect(Collectors.toList());
AssertExtensions.assertSuppliedFutureThrows("update(Remove) did not throw for bad version." + hint, () -> kvt.update(badRemovals), ex -> ex instanceof BadKeyVersionException);
// Correct update.
List<TableModification> removals = secondaryKeys.stream().map(sk -> new Remove(new TableKey(pk, sk), versions.get(getUniqueKeyId(pk, sk)))).collect(Collectors.toList());
kvt.update(removals).join();
for (val sk : secondaryKeys) {
versions.remove(getUniqueKeyId(pk, sk));
}
});
Assert.assertTrue("Expected all keys to have been removed.", versions.isEmpty());
checkValues(iteration.get(), versions, kvt);
// Reinsert (conditionally)
iteration.incrementAndGet();
forEveryPrimaryKey((pk, secondaryKeys) -> {
val hint = getUniqueKeyId(pk);
List<TableModification> entries = secondaryKeys.stream().map(sk -> new Insert(new TableKey(pk, sk), getValue(pk, sk, iteration.get()))).collect(Collectors.toList());
val keyVersions = kvt.update(entries).join();
Assert.assertEquals("Unexpected result size" + hint, entries.size(), keyVersions.size());
for (int i = 0; i < entries.size(); i++) {
versions.add(getUniqueKeyId(pk, entries.get(i).getKey().getSecondaryKey()), keyVersions.get(i));
}
});
checkValues(iteration.get(), versions, kvt);
}
Aggregations