use of com.apple.foundationdb.Transaction in project fdb-record-layer by FoundationDB.
the class BunchedMapTest method insertTwoKeys.
@Test
public void insertTwoKeys() throws ExecutionException, InterruptedException {
final Tuple value = Tuple.from("hello", "there");
final List<Tuple> firstTuples = LongStream.range(100L, 110L).boxed().map(Tuple::from).collect(Collectors.toList());
final List<Tuple> secondTuples = LongStream.range(120L, 130L).boxed().map(Tuple::from).collect(Collectors.toList());
db.run(tr -> {
firstTuples.forEach(t -> map.put(tr, bmSubspace, t, value).join());
secondTuples.forEach(t -> map.put(tr, bmSubspace, t, value).join());
List<KeyValue> rangeKVs = tr.getRange(bmSubspace.range()).asList().join();
assertEquals(2, rangeKVs.size());
firstTuples.forEach(t -> assertTrue(map.containsKey(tr, bmSubspace, t).join(), t.toString() + " not in map"));
secondTuples.forEach(t -> assertTrue(map.containsKey(tr, bmSubspace, t).join(), t.toString() + " not in map"));
return null;
});
try (Transaction tr = db.createTransaction()) {
// Insert in the middle.
List<Tuple> middleTuples = Stream.of(115L, 118L, 119L, 114L).map(Tuple::from).collect(Collectors.toList());
Tuple minSoFar = null;
for (int i = 0; i < middleTuples.size(); i++) {
Tuple t = middleTuples.get(i);
map.put(tr, bmSubspace, t, value).join();
minSoFar = (minSoFar == null || t.compareTo(minSoFar) < 0) ? t : minSoFar;
for (int j = 0; j < middleTuples.size(); j++) {
assertEquals(j <= i, map.containsKey(tr, bmSubspace, middleTuples.get(j)).get());
}
List<KeyValue> rangeKVs = tr.getRange(bmSubspace.range()).asList().join();
assertEquals(3, rangeKVs.size());
List<Tuple> keys = rangeKVs.stream().map(KeyValue::getKey).map(bmSubspace::unpack).collect(Collectors.toList());
assertEquals(Arrays.asList(Tuple.from(100L), minSoFar, Tuple.from(120L)), keys);
}
tr.cancel();
}
try (Transaction tr = db.createTransaction()) {
// Remove a key from the end of first tuple collection.
assertTrue(map.remove(tr, bmSubspace, Tuple.from(109L)).get().isPresent());
assertFalse(map.remove(tr, bmSubspace, Tuple.from(109L)).get().isPresent());
map.put(tr, bmSubspace, Tuple.from(110L), value).get();
List<KeyValue> rangeKVs = tr.getRange(bmSubspace.range()).asList().get();
assertEquals(2, rangeKVs.size());
// Now insert in the middle to force it to split.
map.put(tr, bmSubspace, Tuple.from(109L), value).get();
rangeKVs = tr.getRange(bmSubspace.range()).asList().get();
assertEquals(3, rangeKVs.size());
List<Tuple> keys = rangeKVs.stream().map(KeyValue::getKey).map(bmSubspace::unpack).collect(Collectors.toList());
assertEquals(Arrays.asList(Tuple.from(100L), Tuple.from(105L), Tuple.from(120L)), keys);
tr.cancel();
}
}
use of com.apple.foundationdb.Transaction in project fdb-record-layer by FoundationDB.
the class BunchedMapTest method verifyBoundaryKeys.
private void verifyBoundaryKeys(@Nonnull List<Tuple> boundaryKeys) throws ExecutionException, InterruptedException {
try (Transaction tr = db.createTransaction()) {
map.verifyIntegrity(tr, bmSubspace).get();
List<KeyValue> rangeKVs = tr.getRange(bmSubspace.range()).asList().get();
List<Tuple> actualBoundaryKeys = rangeKVs.stream().map(KeyValue::getKey).map(bmSubspace::unpack).collect(Collectors.toList());
List<Map.Entry<Tuple, Tuple>> entryList = rangeKVs.stream().flatMap(kv -> serializer.deserializeEntries(bmSubspace.unpack(kv.getKey()), kv.getValue()).stream()).collect(Collectors.toList());
System.out.println(entryList);
assertEquals(boundaryKeys, actualBoundaryKeys);
tr.cancel();
}
}
use of com.apple.foundationdb.Transaction in project fdb-record-layer by FoundationDB.
the class RangeSetTest method concurrentWithInsert.
// Test out a few of the wild and wacky things that can happen when there are insertions going concurrently.
@Test
@Tag(Tags.Slow)
public void concurrentWithInsert() {
final List<byte[]> keys = createKeys();
final List<Range> ranges = new ArrayList<>();
// Two disjoint ranges -- both should succeed.
Transaction tr1 = db.createTransaction();
Transaction tr2 = db.createTransaction();
Range r1 = new Range(new byte[] { 0x01 }, new byte[] { 0x02 });
Range r2 = new Range(new byte[] { 0x02 }, new byte[] { 0x03 });
CompletableFuture<Boolean> future1 = rs.insertRange(tr1, r1);
CompletableFuture<Boolean> future2 = rs.insertRange(tr2, r2);
assertTrue(future1.join(), "Range 1 did not do insertion.");
assertTrue(future2.join(), "Range 2 did not do insertion.");
tr1.commit().join();
tr2.commit().join();
ranges.add(r1);
ranges.add(r2);
checkConsistent(ranges, keys);
checkIncreasing();
// Two non-disjoint ranges. The second should fail.
tr1 = db.createTransaction();
tr2 = db.createTransaction();
r1 = new Range(new byte[] { 0x03 }, new byte[] { 0x05 });
r2 = new Range(new byte[] { 0x04 }, new byte[] { 0x06 });
future1 = rs.insertRange(tr1, r1);
future2 = rs.insertRange(tr2, r2);
assertTrue(future1.join(), "Range 1 did not do insertion");
assertTrue(future2.join(), "Range 2 did not do insertion");
tr1.commit().join();
tr2.commit().handle((vignore, e) -> {
assertNotNull(e, "No error thrown from commit");
assertTrue(e instanceof FDBException, "Non-FDBException " + e.toString());
FDBException fdbe = (FDBException) e;
assertEquals(FDBError.NOT_COMMITTED.code(), fdbe.getCode(), "Did not get not-committed error.");
return vignore;
}).join();
ranges.add(r1);
checkConsistent(ranges, keys);
checkIncreasing();
// Read during write - the reads in the range should fail.
r1 = new Range(new byte[] { 0x07 }, new byte[] { 0x08 });
List<byte[]> specificKeys = Arrays.asList(new byte[] { 0x06, (byte) 0xff }, new byte[] { 0x07 }, new byte[] { 0x07, 0x00 }, new byte[] { 0x07, 0x10 }, new byte[] { 0x08 }, new byte[] { 0x08, 0x00 }, new byte[] { 0x08, 0x10 }, new byte[] { 0x09 });
tr1 = db.createTransaction();
List<Transaction> transactions = specificKeys.stream().map(ignore -> db.createTransaction()).collect(Collectors.toList());
// Add write conflict ranges to each key so that they are not read only.
transactions.forEach(tr -> tr.addWriteConflictKey(DEADC0DE));
future1 = rs.insertRange(tr1, r1);
List<CompletableFuture<Boolean>> futures = new ArrayList<>();
for (int i = 0; i < specificKeys.size(); i++) {
futures.add(rs.contains(transactions.get(i), specificKeys.get(i)));
}
assertTrue(future1.join(), "Range 1 did not do insertion");
futures.forEach(future -> assertFalse(future.join(), "Key should not be present"));
tr1.commit().join();
Range range = r1;
for (int i = 0; i < transactions.size(); i++) {
final int index = i;
transactions.get(i).commit().handle((vignore, e) -> {
byte[] key = specificKeys.get(index);
String repr = ByteArrayUtil.printable(key);
if (ByteArrayUtil.compareUnsigned(range.begin, key) <= 0 && ByteArrayUtil.compareUnsigned(key, range.end) < 0) {
assertNotNull(e, "No error from commit when key is " + repr);
assertTrue(e instanceof FDBException, "Non-FDBException " + e.toString() + " with key " + repr);
FDBException fdbe = (FDBException) e;
assertEquals(FDBError.NOT_COMMITTED.code(), fdbe.getCode(), "Did not get non-committed error when key is " + repr);
} else {
assertNull(e, "Error when key is " + repr);
}
return vignore;
}).join();
}
ranges.add(r1);
checkConsistent(ranges, keys);
checkIncreasing();
}
use of com.apple.foundationdb.Transaction in project fdb-record-layer by FoundationDB.
the class RankedSetTest method concurrentAdd.
@Test
public void concurrentAdd() throws Exception {
// 20 does go onto level 1, 30 and 40 do not. There should be no reason for them to conflict on level 0.
RankedSet rs = newRankedSet();
db.run(tr -> {
rs.add(tr, Tuple.from(20).pack()).join();
return null;
});
Transaction tr1 = db.createTransaction();
if (TRACE) {
tr1.options().setDebugTransactionIdentifier("tr1");
tr1.options().setLogTransaction();
}
Transaction tr2 = db.createTransaction();
if (TRACE) {
tr2.options().setDebugTransactionIdentifier("tr2");
tr2.options().setLogTransaction();
}
rs.add(tr1, Tuple.from(30).pack()).join();
rs.add(tr2, Tuple.from(40).pack()).join();
tr1.commit().join();
tr2.commit().join();
db.read(tr -> {
assertEquals(0L, rs.rank(tr, Tuple.from(20).pack()).join().longValue());
assertEquals(1L, rs.rank(tr, Tuple.from(30).pack()).join().longValue());
assertEquals(2L, rs.rank(tr, Tuple.from(40).pack()).join().longValue());
return null;
});
}
use of com.apple.foundationdb.Transaction in project fdb-record-layer by FoundationDB.
the class RankedSetTest method concurrentRemove.
@Test
public void concurrentRemove() throws Exception {
RankedSet rs = newRankedSet();
db.run(tr -> {
// Create a higher level entry.
rs.add(tr, Tuple.from(20).pack()).join();
return null;
});
Transaction tr1 = db.createTransaction();
if (TRACE) {
tr1.options().setDebugTransactionIdentifier("tr1");
tr1.options().setLogTransaction();
}
Transaction tr2 = db.createTransaction();
if (TRACE) {
tr2.options().setDebugTransactionIdentifier("tr2");
tr2.options().setLogTransaction();
}
// Will remove from all levels.
rs.remove(tr1, Tuple.from(20).pack()).join();
// Needs to increment the leftmost entry, not the one being removed.
rs.add(tr2, Tuple.from(30).pack()).join();
tr1.commit().join();
assertThrows(CompletionException.class, () -> tr2.commit().join());
db.run(tr -> {
rs.add(tr, Tuple.from(30).pack()).join();
return null;
});
db.read(tr -> {
// If the overlapping commit had succeeded, it would have incremented the 20 entry at level 1, so 20 would be returned here.
assertEquals(30, Tuple.fromBytes(rs.getNth(tr, 0).join()).getLong(0));
return null;
});
}
Aggregations