Skip to content

Commit

Permalink
feat!: Improve file attribute caching (#854)
Browse files Browse the repository at this point in the history
Add logging.
  • Loading branch information
steve-todorov committed Nov 7, 2024
1 parent bbcf747 commit 7cc3d79
Showing 1 changed file with 25 additions and 6 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -2,12 +2,15 @@

import com.github.benmanes.caffeine.cache.Cache;
import com.github.benmanes.caffeine.cache.Caffeine;
import com.github.benmanes.caffeine.cache.RemovalCause;
import com.github.benmanes.caffeine.cache.stats.CacheStats;
import org.carlspring.cloud.storage.s3fs.S3ObjectId;
import org.carlspring.cloud.storage.s3fs.S3Path;
import org.carlspring.cloud.storage.s3fs.attribute.S3BasicFileAttributes;
import org.carlspring.cloud.storage.s3fs.attribute.S3PosixFileAttributes;
import org.carlspring.cloud.storage.s3fs.util.S3Utils;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

import java.nio.file.NoSuchFileException;
import java.nio.file.attribute.BasicFileAttributes;
Expand All @@ -20,6 +23,8 @@
public class S3FileAttributesCache
{

private static final Logger logger = LoggerFactory.getLogger(S3FileAttributesCache.class);

private final S3Utils s3Utils = new S3Utils();

// This should be volatile, despite what IntelliJ / Sonar says.
Expand Down Expand Up @@ -91,14 +96,18 @@ public static String generateCacheKey(S3ObjectId s3ObjectId, Class<? extends Bas
public S3BasicFileAttributes get(final S3Path path, final Class<? extends BasicFileAttributes> attrType)
{
String key = generateCacheKey(path, attrType);
logger.trace("Get cache for key {}", key);

Optional<S3BasicFileAttributes> attrs = cache.getIfPresent(key);

// Don't get confused - Caffeine returns `null` if the key does not exist.
if(attrs == null)
{
logger.trace("No cache found for key {}", key);
// We need a way to preserve non-existing files/paths.
// This is necessary, because the Files.exist() method is called multiple times from different threads
// during checks. As a result multiple requests for the same path are executed within milliseconds.
logger.trace("Fetch data for key {}", key);
attrs = Optional.ofNullable(fetchAttribute(path, key));
put(path, attrs);
}
Expand Down Expand Up @@ -138,11 +147,13 @@ public void put(final S3Path path, final Optional<S3BasicFileAttributes> attrs)
// To ensure this does not happen we always need to replace the BasicFileAttributes instances when
// the PosixFileAttributes type is cached/updated.
String basicKey = generateCacheKey(path, BasicFileAttributes.class);
logger.trace("Save response for key {}", basicKey);
cache.put(basicKey, attrs);

if(attrs.isPresent() && attrs.get() instanceof PosixFileAttributes)
{
String posixKey = generateCacheKey(path, PosixFileAttributes.class);
logger.trace("Save response for key {}", posixKey);
cache.put(posixKey, attrs);
}
}
Expand All @@ -155,6 +166,7 @@ public void put(final S3Path path, final Optional<S3BasicFileAttributes> attrs)
public void invalidate(final S3Path path, final Class<? extends BasicFileAttributes> attrType)
{
String key = generateCacheKey(path, attrType);
logger.trace("Invalidate cache key {}", key);
cache.invalidate(key);
}

Expand Down Expand Up @@ -211,6 +223,7 @@ public void invalidate(final S3ObjectId objectId)
{
try
{
logger.trace("Invalidate cache key {}", key);
cache.invalidate(key);
}
catch (NullPointerException e)
Expand All @@ -224,6 +237,7 @@ public void invalidate(final S3ObjectId objectId)

public void invalidateAll()
{
logger.trace("Invalidate all cache");
cache.invalidateAll();
}

Expand All @@ -234,12 +248,17 @@ public CacheStats stats()

protected Caffeine<String, Optional<S3BasicFileAttributes>> cacheBuilder(int cacheTTL, int cacheSize)
{
return Caffeine.newBuilder()
.expireAfter(new S3FileAttributesCachePolicy(cacheTTL))
.maximumSize(cacheSize)
.softValues()
.recordStats()
;
Caffeine<String, Optional<S3BasicFileAttributes>> builder = Caffeine.newBuilder()
.expireAfter(new S3FileAttributesCachePolicy(cacheTTL));

builder.maximumSize(cacheSize);
builder.recordStats();
builder.evictionListener((String key, Optional<S3BasicFileAttributes> value, RemovalCause cause) ->
logger.trace("Key {} was evicted (reason: {})", key, cause));
builder.removalListener((String key, Optional<S3BasicFileAttributes> value, RemovalCause cause) ->
logger.trace("Key {} was removed (reason: {})", key, cause));

return builder;
}

protected S3BasicFileAttributes fetchAttribute(S3Path path, String key)
Expand Down

0 comments on commit 7cc3d79

Please sign in to comment.