FDBReverseDirectoryCache { public CompletableFuture<Void> putIfNotExists(@Nonnull FDBRecordContext context, @Nonnull ScopedValue<String> scopedPathString, @Nonnull Long pathValue) { LocatableResolver scope = scopedPathString.getScope(); String pathString = scopedPathString.getData(); String cachedString = context.getDatabase().getReverseDirectoryInMemoryCache().getIfPresent(scope.wrap(pathValue)); if (cachedString != null) { if (!cachedString.equals(pathString)) { throw new RecordCoreException("Provided value for path key does not match value found in cache") .addLogInfo("provided_value", pathValue) .addLogInfo("provided_string", pathString) .addLogInfo("cached_string", cachedString); } if (LOGGER.isDebugEnabled()) { LOGGER.debug("In-memory cache contains '" + pathString + "' -> '" + pathValue + "' mapping. No need to put"); } return AsyncUtil.DONE; } return getReverseCacheSubspace(scope) .thenCompose(subspace -> putToSubspace(context, subspace, scopedPathString, pathValue)); } 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 testPutIfNotExists() throws Exception { final Random random = new Random(); final String name = "dir_" + Math.abs(random.nextInt()); final Long id; ScopedValue<String> scopedName = globalScope.wrap(name); FDBReverseDirectoryCache rdc = fdb.getReverseDirectoryCache(); try (FDBRecordContext context = openContext()) { Transaction tr = context.ensureActive(); id = Tuple.fromBytes(DirectoryLayer.getDefault().createOrOpen(tr, PathUtil.from(name)).get().pack()).getLong(0); commit(context); } try (FDBRecordContext context = openContext()) { rdc.putIfNotExists(context, scopedName, id).get(); rdc.putIfNotExists(context, scopedName, id).get(); rdc.putIfNotExists(context, scopedName, id).get(); rdc.putIfNotExists(context, scopedName, id).get(); assertEquals(3L, rdc.getPersistentCacheHitCount()); assertEquals(1L, rdc.getPersistentCacheMissCount()); assertEquals(3L, context.getTimer().getCount(FDBStoreTimer.Counts.REVERSE_DIR_PERSISTENT_CACHE_HIT_COUNT)); assertEquals(1L, context.getTimer().getCount(FDBStoreTimer.Counts.REVERSE_DIR_PERSISTENT_CACHE_MISS_COUNT)); commit(context); } rdc.clearStats(); try (FDBRecordContext context = openContext()) { rdc.putIfNotExists(context, scopedName, id).get(); assertEquals(1L, rdc.getPersistentCacheHitCount()); assertEquals(0L, rdc.getPersistentCacheMissCount()); assertEquals(1L, context.getTimer().getCount(FDBStoreTimer.Counts.REVERSE_DIR_PERSISTENT_CACHE_HIT_COUNT)); assertEquals(0L, context.getTimer().getCount(FDBStoreTimer.Counts.REVERSE_DIR_PERSISTENT_CACHE_MISS_COUNT)); commit(context); } }