use of com.apple.foundationdb.record.provider.foundationdb.keyspace.ResolverCreateHooks.PreWriteCheck in project fdb-record-layer by FoundationDB.
the class ResolverCreateHooksTest method testPreWriteChecks.
@Test
void testPreWriteChecks() {
// reads the key, and chooses the resolver based on the value
final PreWriteCheck check = (context, providedResolver) -> {
CompletableFuture<LocatableResolver> expectedResolverFuture = root().add("should-use-A").toTupleAsync(context).thenCompose(keyTuple -> context.ensureActive().get(keyTuple.pack())).thenApply(value -> {
boolean useA = Tuple.fromBytes(value).getBoolean(0);
return new ScopedInterningLayer(database, resolverPath(context, useA ? "A" : "B"));
});
return expectedResolverFuture.thenApply(expectedResolver -> expectedResolver.equals(providedResolver));
};
final ResolverCreateHooks hooks = new ResolverCreateHooks(check, ResolverCreateHooks.DEFAULT_HOOK);
// use resolver A
database.run(context -> root().add("should-use-A").toTupleAsync(context).thenAccept(tuple -> context.ensureActive().set(tuple.pack(), Tuple.from(true).pack())));
try (FDBRecordContext context = database.openContext()) {
LocatableResolver resolverA = new ScopedInterningLayer(database, resolverPath(context, "A"));
LocatableResolver resolverB = new ScopedInterningLayer(database, resolverPath(context, "B"));
assertChecks(context, resolverA, hooks, true);
assertChecks(context, resolverB, hooks, false);
}
// use resolver B
database.run(context -> root().add("should-use-A").toTupleAsync(context).thenAccept(tuple -> context.ensureActive().set(tuple.pack(), Tuple.from(false).pack())));
// after migration
try (FDBRecordContext context = database.openContext()) {
LocatableResolver resolverA = new ScopedInterningLayer(database, resolverPath(context, "A"));
LocatableResolver resolverB = new ScopedInterningLayer(database, resolverPath(context, "B"));
assertChecks(context, resolverA, hooks, false);
assertChecks(context, resolverB, hooks, true);
}
}
use of com.apple.foundationdb.record.provider.foundationdb.keyspace.ResolverCreateHooks.PreWriteCheck in project fdb-record-layer by FoundationDB.
the class LocatableResolverTest method testWriteSafetyCheck.
@Test
public void testWriteSafetyCheck() {
KeySpace keySpace = new KeySpace(new KeySpaceDirectory("path1", KeyType.STRING, "path1"), new KeySpaceDirectory("path2", KeyType.STRING, "path2"));
final LocatableResolver path1Resolver;
final LocatableResolver path2Resolver;
try (FDBRecordContext context = database.openContext()) {
ResolvedKeySpacePath path1 = keySpace.path("path1").toResolvedPath(context);
ResolvedKeySpacePath path2 = keySpace.path("path2").toResolvedPath(context);
path1Resolver = resolverFactory.create(path1);
path2Resolver = resolverFactory.create(path2);
}
PreWriteCheck validCheck = (context, resolver) -> CompletableFuture.completedFuture(Objects.equals(path1Resolver, resolver));
PreWriteCheck invalidCheck = (context, resolver) -> CompletableFuture.completedFuture(Objects.equals(path2Resolver, resolver));
ResolverCreateHooks validHooks = new ResolverCreateHooks(validCheck, DEFAULT_HOOK);
ResolverCreateHooks invalidHooks = new ResolverCreateHooks(invalidCheck, DEFAULT_HOOK);
Long value = path1Resolver.resolve("some-key", validHooks).join();
try (FDBRecordContext context = database.openContext()) {
assertThat("it succeeds and writes the value", path1Resolver.mustResolve(context, "some-key").join(), is(value));
}
assertThat("when reading the same key it doesn't perform the check", path1Resolver.resolve("some-key", invalidHooks).join(), is(value));
try {
path1Resolver.resolve("another-key", invalidHooks).join();
fail("should throw CompletionException");
} catch (CompletionException ex) {
assertThat("it has the correct cause", ex.getCause(), is(instanceOf(LocatableResolverLockedException.class)));
assertThat(ex, hasMessageContaining("prewrite check failed"));
}
}
Aggregations