ResolverMappingReplicator implements AutoCloseable { public void copyTo(LocatableResolver replica) { runner.asyncToSync(FDBStoreTimer.Waits.WAIT_LOCATABLE_RESOLVER_MAPPING_COPY, copyToAsync(replica)); } ResolverMappingReplicator(@Nonnull LocatableResolver primary);  ResolverMappingReplicator(@Nonnull LocatableResolver primary,
                                     final int transactionRowLimit);  ResolverMappingReplicator(@Nonnull LocatableResolver primary,
                                     final int transactionRowLimit,
                                     final long transactionTimeLimitMillis); @Override void close(); void copyTo(LocatableResolver replica); CompletableFuture<Void> copyToAsync(@Nonnull final LocatableResolver replica); @Override String toString();  }
@Test public void testDirectoryLayerCopy() { Map<String, ResolverResult> dirLayerMappings; try (FDBRecordContext context = database.openContext()) { dirLayerMappings = seedDirectoryLayer(context, primary, 10); } ResolverMappingReplicator replicator = new ResolverMappingReplicator(primary); replicator.copyTo(replica); assertContainsMappings(replica, dirLayerMappings); }
@Test public void testCopyWithMultipleTransactions() { Map<String, ResolverResult> dirLayerMappings; try (FDBRecordContext context = database.openContext()) { dirLayerMappings = seedDirectoryLayer(context, primary, 100); } ResolverMappingReplicator replicator = new ResolverMappingReplicator(primary, 3); replicator.copyTo(replica); assertContainsMappings(replica, dirLayerMappings); }
@Test public void testCopiedDirectoryStartsAllocationBeyondOriginal() { Map<String, ResolverResult> dirLayerMappings; try (FDBRecordContext context = database.openContext()) { dirLayerMappings = seedDirectoryLayer(context, primary, 20); } final Long maxMappedValue = dirLayerMappings.entrySet().stream() .max(ResolverMappingReplicatorTest::resolverResultComparator) .map(max -> max.getValue().getValue()) .orElseThrow(IllegalStateException::new); ResolverMappingReplicator replicator = new ResolverMappingReplicator(primary); replicator.copyTo(replica); try (FDBRecordContext context = database.openContext()) { for (int i = 0; i < 20; i++) { String key = "new-value-" + random.nextLong(); Long mapped = replica.resolve(context.getTimer(), key).join(); assertThat("new mapped values are all greater than max from original directory layer", mapped, is(greaterThan(maxMappedValue))); } } }
@Test public void testPickupFromIncompleteCopy() { Map<String, ResolverResult> dirLayerMappings; try (FDBRecordContext context = database.openContext()) { dirLayerMappings = seedDirectoryLayer(context, primary, 34); } ResolverMappingReplicator incompleteReplicator = new ResolverMappingReplicator(primary, 10); incompleteReplicator.copyTo(replica); try (FDBRecordContext context = database.openContext()) { List<CompletableFuture<Boolean>> existsFutures = new ArrayList<>(); for (Map.Entry<String, ResolverResult> entry : dirLayerMappings.entrySet()) { existsFutures.add(replica.read(context, entry.getKey()).thenApply(Optional::isPresent)); } List<Boolean> results = AsyncUtil.getAll(existsFutures).join(); long presentValues = results.stream().filter(a -> a).count(); assertThat(presentValues, is(34L)); } Map<String, ResolverResult> newMappings; try (FDBRecordContext context = database.openContext()) { newMappings = seedDirectoryLayer(context, primary, 66); } Map<String, ResolverResult> totalMappings = ImmutableMap.<String, ResolverResult>builder() .putAll(dirLayerMappings) .putAll(newMappings) .build(); ResolverMappingReplicator completeReplicator = new ResolverMappingReplicator(primary, 10); completeReplicator.copyTo(replica); assertContainsMappings(replica, totalMappings); }
@Test public void testCopyEmptyIsValidDirectoryLayer() { ResolverMappingReplicator replicator = new ResolverMappingReplicator(primary); replicator.copyTo(replica); Map<String, ResolverResult> dirLayerMappings = new HashMap<>(); try (FDBRecordContext context = database.openContext()) { for (int i = 0; i < 5; i++) { String key = "entry-" + i; ResolverResult value = replica.resolveWithMetadata(context.getTimer(), key, ResolverCreateHooks.getDefault()).join(); dirLayerMappings.put(key, value); } context.commit(); } assertContainsMappings(replica, dirLayerMappings); }
@Test public void testDigestsMatch() { try (FDBRecordContext context = database.openContext()) { seedDirectoryLayer(context, primary, 50); } ResolverMappingReplicator replicator = new ResolverMappingReplicator(primary, 10); replicator.copyTo(replica); ResolverMappingDigest primaryDigest = new ResolverMappingDigest(primary); ResolverMappingDigest replicaDigest = new ResolverMappingDigest(replica); assertThat("digests match", primaryDigest.computeDigest().join(), is(replicaDigest.computeDigest().join())); }
@Test public void testCopyInSameDatabase() { ResolverMappingReplicator replicator = new ResolverMappingReplicator(primary, 10); FDBDatabase differentDB = new FDBDatabase(FDBDatabaseFactory.instance(), null); KeySpacePath path = keySpace.path("test-path").add("to").add("replica"); try (FDBRecordContext context = differentDB.openContext()) { LocatableResolver resolverInDifferentDB = new ScopedInterningLayer(differentDB, path.toResolvedPath(context)); replicator.copyTo(resolverInDifferentDB); fail("should throw IllegalArgumentException"); } catch (IllegalArgumentException ex) { assertThat(ex, hasMessageContaining("copy must be within same database")); } }