FDBReverseDirectoryCache { @Nonnull public CompletableFuture<Optional<String>> get(@Nonnull final ScopedValue<Long> scopedReverseDirectoryKey) { return get(null, scopedReverseDirectoryKey); } FDBReverseDirectoryCache(@Nonnull FDBDatabase fdb);  FDBReverseDirectoryCache(@Nonnull FDBDatabase fdb, int maxRowsPerTransaction, long maxMillisPerTransaction); int getMaxRowsPerTransaction(); void setMaxRowsPerTransaction(int maxRowsPerTransaction); long getMaxMillisPerTransaction(); void setMaxMillisPerTransaction(long maxMillisPerTransaction); long getPersistentCacheMissCount(); long getPersistentCacheHitCount(); void clearStats(); @Nonnull @SuppressWarnings("squid:S2095") // SonarQube doesn't realize that the context is closed in the returned future CompletableFuture<Optional<String>> getInReverseDirectoryCacheSubspace(@Nullable FDBStoreTimer timer, @Nonnull ScopedValue<Long> scopedReverseDirectoryKey); @Nonnull CompletableFuture<Optional<String>> get(@Nonnull final ScopedValue<Long> scopedReverseDirectoryKey); @Nonnull @SuppressWarnings("squid:S2095") // SonarQube doesn't realize that the context is closed in the returned future CompletableFuture<Optional<String>> get(@Nullable FDBStoreTimer timer, @Nonnull final ScopedValue<Long> scopedReverseDirectoryKey); CompletableFuture<Void> put(@Nonnull FDBRecordContext context, @Nonnull ScopedValue<String> pathKey); CompletableFuture<Void> putIfNotExists(@Nonnull FDBRecordContext context,
                                                  @Nonnull ScopedValue<String> scopedPathString,
                                                  @Nonnull Long pathValue); @VisibleForTesting void rebuild(LocatableResolver scope); @VisibleForTesting void waitUntilReadyForTesting(); static final String REVERSE_DIRECTORY_CACHE_ENTRY; static final int MAX_ROWS_PER_TRANSACTION; static final long MAX_MILLIS_PER_TRANSACTION; }
@Test public void testReverseDirectoryCacheMiss() throws Exception { FDBReverseDirectoryCache reverseDirectoryCache = fdb.getReverseDirectoryCache(); assertFalse(reverseDirectoryCache.get(createRandomDirectoryScope().wrap(1L)).join().isPresent(), "reverse lookup miss should return empty optional"); }
@Test public void testGetAvoidsConflict() throws Exception { final FDBReverseDirectoryCache rdc = fdb.getReverseDirectoryCache(); final int iterations = 20; final int parallelism = 2; final Executor executor = new ForkJoinPool(parallelism + 1); final Semaphore lock = new Semaphore(parallelism); for (int i = 0; i < iterations; i++) { final String name = "dir_" + Math.abs(new Random().nextInt()); final Long id; try (FDBRecordContext context = openContext()) { id = globalScope.resolve(context.getTimer(), name).get(); } final List<CompletableFuture<Void>> futures = IntStream.range(0, parallelism).mapToObj(k -> CompletableFuture.runAsync(() -> { try { lock.acquire(); rdc.get(globalScope.wrap(id)).get(); } catch (Exception e) { throw new AssertionError(e); } }, executor)).collect(Collectors.toList()); lock.release(parallelism); AsyncUtil.whenAll(futures).get(); } }