diff --git a/src/main/java/org/commonjava/service/storage/config/StorageServiceConfig.java b/src/main/java/org/commonjava/service/storage/config/StorageServiceConfig.java index 6e17dd5..8dbccb2 100644 --- a/src/main/java/org/commonjava/service/storage/config/StorageServiceConfig.java +++ b/src/main/java/org/commonjava/service/storage/config/StorageServiceConfig.java @@ -64,4 +64,8 @@ public interface StorageServiceConfig @WithName( "bucket.name" ) @WithDefault( "test" ) String bucketName(); + + @WithName( "filesystemsCacheTtlSeconds" ) + @WithDefault( "600" ) + int filesystemsCacheTtlSeconds(); } diff --git a/src/main/java/org/commonjava/service/storage/controller/StorageController.java b/src/main/java/org/commonjava/service/storage/controller/StorageController.java index 8291c6d..5cb2a00 100644 --- a/src/main/java/org/commonjava/service/storage/controller/StorageController.java +++ b/src/main/java/org/commonjava/service/storage/controller/StorageController.java @@ -18,6 +18,7 @@ import com.fasterxml.jackson.databind.ObjectMapper; import io.quarkus.runtime.Startup; import org.apache.commons.io.IOUtils; +import org.commonjava.service.storage.config.StorageServiceConfig; import org.commonjava.service.storage.dto.*; import org.commonjava.storage.pathmapped.core.PathMappedFileManager; import org.commonjava.storage.pathmapped.model.FileChecksum; @@ -61,10 +62,16 @@ public class StorageController @Inject PathMappedFileManager fileManager; + @Inject + StorageServiceConfig config; + private ObjectMapper objectMapper = new ObjectMapper(); private static final int DEFAULT_RECURSIVE_LIST_LIMIT = 5000; + // Cache for filesystems list + private volatile CachedFilesystems cachedFilesystems; + public InputStream openInputStream( String fileSystem, String path) throws IOException { return fileManager.openInputStream( fileSystem, path ); @@ -248,16 +255,36 @@ public BatchDeleteResult purgeFilesystem(String filesystem) { fileManager.purgeFilesystem( statistics ); } + invalidateFilesystemsCache(); return ret; } public Collection getFilesystems() { + CachedFilesystems cached = cachedFilesystems; + long now = System.currentTimeMillis(); + + // Check if cache is valid + if ( cached != null && ( now - cached.timestamp ) < TimeUnit.SECONDS.toMillis( config.filesystemsCacheTtlSeconds() ) ) + { + logger.debug( "Returning cached filesystems list (age: {}ms)", now - cached.timestamp ); + return cached.filesystems; + } + + // Cache miss or expired - fetch from database + logger.debug( "Cache miss or expired, fetching filesystems from database" ); Collection filesystems = fileManager.getFilesystems(); + Collection result; if ( filesystems != null ) { - return filesystems.stream().map(filesystem -> filesystem.getFilesystem()).sorted().collect(Collectors.toList()); + result = filesystems.stream().map(filesystem -> filesystem.getFilesystem()).sorted().collect(Collectors.toList()); + } else { + result = emptyList(); } - return emptyList(); + + // Update cache + cachedFilesystems = new CachedFilesystems( result, now ); + logger.debug( "Cached filesystems list (size: {})", result.size() ); + return result; } public Collection getEmptyFilesystems() @@ -271,6 +298,7 @@ public void purgeEmptyFilesystems() { Collection ret = getEmptyFilesystems(); ret.forEach( filesystem -> fileManager.purgeFilesystem( filesystem )); + invalidateFilesystemsCache(); } /** @@ -426,4 +454,28 @@ public FileCopyResult copy(FileCopyRequest request) return new FileCopyResult( true, completed, skipped ); } + + /** + * Invalidates the filesystems cache. Should be called whenever filesystems are added or removed. + */ + private void invalidateFilesystemsCache() + { + logger.debug( "Invalidating filesystems cache" ); + cachedFilesystems = null; + } + + /** + * Simple cache entry for filesystems list. + */ + private static class CachedFilesystems + { + final Collection filesystems; + final long timestamp; + + CachedFilesystems( Collection filesystems, long timestamp ) + { + this.filesystems = filesystems; + this.timestamp = timestamp; + } + } } diff --git a/src/main/resources/application.yaml b/src/main/resources/application.yaml index 35c340d..b878ec8 100644 --- a/src/main/resources/application.yaml +++ b/src/main/resources/application.yaml @@ -68,6 +68,7 @@ storage: readonly: false deduplicatePattern: "(generic-http|npm).+" removableFilesystemPattern: ".+:(remote|group):.+" + filesystemsCacheTtlSeconds: 600 #type: s3 #bucket: # name: test