use of com.apple.foundationdb.record.provider.foundationdb.FDBDatabase in project fdb-record-layer by FoundationDB.
the class LocatableResolverTest method testCachesWinnerOfConflict.
@Test
public void testCachesWinnerOfConflict() {
FDBDatabase fdb = FDBDatabaseFactory.instance().getDatabase();
fdb.clearCaches();
// In the scoped directory layer test, this can conflict with initializing the reverse directory layer
fdb.getReverseDirectoryCache().waitUntilReadyForTesting();
final String key = "hello " + UUID.randomUUID();
long resolved;
final FDBStoreTimer timer = new FDBStoreTimer();
try (FDBRecordContext context1 = fdb.openContext(null, timer);
FDBRecordContext context2 = fdb.openContext(null, timer)) {
// Ensure both started
context1.getReadVersion();
context2.getReadVersion();
// Both contexts try to create the key
CompletableFuture<Long> resolvedFuture1 = globalScope.resolve(context1, key);
CompletableFuture<Long> resolvedFuture2 = globalScope.resolve(context2, key);
long resolved1 = context1.asyncToSync(FDBStoreTimer.Waits.WAIT_DIRECTORY_RESOLVE, resolvedFuture1);
long resolved2 = context2.asyncToSync(FDBStoreTimer.Waits.WAIT_DIRECTORY_RESOLVE, resolvedFuture2);
assertAll(() -> assertThat("two concurrent resolutions of the same key should match", resolved1, equalTo(resolved2)), () -> assertThat("at least one transaction should read from database", timer.getCount(FDBStoreTimer.Events.DIRECTORY_READ), greaterThanOrEqualTo(1)), () -> assertThat("should not open more transactions than the two parents and five children", timer.getCount(FDBStoreTimer.Counts.OPEN_CONTEXT), lessThanOrEqualTo(7)), () -> assertThat("should not have committed more than the five children", timer.getCount(FDBStoreTimer.Events.COMMIT), lessThanOrEqualTo(5)));
resolved = resolved1;
}
timer.reset();
try (FDBRecordContext context = fdb.openContext(null, timer)) {
context.getReadVersion();
long resolvedAgain = context.asyncToSync(FDBStoreTimer.Waits.WAIT_DIRECTORY_RESOLVE, globalScope.resolve(context, key));
assertAll(() -> assertThat("resolved value in cache should match initial resolution", resolvedAgain, equalTo(resolved)), () -> assertThat("should have resolved from cache", timer.getCount(FDBStoreTimer.Events.DIRECTORY_READ), equalTo(0)));
}
}
use of com.apple.foundationdb.record.provider.foundationdb.FDBDatabase in project fdb-record-layer by FoundationDB.
the class LocatableResolverTest method testDoesNotCacheValueReadFromReadYourWritesCache.
/**
* This is mainly to test a counter factual where the same transaction is used to actually resolve the value as
* is used by the caller. In that case, one could accidentally pollute the cache with uncommitted data. To protect
* against that, this test is designed to fail if someone changes the resolution logic so that uncommitted data
* (even possibly uncommitted data re-read from the same transaction that wrote it) might be put in the cache.
*/
@Test
public void testDoesNotCacheValueReadFromReadYourWritesCache() {
FDBDatabase fdb = FDBDatabaseFactory.instance().getDatabase();
fdb.clearCaches();
final String key = "hello " + UUID.randomUUID();
final FDBStoreTimer timer = new FDBStoreTimer();
long resolved;
try (FDBRecordContext context = fdb.openContext(null, timer)) {
// First time: nothing in cache or DB. Entry is created.
resolved = context.asyncToSync(FDBStoreTimer.Waits.WAIT_DIRECTORY_RESOLVE, globalScope.resolve(context, key));
assertEquals(1, timer.getCount(FDBStoreTimer.Events.DIRECTORY_READ), "should have read from the database");
// Second time: if same context used to create and read, then this would read from transaction's read your writes cache, not the database
long resolvedAgain = context.asyncToSync(FDBStoreTimer.Waits.WAIT_DIRECTORY_RESOLVE, globalScope.resolve(context, key));
assertEquals(resolved, resolvedAgain, "resolving the same key should not change the value even in the same transaction");
// do not commit main transaction
}
// Read from cache. If present, this should not have changed its value
timer.reset();
boolean cached;
try (FDBRecordContext context = fdb.openContext(null, timer)) {
long resolvedFromCache = context.asyncToSync(FDBStoreTimer.Waits.WAIT_DIRECTORY_RESOLVE, globalScope.resolve(context, key));
cached = timer.getCount(FDBStoreTimer.Events.DIRECTORY_READ) == 0;
if (cached) {
assertEquals(resolved, resolvedFromCache, "resolved value should have changed when reading from cache");
}
}
// Clear caches, and re-read from the database.
if (cached) {
fdb.clearCaches();
timer.reset();
try (FDBRecordContext context = fdb.openContext(null, timer)) {
long resolvedFromDb = context.asyncToSync(FDBStoreTimer.Waits.WAIT_DIRECTORY_RESOLVE, globalScope.resolve(context, key));
assertEquals(resolved, resolvedFromDb, "resolved value from database should have matched initial resolution");
}
}
}
use of com.apple.foundationdb.record.provider.foundationdb.FDBDatabase in project fdb-record-layer by FoundationDB.
the class KeySpaceDirectoryTest method rootForMetadataTests.
private KeySpace rootForMetadataTests(String name, ResolverCreateHooks hooks, Function<FDBRecordContext, CompletableFuture<LocatableResolver>> generator) {
final FDBDatabase database = FDBDatabaseFactory.instance().getDatabase();
KeySpace root = new KeySpace(new DirectoryLayerDirectory(name, name).addSubdirectory(new DirectoryLayerDirectory("dir_with_metadata_name", DirWithMetadataWrapper::new, generator, hooks)));
database.run(context -> root.path(name).deleteAllDataAsync(context));
return root;
}
use of com.apple.foundationdb.record.provider.foundationdb.FDBDatabase in project fdb-record-layer by FoundationDB.
the class KeySpaceDirectoryTest method testDirectoryLayerDirectoryUsingLongs.
@Test
public void testDirectoryLayerDirectoryUsingLongs() throws Exception {
KeySpace root = new KeySpace(new DirectoryLayerDirectory("cabinet", "cabinet").addSubdirectory(new DirectoryLayerDirectory("game")));
final FDBDatabase database = FDBDatabaseFactory.instance().getDatabase();
final Tuple senetTuple;
final Tuple urTuple;
try (FDBRecordContext context = database.openContext()) {
senetTuple = root.path("cabinet").add("game", "senet").toTuple(context);
urTuple = root.path("cabinet").add("game", "royal_game_of_ur").toTuple(context);
context.commit();
}
try (FDBRecordContext context = database.openContext()) {
// Verify that I can create the tuple again using the directory layer values.
assertEquals(senetTuple, root.path("cabinet").add("game", senetTuple.getLong(1)).toTuple(context));
assertEquals(urTuple, root.path("cabinet").add("game", urTuple.getLong(1)).toTuple(context));
}
}
use of com.apple.foundationdb.record.provider.foundationdb.FDBDatabase in project fdb-record-layer by FoundationDB.
the class KeySpaceDirectoryTest method testListConstantValue.
@Test
public void testListConstantValue() throws Exception {
// Create a root directory called "a" with subdirs of every type and a constant value
Long rootValue = random.nextLong();
KeySpaceDirectory dirA = new KeySpaceDirectory("a", KeyType.LONG, rootValue);
for (KeyTypeValue kv : valueOfEveryType) {
dirA.addSubdirectory(new KeySpaceDirectory(kv.keyType.toString(), kv.keyType, kv.generator.get()));
}
KeySpace root = new KeySpace(dirA);
final FDBDatabase database = FDBDatabaseFactory.instance().getDatabase();
try (FDBRecordContext context = database.openContext()) {
Transaction tr = context.ensureActive();
for (KeyTypeValue kv : valueOfEveryType) {
KeySpaceDirectory dir = root.getDirectory("a").getSubdirectory(kv.keyType.name());
for (int i = 0; i < 5; i++) {
tr.set(Tuple.from(rootValue, dir.getValue(), i).pack(), Tuple.from(i).pack());
}
}
context.commit();
}
try (FDBRecordContext context = database.openContext()) {
for (KeyTypeValue kv : valueOfEveryType) {
KeySpaceDirectory dir = root.getDirectory("a").getSubdirectory(kv.keyType.name());
List<ResolvedKeySpacePath> paths = root.path("a").listSubdirectory(context, kv.keyType.toString());
assertEquals(1, paths.size());
if (dir.getKeyType() == KeyType.BYTES) {
assertTrue(Arrays.equals((byte[]) dir.getValue(), paths.get(0).toTuple().getBytes(1)));
} else {
assertEquals(dir.getValue(), paths.get(0).toTuple().get(1));
}
}
}
}
Aggregations