diff --git a/modules/cells/pom.xml b/modules/cells/pom.xml index c63b4a7b3a2..e4590e5b8bf 100644 --- a/modules/cells/pom.xml +++ b/modules/cells/pom.xml @@ -73,6 +73,10 @@ com.google.guava guava + + com.github.ben-manes.caffeine + caffeine + diff --git a/modules/cells/src/main/java/dmg/cells/services/CoreRoutingManager.java b/modules/cells/src/main/java/dmg/cells/services/CoreRoutingManager.java index 359b7d6990c..f065b00db46 100644 --- a/modules/cells/src/main/java/dmg/cells/services/CoreRoutingManager.java +++ b/modules/cells/src/main/java/dmg/cells/services/CoreRoutingManager.java @@ -23,9 +23,7 @@ import com.google.common.collect.HashMultimap; import com.google.common.collect.Iterables; -import com.google.common.collect.Lists; import com.google.common.collect.Multimap; -import com.google.common.collect.Sets; import com.google.common.util.concurrent.Futures; import com.google.common.util.concurrent.ListenableFuture; import com.google.common.util.concurrent.MoreExecutors; @@ -329,7 +327,7 @@ public void messageArrived(CellMessage msg) { .map(CellDomainInfo::getCellDomainName) .forEach(domain -> domains.put(domain, new ArrayList<>())); queueRoutes.asMap().forEach( - (domain, cells) -> domains.put(domain, Lists.newArrayList(cells))); + (domain, cells) -> domains.put(domain, new ArrayList<>(cells))); } msg.revertDirection(); msg.setMessageObject(new GetAllDomainsReply(domains)); @@ -504,9 +502,9 @@ private Optional getTunnelInfo(CellAddressCore tunnel) { public synchronized Object ac_ls_$_0(Args args) { return new Object[]{ getCellDomainName(), - Sets.newHashSet(localConsumers.values()), + new HashSet<>(localConsumers.values()), queueRoutes.asMap().entrySet().stream().collect( - toMap(Map.Entry::getKey, e -> Sets.newHashSet(e.getValue()))) + toMap(Map.Entry::getKey, e -> new HashSet<>(e.getValue()))) }; } } diff --git a/modules/cells/src/main/java/dmg/cells/zookeeper/CellCuratorFramework.java b/modules/cells/src/main/java/dmg/cells/zookeeper/CellCuratorFramework.java index 33ca9951ec4..2661f9b7212 100644 --- a/modules/cells/src/main/java/dmg/cells/zookeeper/CellCuratorFramework.java +++ b/modules/cells/src/main/java/dmg/cells/zookeeper/CellCuratorFramework.java @@ -17,9 +17,9 @@ */ package dmg.cells.zookeeper; -import com.google.common.cache.CacheBuilder; -import com.google.common.cache.CacheLoader; -import com.google.common.cache.LoadingCache; +import com.github.benmanes.caffeine.cache.CacheLoader; +import com.github.benmanes.caffeine.cache.Caffeine; +import com.github.benmanes.caffeine.cache.LoadingCache; import dmg.cells.nucleus.CDC; import java.util.Collection; import java.util.List; @@ -115,9 +115,9 @@ public class CellCuratorFramework implements CuratorFramework { private final BoundedExecutor executor; private final LoadingCache watchers = - CacheBuilder.newBuilder().build(new CacheLoader() { + Caffeine.newBuilder().build(new CacheLoader<>() { @Override - public Watcher load(Watcher watcher) throws Exception { + public Watcher load(Watcher watcher) { CDC cdc = new CDC(); return event -> executor.execute(() -> { try (CDC ignore = cdc.restore()) { @@ -128,9 +128,9 @@ public Watcher load(Watcher watcher) throws Exception { }); private final LoadingCache curatorWatchers = - CacheBuilder.newBuilder().build(new CacheLoader() { + Caffeine.newBuilder().build(new CacheLoader<>() { @Override - public CuratorWatcher load(CuratorWatcher watcher) throws Exception { + public CuratorWatcher load(CuratorWatcher watcher) { CDC cdc = new CDC(); return event -> executor.execute(() -> { try (CDC ignore = cdc.restore()) { @@ -175,11 +175,11 @@ protected static BackgroundCallback wrap(BackgroundCallback callback) { } protected Watcher wrap(Watcher watcher) { - return watchers.getUnchecked(watcher); + return watchers.get(watcher); } protected CuratorWatcher wrap(CuratorWatcher watcher) { - return curatorWatchers.getUnchecked(watcher); + return curatorWatchers.get(watcher); } @Override diff --git a/modules/cells/src/main/java/dmg/util/logback/FilterThresholdSet.java b/modules/cells/src/main/java/dmg/util/logback/FilterThresholdSet.java index 6a465780194..3996420de77 100644 --- a/modules/cells/src/main/java/dmg/util/logback/FilterThresholdSet.java +++ b/modules/cells/src/main/java/dmg/util/logback/FilterThresholdSet.java @@ -4,23 +4,24 @@ import static java.util.Objects.requireNonNull; import ch.qos.logback.classic.Level; +import com.github.benmanes.caffeine.cache.CacheLoader; +import com.github.benmanes.caffeine.cache.Caffeine; +import com.github.benmanes.caffeine.cache.LoadingCache; import com.google.common.base.Throwables; -import com.google.common.cache.CacheBuilder; -import com.google.common.cache.CacheLoader; -import com.google.common.cache.LoadingCache; import com.google.common.collect.HashBasedTable; -import com.google.common.collect.Lists; -import com.google.common.collect.Maps; -import com.google.common.collect.Sets; import com.google.common.collect.Table; +import java.io.Serializable; +import java.util.ArrayList; import java.util.Collection; import java.util.Collections; import java.util.Comparator; +import java.util.HashMap; import java.util.HashSet; import java.util.Map; import java.util.Optional; import java.util.Set; -import java.util.concurrent.ExecutionException; +import java.util.concurrent.CompletionException; +import java.util.function.Function; import org.slf4j.Logger; /** @@ -41,7 +42,7 @@ public class FilterThresholdSet { private final FilterThresholdSet _parent; - private final Set _appenders = Sets.newHashSet(); + private final Set _appenders = new HashSet<>(); private final Set _roots = new HashSet<>(); @@ -50,26 +51,25 @@ public class FilterThresholdSet { /* Logger -> (Appender -> Level) */ private final LoadingCache> _effectiveMaps = - CacheBuilder.newBuilder().build(CacheLoader.from( + Caffeine.newBuilder().build(new FunctionToCacheLoader<>( logger -> computeEffectiveMap(LoggerName.getInstance(logger)))); /* Logger -> Level */ private final LoadingCache> _effectiveLevels = - CacheBuilder.newBuilder().build(CacheLoader.from( + Caffeine.newBuilder().build(new FunctionToCacheLoader<>( logger -> { try { Map map = _effectiveMaps.get(logger.getName()); return map.isEmpty() ? Optional.empty() : Optional.of(Collections.min(map.values(), LEVEL_ORDER)); - } catch (ExecutionException e) { + } catch (CompletionException e) { Throwables.throwIfUnchecked(e.getCause()); throw new RuntimeException(e.getCause()); } })); - private static final Comparator LEVEL_ORDER = - (o1, o2) -> Integer.compare(o1.toInt(), o2.toInt()); + private static final Comparator LEVEL_ORDER = Comparator.comparingInt(Level::toInt); public FilterThresholdSet() { this(null); @@ -93,7 +93,7 @@ public synchronized void addAppender(String name) { */ public synchronized Collection getAppenders() { if (_parent == null) { - return Lists.newArrayList(_appenders); + return new ArrayList<>(_appenders); } else { Collection appenders = _parent.getAppenders(); appenders.addAll(_appenders); @@ -182,7 +182,7 @@ private void clearCache() { */ public synchronized Map getInheritedMap(LoggerName logger) { if (_parent == null) { - return Maps.newHashMap(_rules.row(logger)); + return new HashMap<>(_rules.row(logger)); } else { Map map = _parent.getInheritedMap(logger); map.putAll(_rules.row(logger)); @@ -222,7 +222,7 @@ public Level getThreshold(LoggerName logger, String appender) { public Level getThreshold(String logger, String appender) { try { return _effectiveMaps.get(logger).get(appender); - } catch (ExecutionException e) { + } catch (CompletionException e) { Throwables.throwIfUnchecked(e.getCause()); throw new RuntimeException(e.getCause()); } @@ -234,9 +234,24 @@ public Level getThreshold(String logger, String appender) { public Level getThreshold(Logger logger) { try { return _effectiveLevels.get(logger).orElse(null); - } catch (ExecutionException e) { + } catch (CompletionException e) { Throwables.throwIfUnchecked(e.getCause()); throw new RuntimeException(e.getCause()); } } + + private static final class FunctionToCacheLoader implements + CacheLoader, Serializable { + + private final Function computingFunction; + private static final long serialVersionUID = 0L; + + public FunctionToCacheLoader(Function computingFunction) { + this.computingFunction = requireNonNull(computingFunction); + } + + public V load(K key) { + return this.computingFunction.apply(requireNonNull(key)); + } + } } diff --git a/modules/chimera/pom.xml b/modules/chimera/pom.xml index 1610f5647ce..4947caa56f3 100644 --- a/modules/chimera/pom.xml +++ b/modules/chimera/pom.xml @@ -26,6 +26,10 @@ com.google.guava guava + + com.github.ben-manes.caffeine + caffeine + com.github.spotbugs spotbugs-annotations diff --git a/modules/chimera/src/main/java/org/dcache/chimera/JdbcFs.java b/modules/chimera/src/main/java/org/dcache/chimera/JdbcFs.java index f13bb19abe7..419ede71cd9 100644 --- a/modules/chimera/src/main/java/org/dcache/chimera/JdbcFs.java +++ b/modules/chimera/src/main/java/org/dcache/chimera/JdbcFs.java @@ -26,11 +26,11 @@ import static org.dcache.util.ByteUnit.EiB; import static org.dcache.util.SqlHelper.tryToClose; +import com.github.benmanes.caffeine.cache.AsyncLoadingCache; +import com.github.benmanes.caffeine.cache.Cache; +import com.github.benmanes.caffeine.cache.CacheLoader; +import com.github.benmanes.caffeine.cache.Caffeine; import com.google.common.base.Throwables; -import com.google.common.cache.Cache; -import com.google.common.cache.CacheBuilder; -import com.google.common.cache.CacheLoader; -import com.google.common.cache.LoadingCache; import com.google.common.io.ByteSource; import com.google.common.util.concurrent.ThreadFactoryBuilder; import diskCacheV111.util.RetentionPolicy; @@ -45,7 +45,8 @@ import java.util.List; import java.util.Map; import java.util.Set; -import java.util.concurrent.ExecutionException; +import java.util.concurrent.CompletableFuture; +import java.util.concurrent.CompletionException; import java.util.concurrent.Executor; import java.util.concurrent.Executors; import java.util.concurrent.ScheduledExecutorService; @@ -127,30 +128,23 @@ public class JdbcFs implements FileSystemProvider, LeaderLatchListener { .build() ); - private final LoadingCache _fsStatCache - = CacheBuilder.newBuilder() + private final AsyncLoadingCache _fsStatCache + = Caffeine.newBuilder() .refreshAfterWrite(100, TimeUnit.MILLISECONDS) - .build( - CacheLoader.asyncReloading(new CacheLoader() { - - @Override - public FsStat load(Object k) throws Exception { - return JdbcFs.this.getFsStat0(); - } - } - , _fsStatUpdateExecutor)); + .executor(_fsStatUpdateExecutor) + .buildAsync(key -> JdbcFs.this.getFsStat0()); /* The PNFS ID to inode number mapping will never change while dCache is running. */ protected final Cache _inoCache = - CacheBuilder.newBuilder() + Caffeine.newBuilder() .maximumSize(100000) .build(); /* The inode number to PNFS ID mapping will never change while dCache is running. */ protected final Cache _idCache = - CacheBuilder.newBuilder() + Caffeine.newBuilder() .maximumSize(100000) .build(); @@ -725,14 +719,14 @@ public FsInode path2inode(String path, FsInode startFrom) throws ChimeraFsExcept @Override public String inode2id(FsInode inode) throws ChimeraFsException { try { - return _idCache.get(inode.ino(), () -> { + return _idCache.get(inode.ino(), (key) -> { String id = _sqlDriver.getId(inode); if (id == null) { - throw FileNotFoundChimeraFsException.of(inode); + throw new CompletionException(FileNotFoundChimeraFsException.of(inode)); } return id; }); - } catch (ExecutionException e) { + } catch (CompletionException e) { Throwables.throwIfInstanceOf(e.getCause(), ChimeraFsException.class); Throwables.throwIfInstanceOf(e.getCause(), DataAccessException.class); Throwables.throwIfUnchecked(e.getCause()); @@ -744,14 +738,14 @@ public String inode2id(FsInode inode) throws ChimeraFsException { public FsInode id2inode(String id, StatCacheOption option) throws ChimeraFsException { if (option == NO_STAT) { try { - return new FsInode(this, _inoCache.get(id, () -> { + return new FsInode(this, _inoCache.get(id, (key) -> { Long ino = _sqlDriver.getInumber(id); if (ino == null) { - throw FileNotFoundChimeraFsException.ofPnfsId(id); + throw new CompletionException(FileNotFoundChimeraFsException.ofPnfsId(id)); } return ino; })); - } catch (ExecutionException e) { + } catch (CompletionException e) { Throwables.throwIfInstanceOf(e.getCause(), ChimeraFsException.class); Throwables.throwIfInstanceOf(e.getCause(), DataAccessException.class); Throwables.throwIfUnchecked(e.getCause()); @@ -1403,19 +1397,19 @@ private static void checkNameLength(String name) throws InvalidNameChimeraExcept } @Override - public void updateFsStat() throws ChimeraFsException { + public void updateFsStat() { _sqlDriver.updateFsStat(); } - public FsStat getFsStat0() throws ChimeraFsException { + public FsStat getFsStat0() { return _sqlDriver.getFsStat(); } @Override public FsStat getFsStat() throws ChimeraFsException { try { - return _fsStatCache.get(DUMMY_KEY); - } catch (ExecutionException e) { + return _fsStatCache.synchronous().get(DUMMY_KEY); + } catch (CompletionException e) { Throwable t = e.getCause(); Throwables.propagateIfPossible(t, ChimeraFsException.class); throw new ChimeraFsException(t.getMessage(), t); diff --git a/modules/common-security/src/main/java/org/dcache/gsi/KeyPairCache.java b/modules/common-security/src/main/java/org/dcache/gsi/KeyPairCache.java index 3e6bace4312..f1f78c50c25 100644 --- a/modules/common-security/src/main/java/org/dcache/gsi/KeyPairCache.java +++ b/modules/common-security/src/main/java/org/dcache/gsi/KeyPairCache.java @@ -17,17 +17,14 @@ */ package org.dcache.gsi; -import com.google.common.cache.CacheBuilder; -import com.google.common.cache.CacheLoader; -import com.google.common.cache.LoadingCache; -import com.google.common.util.concurrent.ListenableFuture; -import com.google.common.util.concurrent.ListenableFutureTask; +import com.github.benmanes.caffeine.cache.AsyncLoadingCache; +import com.github.benmanes.caffeine.cache.Caffeine; import com.google.common.util.concurrent.ThreadFactoryBuilder; import java.security.KeyPair; import java.security.KeyPairGenerator; import java.security.NoSuchAlgorithmException; import java.security.NoSuchProviderException; -import java.util.concurrent.ExecutionException; +import java.util.concurrent.CompletionException; import java.util.concurrent.Executor; import java.util.concurrent.Executors; import java.util.concurrent.TimeUnit; @@ -52,35 +49,18 @@ public class KeyPairCache { private static final Executor _executor = Executors.newCachedThreadPool( new ThreadFactoryBuilder().setNameFormat("KeyPair-generator-%d").setDaemon(true).build()); - private final LoadingCache _cache; + private final AsyncLoadingCache _cache; private String algorithm = DEFAULT_ALGORITHM; private String provider = DEFAULT_PROVIDER; public KeyPairCache(long lifetime, TimeUnit unit) { if (lifetime > 0) { - _cache = CacheBuilder.newBuilder() + _cache = Caffeine.newBuilder() .maximumSize(1000) .expireAfterWrite(EXPIRE_AFTER, TimeUnit.DAYS) .refreshAfterWrite(lifetime, unit) - .build( - new CacheLoader() { - @Override - public KeyPair load(Integer keySize) throws - NoSuchAlgorithmException, - NoSuchProviderException { - return generate(keySize); - } - - @Override - public ListenableFuture reload(final - Integer keySize, KeyPair previous) { - ListenableFutureTask task = - ListenableFutureTask.create(() -> generate(keySize)); - _executor.execute(task); - return task; - } - } - ); + .executor(_executor) + .buildAsync(this::generate); } else { _cache = null; } @@ -109,8 +89,8 @@ public KeyPair getKeyPair(int bits) return generate(bits); } else { try { - return _cache.get(bits); - } catch (ExecutionException e) { + return _cache.synchronous().get(bits); + } catch (CompletionException e) { // propagate throw new RuntimeException(); } diff --git a/modules/common/pom.xml b/modules/common/pom.xml index a4ee3230d51..b167c8cecad 100644 --- a/modules/common/pom.xml +++ b/modules/common/pom.xml @@ -22,6 +22,10 @@ com.google.guava guava + + com.github.ben-manes.caffeine + caffeine + org.apache.commons commons-math3 diff --git a/modules/common/src/main/java/org/dcache/util/CachingCertificateValidator.java b/modules/common/src/main/java/org/dcache/util/CachingCertificateValidator.java index d57d6c49056..3dab7288fb6 100644 --- a/modules/common/src/main/java/org/dcache/util/CachingCertificateValidator.java +++ b/modules/common/src/main/java/org/dcache/util/CachingCertificateValidator.java @@ -21,9 +21,9 @@ import static java.util.Collections.singletonList; import static java.util.Objects.requireNonNull; -import com.google.common.cache.Cache; -import com.google.common.cache.CacheBuilder; -import com.google.common.cache.CacheStats; +import com.github.benmanes.caffeine.cache.Cache; +import com.github.benmanes.caffeine.cache.Caffeine; +import com.github.benmanes.caffeine.cache.stats.CacheStats; import com.google.common.hash.Hasher; import com.google.common.hash.Hashing; import eu.emi.security.authn.x509.ProxySupport; @@ -39,7 +39,7 @@ import java.security.cert.CertificateExpiredException; import java.security.cert.CertificateNotYetValidException; import java.security.cert.X509Certificate; -import java.util.concurrent.ExecutionException; +import java.util.concurrent.CompletionException; import java.util.concurrent.TimeUnit; /** @@ -53,7 +53,7 @@ public class CachingCertificateValidator implements X509CertChainValidatorExt { public CachingCertificateValidator(X509CertChainValidatorExt val, long maxCacheEntryLifetime) { - cache = CacheBuilder.newBuilder() + cache = Caffeine.newBuilder() .expireAfterWrite(maxCacheEntryLifetime, TimeUnit.MILLISECONDS).build(); validator = val; } @@ -77,12 +77,12 @@ public ValidationResult validate(final X509Certificate[] certChain) { String certFingerprint = hasher.hash().toString(); - return cache.get(certFingerprint, () -> validator.validate(certChain)); + return cache.get(certFingerprint, (key) -> validator.validate(certChain)); } catch (CertificateEncodingException e) { return new ValidationResult(false, singletonList( new ValidationError(certChain, pos, ValidationErrorCode.inputError, e.getMessage()))); - } catch (ExecutionException e) { + } catch (CompletionException e) { return new ValidationResult(false, singletonList( new ValidationError(certChain, pos, ValidationErrorCode.inputError, e.getMessage()))); diff --git a/modules/dcache-bulk/src/main/java/org/dcache/services/bulk/store/jdbc/request/JdbcBulkRequestStore.java b/modules/dcache-bulk/src/main/java/org/dcache/services/bulk/store/jdbc/request/JdbcBulkRequestStore.java index f36708d5633..92c72547b17 100644 --- a/modules/dcache-bulk/src/main/java/org/dcache/services/bulk/store/jdbc/request/JdbcBulkRequestStore.java +++ b/modules/dcache-bulk/src/main/java/org/dcache/services/bulk/store/jdbc/request/JdbcBulkRequestStore.java @@ -72,11 +72,11 @@ LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING import static org.dcache.services.bulk.util.BulkRequestTarget.ROOT_REQUEST_PATH; import static org.dcache.services.bulk.util.BulkRequestTarget.State.CREATED; +import com.github.benmanes.caffeine.cache.CacheLoader; +import com.github.benmanes.caffeine.cache.Caffeine; +import com.github.benmanes.caffeine.cache.LoadingCache; import com.google.common.base.Strings; import com.google.common.base.Throwables; -import com.google.common.cache.CacheBuilder; -import com.google.common.cache.CacheLoader; -import com.google.common.cache.LoadingCache; import com.google.common.collect.ArrayListMultimap; import com.google.common.collect.ListMultimap; import diskCacheV111.util.CacheException; @@ -91,6 +91,7 @@ LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING import java.util.Map; import java.util.Optional; import java.util.Set; +import java.util.concurrent.CompletionException; import java.util.concurrent.ExecutionException; import java.util.concurrent.TimeUnit; import java.util.function.Consumer; @@ -139,7 +140,7 @@ public final class JdbcBulkRequestStore implements BulkRequestStore { private static final Integer FETCH_SIZE = 10000; - class RequestLoader extends CacheLoader> { + class RequestLoader implements CacheLoader> { @Override public Optional load(String uid) throws Exception { @@ -170,7 +171,7 @@ public Optional load(String uid) throws Exception { private PnfsHandler pnfsHandler; public void initialize() { - requestCache = CacheBuilder.newBuilder() + requestCache = Caffeine.newBuilder() .expireAfterAccess(expiry, expiryUnit) .maximumSize(capacity) .build(new RequestLoader()); @@ -232,7 +233,7 @@ public void clear(Subject subject, String uid) Optional stored; try { stored = requestCache.get(uid); - } catch (ExecutionException e) { + } catch (CompletionException e) { throw new BulkStorageException(e.getMessage(), e.getCause()); } @@ -251,7 +252,7 @@ public void clear(String uid) { try { stored = requestCache.get(uid); - } catch (ExecutionException e) { + } catch (CompletionException e) { Throwable cause = e.getCause(); LOGGER.error("Fatal error trying to clear {}: " + "{}.", uid, cause == null ? e.getMessage() : cause.getMessage()); @@ -354,7 +355,7 @@ public Optional getRequest(String uid) throws BulkStorageException Optional stored = Optional.empty(); try { stored = requestCache.get(uid); - } catch (ExecutionException e) { + } catch (CompletionException e) { Throwable cause = e.getCause(); LOGGER.error("Fatal error trying to get request {}: " + "{}.", uid, cause == null ? e.getMessage() : cause.getMessage()); @@ -542,7 +543,7 @@ public void reset(String uid) throws BulkStorageException { status.setLastModified(System.currentTimeMillis()); status.setCompletedAt(null); }); - } catch (ExecutionException e) { + } catch (CompletionException e) { throw new BulkStorageException(e.getMessage(), e.getCause()); } } @@ -712,7 +713,7 @@ public boolean update(String uid, BulkRequestStatus status) default: } }); - } catch (ExecutionException e) { + } catch (CompletionException e) { throw new BulkStorageException(e.getMessage(), e.getCause()); } @@ -805,7 +806,7 @@ private void clear(BulkRequest request) { private BulkRequest get(String uid) throws BulkStorageException { try { return requestCache.get(uid).orElse(null); - } catch (ExecutionException e) { + } catch (CompletionException e) { Throwable cause = e.getCause(); throw new BulkStorageException( cause == null ? e.getMessage() : cause.getMessage()); diff --git a/modules/dcache-ftp/src/main/java/org/dcache/ftp/door/AbstractFtpDoorV1.java b/modules/dcache-ftp/src/main/java/org/dcache/ftp/door/AbstractFtpDoorV1.java index d780922f390..eefcb28d239 100644 --- a/modules/dcache-ftp/src/main/java/org/dcache/ftp/door/AbstractFtpDoorV1.java +++ b/modules/dcache-ftp/src/main/java/org/dcache/ftp/door/AbstractFtpDoorV1.java @@ -71,6 +71,7 @@ LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING import static java.lang.annotation.ElementType.METHOD; import static java.lang.annotation.RetentionPolicy.RUNTIME; import static java.nio.charset.StandardCharsets.UTF_8; +import static java.util.Collections.synchronizedList; import static java.util.Objects.requireNonNull; import static org.dcache.acl.enums.AccessType.ACCESS_ALLOWED; import static org.dcache.auth.attributes.Activity.DELETE; @@ -102,11 +103,11 @@ LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING import static org.dcache.util.TransferRetryPolicy.maximumTries; import static org.dcache.util.TransferRetryPolicy.tryOnce; +import com.github.benmanes.caffeine.cache.LoadingCache; import com.google.common.annotations.VisibleForTesting; import com.google.common.base.Splitter; import com.google.common.base.Strings; import com.google.common.base.Throwables; -import com.google.common.cache.LoadingCache; import com.google.common.collect.ImmutableMap; import com.google.common.collect.Lists; import com.google.common.collect.Ordering; @@ -200,7 +201,7 @@ LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING import java.util.TimeZone; import java.util.Timer; import java.util.TimerTask; -import java.util.concurrent.ExecutionException; +import java.util.concurrent.CompletionException; import java.util.concurrent.Executor; import java.util.concurrent.TimeUnit; import java.util.function.Supplier; @@ -267,8 +268,6 @@ LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING import org.slf4j.Logger; import org.slf4j.LoggerFactory; -import static java.util.Collections.synchronizedList; - @Inherited @Retention(RUNTIME) @Target(METHOD) @@ -1522,11 +1521,13 @@ public void setExecutor(Executor executor) { _executor = new CDCExecutorDecorator<>(executor); } - public void setSpaceDescriptionCache(LoadingCache cache) { + public void setSpaceDescriptionCache( + LoadingCache cache) { _spaceDescriptionCache = cache; } - public void setSpaceLookupCache(LoadingCache> cache) { + public void setSpaceLookupCache( + LoadingCache> cache) { _spaceLookupCache = cache; } @@ -3233,7 +3234,7 @@ public void doUsage(String arg, boolean hasToken) throws FTPCommandException { default: throw new FTPCommandException(451, "Operation failed: " + e.getMessage(), e); } - } catch (ExecutionException e) { + } catch (CompletionException e) { Throwable cause = e.getCause(); Throwables.throwIfUnchecked(cause); throw new FTPCommandException(451, diff --git a/modules/dcache-ftp/src/main/java/org/dcache/ftp/door/FtpInterpreterFactory.java b/modules/dcache-ftp/src/main/java/org/dcache/ftp/door/FtpInterpreterFactory.java index d6957e0157c..1de296d9b36 100644 --- a/modules/dcache-ftp/src/main/java/org/dcache/ftp/door/FtpInterpreterFactory.java +++ b/modules/dcache-ftp/src/main/java/org/dcache/ftp/door/FtpInterpreterFactory.java @@ -17,7 +17,7 @@ */ package org.dcache.ftp.door; -import com.google.common.cache.LoadingCache; +import com.github.benmanes.caffeine.cache.LoadingCache; import diskCacheV111.doors.LineBasedInterpreter; import diskCacheV111.doors.NettyLineBasedInterpreterFactory; import diskCacheV111.services.space.Space; diff --git a/modules/dcache-info/src/main/java/org/dcache/services/info/InfoHttpEngine.java b/modules/dcache-info/src/main/java/org/dcache/services/info/InfoHttpEngine.java index d65460fff42..f9fc4e47c34 100644 --- a/modules/dcache-info/src/main/java/org/dcache/services/info/InfoHttpEngine.java +++ b/modules/dcache-info/src/main/java/org/dcache/services/info/InfoHttpEngine.java @@ -8,10 +8,10 @@ import static java.util.Arrays.asList; import static java.util.concurrent.TimeUnit.MILLISECONDS; +import com.github.benmanes.caffeine.cache.CacheLoader; +import com.github.benmanes.caffeine.cache.Caffeine; +import com.github.benmanes.caffeine.cache.LoadingCache; import com.google.common.base.Splitter; -import com.google.common.cache.CacheBuilder; -import com.google.common.cache.CacheLoader; -import com.google.common.cache.LoadingCache; import com.google.common.collect.ImmutableMap; import diskCacheV111.util.CacheException; import diskCacheV111.util.TimeoutCacheException; @@ -28,6 +28,7 @@ import java.util.Arrays; import java.util.List; import java.util.Map; +import java.util.concurrent.CompletionException; import java.util.concurrent.ExecutionException; import java.util.concurrent.TimeUnit; import org.dcache.cells.CellStub; @@ -93,10 +94,10 @@ private class SerialisationHandler { private final String _name; private final String _mimeType; - LoadingCache, String> resultCache = CacheBuilder.newBuilder() + LoadingCache, String> resultCache = Caffeine.newBuilder() .maximumSize(10) .expireAfterWrite(1, TimeUnit.SECONDS) - .build(new CacheLoader, String>() { + .build(new CacheLoader<>() { @Override public String load(List path) throws InterruptedException, CacheException, NoRouteToCellException { @@ -125,7 +126,7 @@ public void handleRequest(HttpRequest request) throws HttpException { request.printHttpHeader(raw.length); request.setContentType(this._mimeType); out.write(raw); - } catch (ExecutionException e) { + } catch (CompletionException e) { Throwable cause = e.getCause(); if (cause instanceof TimeoutCacheException) { throw new HttpException(503, "The info cell took too " + diff --git a/modules/dcache-nfs/src/main/java/org/dcache/chimera/nfsv41/door/DoorOperationFactory.java b/modules/dcache-nfs/src/main/java/org/dcache/chimera/nfsv41/door/DoorOperationFactory.java index 381fb695cfb..1c8771d2d4c 100644 --- a/modules/dcache-nfs/src/main/java/org/dcache/chimera/nfsv41/door/DoorOperationFactory.java +++ b/modules/dcache-nfs/src/main/java/org/dcache/chimera/nfsv41/door/DoorOperationFactory.java @@ -20,13 +20,14 @@ import static com.google.common.base.Throwables.getRootCause; import static java.nio.charset.StandardCharsets.UTF_8; -import com.google.common.cache.CacheBuilder; -import com.google.common.cache.CacheLoader; -import com.google.common.cache.LoadingCache; +import com.github.benmanes.caffeine.cache.CacheLoader; +import com.github.benmanes.caffeine.cache.Caffeine; +import com.github.benmanes.caffeine.cache.LoadingCache; import java.io.IOException; import java.security.Principal; import java.security.PrivilegedAction; import java.util.Optional; +import java.util.concurrent.CompletionException; import java.util.concurrent.ExecutionException; import java.util.concurrent.TimeUnit; import java.util.function.Function; @@ -110,7 +111,7 @@ public DoorOperationFactory(ProxyIoFactory proxyIoFactory, ChimeraVfs fs, _proxyIoFactory = proxyIoFactory; _vfs = fs; _jdbcFs = jdbcFs; - _pathCache = CacheBuilder.newBuilder() + _pathCache = Caffeine.newBuilder() .maximumSize(512) .expireAfterWrite(30, TimeUnit.SECONDS) .softValues() @@ -137,7 +138,7 @@ public DoorOperationFactory(ProxyIoFactory proxyIoFactory, ChimeraVfs fs, _inode2path = i -> { try { return _pathCache.get(i); - } catch (ExecutionException e) { + } catch (CompletionException e) { Throwable t = getRootCause(e); LOG.error("Failed to get inode path {} : {}", i, t.getMessage()); return "inode:" + i; @@ -157,19 +158,14 @@ public DoorOperationFactory(ProxyIoFactory proxyIoFactory, ChimeraVfs fs, } if (subjectMapper.isPresent()) { - CacheLoader loader = new CacheLoader() { - @Override - public Subject load(Principal key) throws Exception { - Subject in = new Subject(); - in.getPrincipals().add(key); - return subjectMapper.get().login(in); - } - }; - - _subjectCache = Optional.of(CacheBuilder.newBuilder() + _subjectCache = Optional.of(Caffeine.newBuilder() .maximumSize(2048) .expireAfterWrite(10, TimeUnit.MINUTES) - .build(loader)); + .build(key -> { + Subject in = new Subject(); + in.getPrincipals().add(key); + return subjectMapper.get().login(in); + })); } else { _subjectCache = Optional.empty(); } @@ -223,7 +219,7 @@ public void process(CompoundContext context, nfs_resop4 result) if (gids.length >= 16) { long uid = UnixSubjects.getUid(subject); UidPrincipal uidPrincipal = new UidPrincipal(uid); - subject = _subjectCache.get().getUnchecked(uidPrincipal); + subject = _subjectCache.get().get(uidPrincipal); context.getSubject().getPrincipals() .addAll(subject.getPrincipals()); } @@ -459,7 +455,7 @@ public void process(CompoundContext context, nfs_resop4 result) } } - private class ParentPathLoader extends CacheLoader { + private class ParentPathLoader implements CacheLoader { @Override public String load(FsInode inode) throws Exception { diff --git a/modules/dcache-nfs/src/main/java/org/dcache/chimera/nfsv41/door/proxy/NfsProxyIoFactory.java b/modules/dcache-nfs/src/main/java/org/dcache/chimera/nfsv41/door/proxy/NfsProxyIoFactory.java index 442d4a4efe8..af46df8aec5 100644 --- a/modules/dcache-nfs/src/main/java/org/dcache/chimera/nfsv41/door/proxy/NfsProxyIoFactory.java +++ b/modules/dcache-nfs/src/main/java/org/dcache/chimera/nfsv41/door/proxy/NfsProxyIoFactory.java @@ -2,15 +2,15 @@ import static org.dcache.chimera.nfsv41.door.ExceptionUtils.asNfsException; +import com.github.benmanes.caffeine.cache.Cache; +import com.github.benmanes.caffeine.cache.Caffeine; import com.google.common.base.Stopwatch; -import com.google.common.cache.Cache; -import com.google.common.cache.CacheBuilder; import com.google.common.net.HostAndPort; import java.io.IOException; import java.net.InetAddress; import java.net.InetSocketAddress; import java.util.Arrays; -import java.util.concurrent.ExecutionException; +import java.util.concurrent.CompletionException; import java.util.concurrent.TimeUnit; import java.util.function.Consumer; import java.util.stream.Collectors; @@ -59,7 +59,7 @@ public class NfsProxyIoFactory implements ProxyIoFactory { private static final Logger _log = LoggerFactory.getLogger(NfsProxyIoFactory.class); private final Cache _proxyIO - = CacheBuilder.newBuilder() + = Caffeine.newBuilder() .build(); private final NFSv41DeviceManager deviceManager; @@ -78,26 +78,29 @@ public ProxyIoAdapter getOrCreateProxy(Inode inode, stateid4 stateid, CompoundCo boolean isWrite) throws IOException { try { return _proxyIO.get(stateid, - () -> { - final NFS4Client nfsClient; - if (context.getMinorversion() == 1) { - nfsClient = context.getSession().getClient(); - } else { - nfsClient = context.getStateHandler().getClientIdByStateId(stateid); - } - - final NFS4State state = nfsClient.state(stateid); - final ProxyIoAdapter adapter = createIoAdapter(inode, stateid, context, - isWrite); - - state.addDisposeListener(s -> { - tryToClose(adapter); - _proxyIO.invalidate(s.stateid()); - }); - - return adapter; - }); - } catch (ExecutionException e) { + (key) -> { + try { + final NFS4Client nfsClient; + if (context.getMinorversion() == 1) { + nfsClient = context.getSession().getClient(); + } else { + nfsClient = context.getStateHandler().getClientIdByStateId(stateid); + } + + final NFS4State state = nfsClient.state(stateid); + final ProxyIoAdapter adapter = createIoAdapter(inode, stateid, context, + isWrite); + + state.addDisposeListener(s -> { + tryToClose(adapter); + _proxyIO.invalidate(s.stateid()); + }); + + return adapter; + } catch (IOException e) { + throw new CompletionException(e); + }}); + } catch (CompletionException e) { Throwable t = e.getCause(); _log.debug("failed to create IO adapter: {}", t.getMessage()); throw asNfsException(t, NfsIoException.class); @@ -233,7 +236,7 @@ public void forEach(Consumer action) { @Override public int getCount() { - return (int) _proxyIO.size(); + return (int) _proxyIO.estimatedSize(); } public static nfsv4_1_file_layout4 decodeLayoutId(byte[] data) throws IOException { diff --git a/modules/dcache-qos/src/main/java/org/dcache/qos/services/engine/util/QoSPolicyCache.java b/modules/dcache-qos/src/main/java/org/dcache/qos/services/engine/util/QoSPolicyCache.java index f06fa8d0768..e10c804e59c 100644 --- a/modules/dcache-qos/src/main/java/org/dcache/qos/services/engine/util/QoSPolicyCache.java +++ b/modules/dcache-qos/src/main/java/org/dcache/qos/services/engine/util/QoSPolicyCache.java @@ -59,16 +59,16 @@ LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING */ package org.dcache.qos.services.engine.util; +import com.github.benmanes.caffeine.cache.CacheLoader; +import com.github.benmanes.caffeine.cache.Caffeine; +import com.github.benmanes.caffeine.cache.LoadingCache; import com.google.common.base.Throwables; -import com.google.common.cache.CacheBuilder; -import com.google.common.cache.CacheLoader; -import com.google.common.cache.LoadingCache; import diskCacheV111.util.CacheException; import diskCacheV111.util.PermissionDeniedCacheException; import dmg.cells.nucleus.CellMessageReceiver; import dmg.cells.nucleus.NoRouteToCellException; import java.util.Optional; -import java.util.concurrent.ExecutionException; +import java.util.concurrent.CompletionException; import java.util.concurrent.TimeUnit; import javax.security.auth.Subject; import org.dcache.auth.Subjects; @@ -95,7 +95,7 @@ public class QoSPolicyCache implements CellMessageReceiver{ private static final Logger LOGGER = LoggerFactory.getLogger(QoSPolicyCache.class); - class PolicyLoader extends CacheLoader { + class PolicyLoader implements CacheLoader { @Override public QoSPolicy load(String name) throws Exception { @@ -137,7 +137,7 @@ public void setCapacity(long capacity) { } public void initialize() { - policyCache = CacheBuilder.newBuilder() + policyCache = Caffeine.newBuilder() .expireAfterAccess(expiry, expiryUnit) .maximumSize(capacity) .build(new PolicyLoader()); @@ -210,7 +210,7 @@ public PnfsManagerListQoSPoliciesMessage messageArrived(PnfsManagerListQoSPolici public Optional getPolicy(String name) { try { return Optional.ofNullable(policyCache.get(name)); - } catch (ExecutionException e) { + } catch (CompletionException e) { LOGGER.error("problem getting {}: {}.", name, String.valueOf(Throwables.getRootCause(e))); return Optional.empty(); } diff --git a/modules/dcache-srm/src/main/java/diskCacheV111/srm/SrmHandler.java b/modules/dcache-srm/src/main/java/diskCacheV111/srm/SrmHandler.java index eea06fc8b8d..604d7579922 100644 --- a/modules/dcache-srm/src/main/java/diskCacheV111/srm/SrmHandler.java +++ b/modules/dcache-srm/src/main/java/diskCacheV111/srm/SrmHandler.java @@ -51,11 +51,11 @@ import static org.dcache.srm.v2_2.TStatusCode.SRM_SUCCESS; import static org.dcache.srm.v2_2.TStatusCode.SRM_TOO_MANY_RESULTS; +import com.github.benmanes.caffeine.cache.CacheLoader; +import com.github.benmanes.caffeine.cache.Caffeine; +import com.github.benmanes.caffeine.cache.LoadingCache; import com.google.common.base.Strings; import com.google.common.base.Throwables; -import com.google.common.cache.CacheBuilder; -import com.google.common.cache.CacheLoader; -import com.google.common.cache.LoadingCache; import com.google.common.collect.ImmutableMap; import com.google.common.collect.ImmutableSet; import com.google.common.net.InetAddresses; @@ -257,17 +257,14 @@ public class SrmHandler implements CellInfoProvider, CuratorFrameworkAware { private final CertificateFactory cf = CertificateFactories.newX509CertificateFactory(); - private final LoadingCache> requestTokenFieldCache = CacheBuilder.newBuilder() - .build(new CacheLoader>() { - @Override - public Optional load(Class clazz) { - try { - Field field = clazz.getDeclaredField("requestToken"); - field.setAccessible(true); - return Optional.of(field); - } catch (NoSuchFieldException e) { - return Optional.empty(); - } + private final LoadingCache, Optional> requestTokenFieldCache = Caffeine.newBuilder() + .build(clazz -> { + try { + Field field = clazz.getDeclaredField("requestToken"); + field.setAccessible(true); + return Optional.of(field); + } catch (NoSuchFieldException e) { + return Optional.empty(); } }); @@ -727,7 +724,7 @@ public void close() { } private MappedRequest mapRequest(Object request) throws SRMInternalErrorException { - Optional field = requestTokenFieldCache.getUnchecked(request.getClass()); + Optional field = requestTokenFieldCache.get(request.getClass()); if (field.isPresent()) { try { Field f = field.get(); @@ -803,7 +800,7 @@ private SrmReleaseFilesResponse mapReleaseFilesResponse(SrmReleaseFilesRequest r private Object mapResponse(SrmResponse response) { Object o = response.getResponse(); - Optional field = requestTokenFieldCache.getUnchecked(o.getClass()); + Optional field = requestTokenFieldCache.get(o.getClass()); field.ifPresent(f -> { try { f.set(o, prefix(response.getId(), (String) f.get(o))); diff --git a/modules/dcache-srm/src/main/java/diskCacheV111/srm/dcache/CanonicalizingByteArrayStore.java b/modules/dcache-srm/src/main/java/diskCacheV111/srm/dcache/CanonicalizingByteArrayStore.java index ee4b45b0458..052c138ff89 100644 --- a/modules/dcache-srm/src/main/java/diskCacheV111/srm/dcache/CanonicalizingByteArrayStore.java +++ b/modules/dcache-srm/src/main/java/diskCacheV111/srm/dcache/CanonicalizingByteArrayStore.java @@ -19,15 +19,16 @@ import static org.dcache.util.ByteUnit.KiB; +import com.github.benmanes.caffeine.cache.Cache; +import com.github.benmanes.caffeine.cache.Caffeine; import com.google.common.base.Throwables; -import com.google.common.cache.Cache; -import com.google.common.cache.CacheBuilder; import com.google.common.hash.HashCode; import com.google.common.hash.Hashing; import com.google.common.util.concurrent.Striped; import com.google.common.util.concurrent.UncheckedExecutionException; import java.util.Arrays; import java.util.List; +import java.util.concurrent.CompletionException; import java.util.concurrent.ExecutionException; import java.util.concurrent.TimeUnit; import java.util.concurrent.locks.Lock; @@ -108,7 +109,7 @@ public int hashCode() { * Cache to reduce frequent reloads from the database. */ private final Cache cache = - CacheBuilder.newBuilder().expireAfterAccess(10, TimeUnit.MINUTES).maximumSize(1000) + Caffeine.newBuilder().expireAfterAccess(10, TimeUnit.MINUTES).maximumSize(1000) .build(); /** @@ -117,7 +118,7 @@ public int hashCode() { *

* Class invariant: Any Token has a corresponding byte array in the database. */ - private final Cache canonicalizationCache = CacheBuilder.newBuilder().weakValues() + private final Cache canonicalizationCache = Caffeine.newBuilder().weakValues() .build(); /** @@ -217,8 +218,8 @@ public byte[] readBytes(Token token) { */ private Token makeToken(long id) { try { - return canonicalizationCache.get(id, () -> new Token(id)); - } catch (UncheckedExecutionException | ExecutionException e) { + return canonicalizationCache.get(id, (key) -> new Token(id)); + } catch (UncheckedExecutionException | CompletionException e) { Throwable cause = e.getCause(); Throwables.throwIfUnchecked(cause); throw new RuntimeException(cause); diff --git a/modules/dcache-srm/src/main/java/diskCacheV111/srm/dcache/Storage.java b/modules/dcache-srm/src/main/java/diskCacheV111/srm/dcache/Storage.java index 880d557c8f6..c22518b102c 100644 --- a/modules/dcache-srm/src/main/java/diskCacheV111/srm/dcache/Storage.java +++ b/modules/dcache-srm/src/main/java/diskCacheV111/srm/dcache/Storage.java @@ -81,14 +81,13 @@ LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING import static org.dcache.srm.SRMInvalidPathException.checkValidPath; import static org.dcache.util.NetworkUtils.isInetAddress; +import com.github.benmanes.caffeine.cache.CacheLoader; +import com.github.benmanes.caffeine.cache.Caffeine; +import com.github.benmanes.caffeine.cache.LoadingCache; import com.google.common.base.CharMatcher; -import com.google.common.base.Function; import com.google.common.base.Joiner; import com.google.common.base.Predicate; import com.google.common.base.Throwables; -import com.google.common.cache.CacheBuilder; -import com.google.common.cache.CacheLoader; -import com.google.common.cache.LoadingCache; import com.google.common.collect.ImmutableMap; import com.google.common.collect.Maps; import com.google.common.collect.Ordering; @@ -161,9 +160,8 @@ LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING import java.util.Optional; import java.util.Random; import java.util.Set; -import java.util.concurrent.CancellationException; +import java.util.concurrent.CompletionException; import java.util.concurrent.ConcurrentHashMap; -import java.util.concurrent.ExecutionException; import java.util.concurrent.Executor; import java.util.concurrent.Semaphore; import java.util.concurrent.atomic.AtomicLong; @@ -201,7 +199,6 @@ LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING import org.dcache.srm.CopyCallbacks; import org.dcache.srm.FileMetaData; import org.dcache.srm.RemoveFileCallback; -import org.dcache.srm.SRMAbortedException; import org.dcache.srm.SRMAuthorizationException; import org.dcache.srm.SRMDuplicationException; import org.dcache.srm.SRMExceedAllocationException; @@ -256,7 +253,7 @@ public final class Storage private static final Set FTP_URL_SCHEMATA = Set.of("ftp", "gsiftp", "gkftp"); private static final LoadingCache GET_HOST_BY_ADDR_CACHE = - CacheBuilder.newBuilder() + Caffeine.newBuilder() .expireAfterWrite(10, MINUTES) .recordStats() .build(new GetHostByAddressCacheLoader()); @@ -940,7 +937,7 @@ private String selectHostName(LoginBrokerInfo door, InetAddressScope scope, resolvedHost = GET_HOST_BY_ADDR_CACHE.get(address); } return resolvedHost; - } catch (ExecutionException e) { + } catch (CompletionException e) { Throwable cause = e.getCause(); throw new SRMInternalErrorException("Failed to resolve door: " + cause, cause); } @@ -1032,7 +1029,7 @@ public ListenableFuture prepareToPut( "Space associated with the space token " + spaceToken + " is not enough to hold SURL.")); } - } catch (ExecutionException e) { + } catch (CompletionException e) { return immediateFailedFuture(new SRMException( "Failure while querying space reservation: " + e.getCause() .getMessage())); @@ -2231,7 +2228,7 @@ public String[] srmGetSpaceTokens(SRMUser user, String description) _log.trace("srmGetSpaceTokens returns: {}", Arrays.toString(tokens)); } return Arrays.stream(tokens).mapToObj(Long::toString).toArray(String[]::new); - } catch (ExecutionException e) { + } catch (CompletionException e) { Throwable cause = e.getCause(); Throwables.throwIfInstanceOf(cause, SRMException.class); Throwables.throwIfUnchecked(cause); @@ -2340,7 +2337,7 @@ private static DcacheUser asDcacheUser(SRMUser user) throws SRMAuthorizationExce return dcacheUser; } - private static class GetHostByAddressCacheLoader extends CacheLoader { + private static class GetHostByAddressCacheLoader implements CacheLoader { @Override public String load(InetAddress address) throws Exception { diff --git a/modules/dcache-webdav/src/main/java/org/dcache/webdav/DcacheResourceFactory.java b/modules/dcache-webdav/src/main/java/org/dcache/webdav/DcacheResourceFactory.java index cea7987c0ae..549b82da7be 100644 --- a/modules/dcache-webdav/src/main/java/org/dcache/webdav/DcacheResourceFactory.java +++ b/modules/dcache-webdav/src/main/java/org/dcache/webdav/DcacheResourceFactory.java @@ -27,11 +27,11 @@ import static org.dcache.util.TransferRetryPolicy.tryOnce; import static org.dcache.webdav.InsufficientStorageException.checkStorageSufficient; +import com.github.benmanes.caffeine.cache.LoadingCache; import com.google.common.base.Joiner; import com.google.common.base.Objects; import com.google.common.base.Splitter; import com.google.common.base.Throwables; -import com.google.common.cache.LoadingCache; import com.google.common.collect.ImmutableMap; import com.google.common.collect.Iterables; import com.google.common.collect.Maps; @@ -106,6 +106,7 @@ import java.util.Optional; import java.util.OptionalLong; import java.util.Set; +import java.util.concurrent.CompletionException; import java.util.concurrent.ExecutionException; import java.util.concurrent.ScheduledExecutorService; import java.util.concurrent.TimeUnit; @@ -1614,7 +1615,7 @@ FileLocality calculateLocality(FileAttributes attributes, String clientIP) { private Optional lookupSpaceById(String id) { try { return _spaceLookupCache.get(id); - } catch (ExecutionException e) { + } catch (CompletionException e) { Throwable t = e.getCause(); Throwables.throwIfUnchecked(t); LOGGER.warn("Failed to fetch space statistics for {}: {}", id, t.toString()); @@ -1625,7 +1626,7 @@ private Optional lookupSpaceById(String id) { private Optional lookupWriteToken(FsPath path) { try { return _writeTokenCache.get(path); - } catch (ExecutionException e) { + } catch (CompletionException e) { Throwable t = e.getCause(); Throwables.throwIfUnchecked(t); LOGGER.warn("Failed to query for WriteToken tag on {}: {}", path, t.toString()); diff --git a/modules/dcache-webdav/src/main/java/org/dcache/webdav/transfer/CredentialServiceClient.java b/modules/dcache-webdav/src/main/java/org/dcache/webdav/transfer/CredentialServiceClient.java index 31891fb70d0..c75294d24b9 100644 --- a/modules/dcache-webdav/src/main/java/org/dcache/webdav/transfer/CredentialServiceClient.java +++ b/modules/dcache-webdav/src/main/java/org/dcache/webdav/transfer/CredentialServiceClient.java @@ -20,8 +20,8 @@ import static java.nio.charset.StandardCharsets.UTF_8; import static java.util.concurrent.TimeUnit.SECONDS; -import com.google.common.cache.Cache; -import com.google.common.cache.CacheBuilder; +import com.github.benmanes.caffeine.cache.Cache; +import com.github.benmanes.caffeine.cache.Caffeine; import com.google.common.collect.ImmutableMap; import diskCacheV111.srm.CredentialServiceAnnouncement; import diskCacheV111.srm.CredentialServiceRequest; @@ -86,7 +86,7 @@ public class CredentialServiceClient private CellStub topic; - private Cache cache = CacheBuilder.newBuilder() + private Cache cache = Caffeine.newBuilder() .expireAfterWrite(70, SECONDS).build(); @Required diff --git a/modules/dcache/pom.xml b/modules/dcache/pom.xml index 19ce59ebd70..272433288d5 100644 --- a/modules/dcache/pom.xml +++ b/modules/dcache/pom.xml @@ -46,6 +46,10 @@ com.google.guava guava + + com.github.ben-manes.caffeine + caffeine + org.dcache diff --git a/modules/dcache/src/main/java/diskCacheV111/doors/NettyLineBasedDoor.java b/modules/dcache/src/main/java/diskCacheV111/doors/NettyLineBasedDoor.java index c32a8f69794..b8ed7455f52 100644 --- a/modules/dcache/src/main/java/diskCacheV111/doors/NettyLineBasedDoor.java +++ b/modules/dcache/src/main/java/diskCacheV111/doors/NettyLineBasedDoor.java @@ -22,7 +22,7 @@ import static java.nio.charset.StandardCharsets.UTF_8; import static org.dcache.util.ByteUnit.KiB; -import com.google.common.cache.LoadingCache; +import com.github.benmanes.caffeine.cache.LoadingCache; import com.google.common.net.InetAddresses; import diskCacheV111.services.space.Space; import dmg.cells.nucleus.CDC; diff --git a/modules/dcache/src/main/java/diskCacheV111/doors/NettyLineBasedDoorFactory.java b/modules/dcache/src/main/java/diskCacheV111/doors/NettyLineBasedDoorFactory.java index 9523dda255b..0912e58f88f 100644 --- a/modules/dcache/src/main/java/diskCacheV111/doors/NettyLineBasedDoorFactory.java +++ b/modules/dcache/src/main/java/diskCacheV111/doors/NettyLineBasedDoorFactory.java @@ -19,7 +19,7 @@ package diskCacheV111.doors; -import com.google.common.cache.LoadingCache; +import com.github.benmanes.caffeine.cache.LoadingCache; import com.google.common.util.concurrent.AbstractService; import com.google.common.util.concurrent.ThreadFactoryBuilder; import diskCacheV111.services.space.Space; diff --git a/modules/dcache/src/main/java/diskCacheV111/doors/NettyLineBasedInterpreterFactory.java b/modules/dcache/src/main/java/diskCacheV111/doors/NettyLineBasedInterpreterFactory.java index 2e3bbff9757..b1f2d7b4fd1 100644 --- a/modules/dcache/src/main/java/diskCacheV111/doors/NettyLineBasedInterpreterFactory.java +++ b/modules/dcache/src/main/java/diskCacheV111/doors/NettyLineBasedInterpreterFactory.java @@ -18,7 +18,7 @@ */ package diskCacheV111.doors; -import com.google.common.cache.LoadingCache; +import com.github.benmanes.caffeine.cache.LoadingCache; import diskCacheV111.services.space.Space; import diskCacheV111.util.ConfigurationException; import dmg.cells.nucleus.CellAddressCore; diff --git a/modules/dcache/src/main/java/diskCacheV111/poolManager/PoolSelectionUnitV2.java b/modules/dcache/src/main/java/diskCacheV111/poolManager/PoolSelectionUnitV2.java index c2685acd2a2..d3bb0a87b1b 100644 --- a/modules/dcache/src/main/java/diskCacheV111/poolManager/PoolSelectionUnitV2.java +++ b/modules/dcache/src/main/java/diskCacheV111/poolManager/PoolSelectionUnitV2.java @@ -10,13 +10,13 @@ import static org.dcache.namespace.FileAttribute.HSM; import static org.dcache.namespace.FileAttribute.STORAGECLASS; +import com.github.benmanes.caffeine.cache.Cache; +import com.github.benmanes.caffeine.cache.Caffeine; import com.google.common.base.Joiner; import com.google.common.base.Preconditions; import com.google.common.base.Predicates; import com.google.common.base.Splitter; import com.google.common.base.Strings; -import com.google.common.cache.Cache; -import com.google.common.cache.CacheBuilder; import com.google.common.collect.ImmutableList; import com.google.common.collect.Lists; import com.google.common.collect.Maps; @@ -97,7 +97,7 @@ public String getVersion() { private final Map _uGroups = new HashMap<>(); private final Map _units = new HashMap<>(); private final Cache cachedMatchValue = - CacheBuilder.newBuilder() + Caffeine.newBuilder() .maximumSize(100000) .build(); private boolean _useRegex; diff --git a/modules/dcache/src/main/java/diskCacheV111/poolManager/RestoreRequestsReceiver.java b/modules/dcache/src/main/java/diskCacheV111/poolManager/RestoreRequestsReceiver.java index b08b8528cae..2ae6c8ca69c 100644 --- a/modules/dcache/src/main/java/diskCacheV111/poolManager/RestoreRequestsReceiver.java +++ b/modules/dcache/src/main/java/diskCacheV111/poolManager/RestoreRequestsReceiver.java @@ -59,10 +59,11 @@ LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING */ package diskCacheV111.poolManager; -import com.google.common.cache.Cache; -import com.google.common.cache.CacheBuilder; +import com.github.benmanes.caffeine.cache.Cache; +import com.github.benmanes.caffeine.cache.Caffeine; import diskCacheV111.vehicles.RestoreHandlerInfo; import dmg.cells.nucleus.CellMessageReceiver; +import java.util.Collection; import java.util.List; import java.util.Set; import java.util.concurrent.TimeUnit; @@ -81,7 +82,7 @@ public class RestoreRequestsReceiver implements CellMessageReceiver { private TimeUnit lifetimeUnit = TimeUnit.HOURS; public void initialize() { - restores = CacheBuilder.newBuilder() + restores = Caffeine.newBuilder() .expireAfterWrite(lifetime, lifetimeUnit) .build(); } @@ -92,7 +93,7 @@ public void initialize() { public List getAllRequests() { return restores.asMap().values() .stream() - .flatMap(list -> list.stream()) + .flatMap(Collection::stream) .collect(Collectors.toList()); } diff --git a/modules/dcache/src/main/java/org/dcache/auth/CachingLoginStrategy.java b/modules/dcache/src/main/java/org/dcache/auth/CachingLoginStrategy.java index 25bea1ee98c..f33802e1cb8 100644 --- a/modules/dcache/src/main/java/org/dcache/auth/CachingLoginStrategy.java +++ b/modules/dcache/src/main/java/org/dcache/auth/CachingLoginStrategy.java @@ -1,9 +1,9 @@ package org.dcache.auth; +import com.github.benmanes.caffeine.cache.CacheLoader; +import com.github.benmanes.caffeine.cache.Caffeine; +import com.github.benmanes.caffeine.cache.LoadingCache; import com.google.common.base.Throwables; -import com.google.common.cache.CacheBuilder; -import com.google.common.cache.CacheLoader; -import com.google.common.cache.LoadingCache; import com.google.common.util.concurrent.Futures; import com.google.common.util.concurrent.ListenableFuture; import com.google.common.util.concurrent.UncheckedExecutionException; @@ -15,6 +15,8 @@ import java.io.PrintWriter; import java.security.Principal; import java.util.Set; +import java.util.concurrent.CompletableFuture; +import java.util.concurrent.CompletionException; import java.util.concurrent.ExecutionException; import java.util.concurrent.TimeUnit; import javax.security.auth.Subject; @@ -27,9 +29,9 @@ public class CachingLoginStrategy implements LoginStrategy, CellCommandListener, private final LoginStrategy _inner; - private final LoadingCache> _forwardCache; - private final LoadingCache>> _reverseCache; - private final LoadingCache> _loginCache; + private final LoadingCache> _forwardCache; + private final LoadingCache>> _reverseCache; + private final LoadingCache> _loginCache; private final long _time; private final TimeUnit _unit; @@ -47,21 +49,21 @@ public CachingLoginStrategy(LoginStrategy inner, int size, long timeout, TimeUni _inner = inner; - _forwardCache = CacheBuilder.newBuilder() + _forwardCache = Caffeine.newBuilder() .expireAfterWrite(timeout, unit) .maximumSize(size) .softValues() .recordStats() .build(new ForwardFetcher()); - _reverseCache = CacheBuilder.newBuilder() + _reverseCache = Caffeine.newBuilder() .expireAfterWrite(timeout, unit) .maximumSize(size) .softValues() .recordStats() .build(new ReverseFetcher()); - _loginCache = CacheBuilder.newBuilder() + _loginCache = Caffeine.newBuilder() .expireAfterWrite(timeout, unit) .maximumSize(size) .softValues() @@ -79,7 +81,7 @@ public LoginReply login(Subject subject) throws CacheException { return _loginCache.get(subject).get(); } catch (InterruptedException e) { throw new TimeoutCacheException("Request interrupted"); - } catch (ExecutionException e) { + } catch (ExecutionException | CompletionException e) { Throwables.propagateIfPossible(e.getCause(), CacheException.class); throw new RuntimeException(e.getCause()); } catch (UncheckedExecutionException e) { @@ -118,41 +120,41 @@ public Set reverseMap(Principal principal) throws CacheException { } } - private class ForwardFetcher extends CacheLoader> { + private class ForwardFetcher implements CacheLoader> { @Override - public ListenableFuture load(Principal f) throws CacheException { + public CompletableFuture load(Principal f) throws CacheException { try { - return Futures.immediateFuture(_inner.map(f)); + return CompletableFuture.completedFuture(_inner.map(f)); } catch (CacheException e) { Throwables.propagateIfPossible(e, TimeoutCacheException.class); - return Futures.immediateFailedFuture(e); + return CompletableFuture.failedFuture(e); } } } - private class ReverseFetcher extends CacheLoader>> { + private class ReverseFetcher implements CacheLoader>> { @Override - public ListenableFuture> load(Principal f) throws CacheException { + public CompletableFuture> load(Principal f) throws CacheException { try { - return Futures.immediateFuture(_inner.reverseMap(f)); + return CompletableFuture.completedFuture(_inner.reverseMap(f)); } catch (CacheException e) { Throwables.propagateIfPossible(e, TimeoutCacheException.class); - return Futures.immediateFailedFuture(e); + return CompletableFuture.failedFuture(e); } } } - private class LoginFetcher extends CacheLoader> { + private class LoginFetcher implements CacheLoader> { @Override - public ListenableFuture load(Subject f) throws CacheException { + public CompletableFuture load(Subject f) throws CacheException { try { - return Futures.immediateFuture(_inner.login(f)); + return CompletableFuture.completedFuture(_inner.login(f)); } catch (CacheException e) { Throwables.propagateIfPossible(e, TimeoutCacheException.class); - return Futures.immediateFailedFuture(e); + return CompletableFuture.failedFuture(e); } } } @@ -178,7 +180,7 @@ public String ac_login_dump_cache(Args args) { sb.append("Login:\n"); for (Subject s : _loginCache.asMap().keySet()) { try { - ListenableFuture out = _loginCache.getIfPresent(s); + CompletableFuture out = _loginCache.getIfPresent(s); if (out != null) { sb.append(" ").append(Subjects.toString(s)).append(" => "); sb.append(out.get()).append('\n'); @@ -190,7 +192,7 @@ public String ac_login_dump_cache(Args args) { sb.append("Map:\n"); for (Principal p : _forwardCache.asMap().keySet()) { try { - ListenableFuture out = _forwardCache.getIfPresent(p); + CompletableFuture out = _forwardCache.getIfPresent(p); if (out != null) { sb.append(" ").append(p).append(" => "); sb.append(out.get()).append('\n'); @@ -202,7 +204,7 @@ public String ac_login_dump_cache(Args args) { sb.append("ReverseMap:\n"); for (Principal p : _reverseCache.asMap().keySet()) { try { - ListenableFuture> out = _reverseCache.getIfPresent(p); + CompletableFuture> out = _reverseCache.getIfPresent(p); if (out != null) { sb.append(" ").append(p).append(" => "); sb.append(out.get()).append('\n'); diff --git a/modules/dcache/src/main/java/org/dcache/services/login/IdentityResolverFactory.java b/modules/dcache/src/main/java/org/dcache/services/login/IdentityResolverFactory.java index b90b796706a..a28007fd5d8 100644 --- a/modules/dcache/src/main/java/org/dcache/services/login/IdentityResolverFactory.java +++ b/modules/dcache/src/main/java/org/dcache/services/login/IdentityResolverFactory.java @@ -20,15 +20,15 @@ import static com.google.common.base.Preconditions.checkArgument; +import com.github.benmanes.caffeine.cache.CacheLoader; +import com.github.benmanes.caffeine.cache.Caffeine; +import com.github.benmanes.caffeine.cache.LoadingCache; import com.google.common.base.Throwables; -import com.google.common.cache.CacheBuilder; -import com.google.common.cache.CacheLoader; -import com.google.common.cache.LoadingCache; import com.google.common.util.concurrent.UncheckedExecutionException; import diskCacheV111.util.CacheException; import java.security.Principal; import java.util.Optional; -import java.util.concurrent.ExecutionException; +import java.util.concurrent.CompletionException; import java.util.concurrent.TimeUnit; import javax.security.auth.Subject; import org.dcache.auth.GidPrincipal; @@ -54,10 +54,10 @@ public class IdentityResolverFactory { private final LoginStrategy loginStrategy; - private final LoadingCache> uidToName = CacheBuilder.newBuilder() + private final LoadingCache> uidToName = Caffeine.newBuilder() .maximumSize(1000) .expireAfterWrite(1, TimeUnit.MINUTES) - .build(new CacheLoader>() { + .build(new CacheLoader<>() { @Override public Optional load(Long uid) throws CacheException { for (Principal p : loginStrategy.reverseMap(new UidPrincipal(uid))) { @@ -69,10 +69,10 @@ public Optional load(Long uid) throws CacheException { } }); - private final LoadingCache> gidToName = CacheBuilder.newBuilder() + private final LoadingCache> gidToName = Caffeine.newBuilder() .maximumSize(1000) .expireAfterWrite(1, TimeUnit.MINUTES) - .build(new CacheLoader>() { + .build(new CacheLoader<>() { @Override public Optional load(Long gid) throws CacheException { for (Principal p : loginStrategy.reverseMap(new GidPrincipal(gid, false))) { @@ -195,7 +195,7 @@ public Optional uidToName(long uid) { if (!name.isPresent()) { try { name = uidToName.get(uid); - } catch (ExecutionException e) { + } catch (CompletionException e) { Throwable t = e.getCause(); Throwables.throwIfUnchecked(t); LOGGER.warn("Failed to obtain username for uid {}: {}", uid, @@ -215,7 +215,7 @@ public Optional gidToName(long gid) { if (!name.isPresent()) { try { name = gidToName.get(gid); - } catch (ExecutionException e) { + } catch (CompletionException e) { Throwable t = e.getCause(); Throwables.throwIfUnchecked(t); LOGGER.warn("Failed to obtain groupname for gid {}: {}", gid, diff --git a/modules/dcache/src/main/java/org/dcache/space/ReservationCaches.java b/modules/dcache/src/main/java/org/dcache/space/ReservationCaches.java index cfbba718566..d01ff1ef24a 100644 --- a/modules/dcache/src/main/java/org/dcache/space/ReservationCaches.java +++ b/modules/dcache/src/main/java/org/dcache/space/ReservationCaches.java @@ -69,11 +69,10 @@ LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING import static java.util.concurrent.TimeUnit.MINUTES; import static java.util.concurrent.TimeUnit.SECONDS; -import com.google.common.cache.CacheBuilder; -import com.google.common.cache.CacheLoader; -import com.google.common.cache.LoadingCache; -import com.google.common.util.concurrent.ListenableFuture; -import com.google.common.util.concurrent.SettableFuture; +import com.github.benmanes.caffeine.cache.AsyncCacheLoader; +import com.github.benmanes.caffeine.cache.AsyncLoadingCache; +import com.github.benmanes.caffeine.cache.Caffeine; +import com.github.benmanes.caffeine.cache.LoadingCache; import diskCacheV111.services.space.Space; import diskCacheV111.services.space.message.GetSpaceMetaData; import diskCacheV111.services.space.message.GetSpaceTokens; @@ -89,6 +88,7 @@ LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING import java.util.Objects; import java.util.Optional; import java.util.Set; +import java.util.concurrent.CompletableFuture; import java.util.concurrent.Executor; import javax.security.auth.Subject; import org.dcache.cells.AbstractMessageCallback; @@ -153,16 +153,22 @@ private ReservationCaches() { */ public static LoadingCache buildOwnerDescriptionLookupCache( CellStub spaceManager, Executor executor) { - return CacheBuilder.newBuilder() - .maximumSize(1000) - .expireAfterWrite(30, SECONDS) - .refreshAfterWrite(10, SECONDS) - .recordStats() - .build(new CacheLoader() { + return Caffeine.newBuilder().maximumSize(1000).expireAfterWrite(30, SECONDS) + .refreshAfterWrite(10, SECONDS).recordStats().executor(executor) + .buildAsync(new AsyncCacheLoader() { + private GetSpaceTokens createRequest(GetSpaceTokensKey key) { + GetSpaceTokens message = new GetSpaceTokens(key.description); + message.setSubject(new Subject(true, key.principals, Collections.emptySet(), + Collections.emptySet())); + return message; + } + @Override - public long[] load(GetSpaceTokensKey key) throws Exception { + public CompletableFuture asyncLoad(GetSpaceTokensKey key, + Executor executor) throws Exception { try { - return spaceManager.sendAndWait(createRequest(key)).getSpaceTokens(); + return CompletableFuture.completedFuture( + spaceManager.sendAndWait(createRequest(key)).getSpaceTokens()); } catch (TimeoutCacheException e) { throw new SRMInternalErrorException("Space manager timeout", e); } catch (InterruptedException e) { @@ -170,132 +176,137 @@ public long[] load(GetSpaceTokensKey key) throws Exception { } catch (CacheException e) { LOGGER.warn("GetSpaceTokens failed with rc={} error={}", e.getRc(), e.getMessage()); - throw new SRMException("GetSpaceTokens failed with rc=" + e.getRc() + - " error=" + e.getMessage(), e); + throw new SRMException( + "GetSpaceTokens failed with rc=" + e.getRc() + " error=" + + e.getMessage(), e); } } - private GetSpaceTokens createRequest(GetSpaceTokensKey key) { - GetSpaceTokens message = new GetSpaceTokens(key.description); - message.setSubject(new Subject(true, key.principals, - Collections.emptySet(), Collections.emptySet())); - return message; - } - @Override - public ListenableFuture reload(GetSpaceTokensKey key, long[] oldValue) - throws Exception { - final SettableFuture future = SettableFuture.create(); - CellStub.addCallback( - spaceManager.send(createRequest(key)), - new AbstractMessageCallback() { + public CompletableFuture asyncReload(GetSpaceTokensKey key, + long[] oldValue, Executor executor) { + // A future we are going to complete in the Cell Callback. + final CompletableFuture future = new CompletableFuture<>(); + + CellStub.addCallback(spaceManager.send(createRequest(key)), + new AbstractMessageCallback<>() { @Override public void success(GetSpaceTokens message) { - future.set(message.getSpaceTokens()); + future.complete(message.getSpaceTokens()); } @Override public void failure(int rc, Object error) { - CacheException exception = CacheExceptionFactory.exceptionOf( - rc, Objects.toString(error, null)); - future.setException(exception); + CacheException exception = CacheExceptionFactory.exceptionOf(rc, + Objects.toString(error, null)); + future.completeExceptionally(exception); } }, executor); return future; } - }); + }).synchronous(); } /** * Build a loading cache for looking up space reservations by space token. */ - public static LoadingCache> buildSpaceLookupCache(CellStub spaceManager, + public static LoadingCache> buildSpaceLookupCache( + CellStub spaceManager, Executor executor) { - return CacheBuilder.newBuilder() + return Caffeine.newBuilder() .maximumSize(1000) .expireAfterWrite(10, MINUTES) .refreshAfterWrite(30, SECONDS) .recordStats() - .build( - new CacheLoader>() { - @Override - public Optional load(String token) - throws CacheException, NoRouteToCellException, InterruptedException { - Space space = - spaceManager.sendAndWait(new GetSpaceMetaData(token)) - .getSpaces()[0]; - return Optional.ofNullable(space); - } - - @Override - public ListenableFuture> reload(String token, - Optional oldValue) { - final SettableFuture> future = SettableFuture.create(); - CellStub.addCallback( - spaceManager.send(new GetSpaceMetaData(token)), - new AbstractMessageCallback() { - @Override - public void success(GetSpaceMetaData message) { - future.set(Optional.ofNullable(message.getSpaces()[0])); - } - - @Override - public void failure(int rc, Object error) { - CacheException exception = CacheExceptionFactory.exceptionOf( - rc, Objects.toString(error, null)); - future.setException(exception); - } - }, executor); - return future; - } - }); + .executor(executor) + .buildAsync(new AsyncCacheLoader>() { + @Override + public CompletableFuture> asyncLoad(String token, + Executor executor) + throws CacheException, NoRouteToCellException, InterruptedException { + + Space space = spaceManager.sendAndWait(new GetSpaceMetaData(token)) + .getSpaces()[0]; + + return CompletableFuture.completedFuture(Optional.ofNullable(space)); + } + + @Override + public CompletableFuture> asyncReload(String token, + Optional oldValue, Executor executor) { + // A future we are going to complete in the Cell Callback. + final CompletableFuture> future = new CompletableFuture<>(); + + CellStub.addCallback( + spaceManager.send(new GetSpaceMetaData(token)), + new AbstractMessageCallback<>() { + @Override + public void success(GetSpaceMetaData message) { + future.complete(Optional.ofNullable(message.getSpaces()[0])); + } + + @Override + public void failure(int rc, Object error) { + CacheException exception = CacheExceptionFactory.exceptionOf( + rc, Objects.toString(error, null)); + future.completeExceptionally(exception); + } + }, executor); + return future; + } + }).synchronous(); } /** * Cache queries to discover if a directory has the "WriteToken" tag set. */ - public static LoadingCache> buildWriteTokenLookupCache( + public static LoadingCache> buildWriteTokenLookupCache( PnfsHandler pnfs, Executor executor) { - return CacheBuilder.newBuilder() + return Caffeine.newBuilder() .maximumSize(1000) .expireAfterWrite(10, MINUTES) .refreshAfterWrite(5, MINUTES) .recordStats() - .build(new CacheLoader>() { - private java.util.Optional writeToken(FileAttributes attr) { + .executor(executor) + .buildAsync(new AsyncCacheLoader>() { + private Optional writeToken(FileAttributes attr) { StorageInfo info = attr.getStorageInfo(); - return java.util.Optional.ofNullable(info.getMap().get("writeToken")); + return Optional.ofNullable(info.getMap().get("writeToken")); } @Override - public java.util.Optional load(FsPath path) - throws CacheException, NoRouteToCellException, InterruptedException { - return writeToken( - pnfs.getFileAttributes(path, EnumSet.of(FileAttribute.STORAGEINFO))); + public CompletableFuture> asyncLoad(FsPath path, + Executor executor) + throws CacheException { + return CompletableFuture.completedFuture(writeToken( + pnfs.getFileAttributes(path, EnumSet.of(FileAttribute.STORAGEINFO)))); } @Override - public ListenableFuture> reload(FsPath path, - java.util.Optional old) { + public CompletableFuture> asyncReload(FsPath path, + Optional old, Executor executor) { + // A future we are going to complete in the Cell Callback. + final CompletableFuture> future = new CompletableFuture<>(); + PnfsGetFileAttributes message = new PnfsGetFileAttributes(path.toString(), EnumSet.of(FileAttribute.STORAGEINFO)); - SettableFuture> future = SettableFuture.create(); + CellStub.addCallback(pnfs.requestAsync(message), - new AbstractMessageCallback() { + new AbstractMessageCallback<>() { @Override public void success(PnfsGetFileAttributes message) { - future.set(writeToken(message.getFileAttributes())); + future.complete(writeToken(message.getFileAttributes())); } @Override public void failure(int rc, Object error) { CacheException exception = CacheExceptionFactory.exceptionOf( rc, Objects.toString(error, null)); - future.setException(exception); + future.completeExceptionally(exception); } }, executor); return future; } - }); + }).synchronous(); } } diff --git a/modules/gplazma2-oidc/src/main/java/org/dcache/gplazma/oidc/userinfo/QueryUserInfoEndpoint.java b/modules/gplazma2-oidc/src/main/java/org/dcache/gplazma/oidc/userinfo/QueryUserInfoEndpoint.java index 860095fe2af..d9f0134fa14 100644 --- a/modules/gplazma2-oidc/src/main/java/org/dcache/gplazma/oidc/userinfo/QueryUserInfoEndpoint.java +++ b/modules/gplazma2-oidc/src/main/java/org/dcache/gplazma/oidc/userinfo/QueryUserInfoEndpoint.java @@ -17,17 +17,19 @@ */ package org.dcache.gplazma.oidc.userinfo; +import static java.util.Objects.requireNonNull; +import static java.util.stream.Collectors.toMap; +import static org.dcache.gplazma.oidc.PropertiesUtils.asInt; +import static org.dcache.gplazma.util.Preconditions.checkAuthentication; + import com.fasterxml.jackson.databind.JsonNode; import com.fasterxml.jackson.databind.node.JsonNodeType; +import com.github.benmanes.caffeine.cache.AsyncCacheLoader; +import com.github.benmanes.caffeine.cache.AsyncLoadingCache; +import com.github.benmanes.caffeine.cache.Caffeine; import com.google.common.base.Stopwatch; import com.google.common.base.Throwables; -import com.google.common.cache.CacheBuilder; -import com.google.common.cache.CacheLoader; -import com.google.common.cache.LoadingCache; import com.google.common.collect.Streams; -import com.google.common.util.concurrent.Futures; -import com.google.common.util.concurrent.ListenableFuture; -import com.google.common.util.concurrent.ListenableFutureTask; import java.io.IOException; import java.net.URI; import java.net.URISyntaxException; @@ -43,7 +45,9 @@ import java.util.Optional; import java.util.Properties; import java.util.Set; -import java.util.concurrent.ExecutionException; +import java.util.concurrent.CompletableFuture; +import java.util.concurrent.CompletionException; +import java.util.concurrent.Executor; import java.util.concurrent.ExecutorService; import java.util.concurrent.ThreadLocalRandom; import java.util.concurrent.TimeUnit; @@ -59,11 +63,6 @@ import org.slf4j.Logger; import org.slf4j.LoggerFactory; -import static java.util.Objects.requireNonNull; -import static java.util.stream.Collectors.toMap; -import static org.dcache.gplazma.oidc.PropertiesUtils.asInt; -import static org.dcache.gplazma.util.Preconditions.checkAuthentication; - /** * This TokenProcessor queries the user-info endpoint to learn the claims about the user. The * results are cached for a period, to ensure we do not hammer the server and (potentially) to @@ -84,7 +83,7 @@ public class QueryUserInfoEndpoint implements TokenProcessor { private final JsonHttpClient jsonHttpClient; private final ExecutorService executor; - private final LoadingCache> userInfoCache; + private final AsyncLoadingCache> userInfoCache; private final Map providersByIssuer; private final Duration slowLookupThreshold; @@ -119,8 +118,8 @@ public ExtractResult extract(String token) throws AuthenticationException { List allResults; try { - allResults = userInfoCache.get(token); - } catch (ExecutionException e) { + allResults = userInfoCache.synchronous().get(token); + } catch (CompletionException e) { Throwable cause = e.getCause(); Throwables.throwIfInstanceOf(cause, AuthenticationException.class); Throwables.throwIfUnchecked(cause); @@ -169,16 +168,18 @@ public ExtractResult extract(String token) throws AuthenticationException { return new ExtractResult(result.getIdentityProvider(), result.getClaims()); } - private LoadingCache> createUserInfoCache(int size, + private AsyncLoadingCache> createUserInfoCache(int size, int refresh, TimeUnit refreshUnits, int expire, TimeUnit expireUnits) { - return CacheBuilder.newBuilder() + return Caffeine.newBuilder() .maximumSize(size) .refreshAfterWrite(refresh, refreshUnits) .expireAfterWrite(expire, expireUnits) - .build(new CacheLoader>() { - private ListenableFuture> asyncFetch(String token) + .executor(executor) + .buildAsync(new AsyncCacheLoader<>() { + private CompletableFuture> asyncFetch(String token, + Executor executor) throws AuthenticationException { - List> futures = + List> futures = new ArrayList<>(); for (IdentityProvider ip : identityProviders(token)) { @@ -187,40 +188,36 @@ private ListenableFuture> asyncFetch(String token) ip.getName(), describe(token, 20)); } - ListenableFutureTask lookupTask = - ListenableFutureTask.create(() -> queryUserInfo(ip, token)); - executor.execute(lookupTask); + CompletableFuture lookupTask = + CompletableFuture.supplyAsync(() -> queryUserInfo(ip, token), + executor); futures.add(lookupTask); } - - return Futures.allAsList(futures); + return CompletableFuture.allOf(futures.toArray(new CompletableFuture[0])) + .thenApply(v -> futures.stream() + .map(CompletableFuture::join) + .collect(Collectors.toList()) + ); } @Override - public List load(String token) - throws InterruptedException, AuthenticationException { + public CompletableFuture> asyncLoad(String token, + Executor executor) throws Exception { if (LOG.isDebugEnabled()) { LOG.debug("User-info cache miss for token {}", describe(token, 20)); } - try { - return asyncFetch(token).get(); - } catch (ExecutionException e) { - Throwable cause = e.getCause(); - Throwables.throwIfInstanceOf(cause, AuthenticationException.class); - Throwables.throwIfUnchecked(cause); - throw new RuntimeException("Unexpected exception", e); - } + return asyncFetch(token, executor); } @Override - public ListenableFuture> reload(String token, - List results) throws AuthenticationException { + public CompletableFuture> asyncReload(String token, + List results, Executor executor) throws Exception { if (LOG.isDebugEnabled()) { LOG.debug("Refreshing user-info for token {}", describe(token, 20)); } - return asyncFetch(token); + return asyncFetch(token, executor); } }); } diff --git a/modules/srm-client/src/main/java/org/dcache/srm/shell/SrmShell.java b/modules/srm-client/src/main/java/org/dcache/srm/shell/SrmShell.java index 8ea01d05d7d..a83e47d2dcf 100644 --- a/modules/srm-client/src/main/java/org/dcache/srm/shell/SrmShell.java +++ b/modules/srm-client/src/main/java/org/dcache/srm/shell/SrmShell.java @@ -30,15 +30,15 @@ import static org.dcache.util.TimeUtils.TimeUnitFormat.SHORT; import static org.dcache.util.TimeUtils.duration; +import com.github.benmanes.caffeine.cache.CacheLoader; +import com.github.benmanes.caffeine.cache.Caffeine; +import com.github.benmanes.caffeine.cache.LoadingCache; import com.google.common.annotations.VisibleForTesting; import com.google.common.base.CharMatcher; import com.google.common.base.Function; import com.google.common.base.Joiner; import com.google.common.base.Predicate; import com.google.common.base.Throwables; -import com.google.common.cache.CacheBuilder; -import com.google.common.cache.CacheLoader; -import com.google.common.cache.LoadingCache; import com.google.common.collect.HashMultimap; import com.google.common.collect.Lists; import com.google.common.collect.Maps; @@ -90,6 +90,7 @@ import java.util.Optional; import java.util.Set; import java.util.concurrent.Callable; +import java.util.concurrent.CompletionException; import java.util.concurrent.ConcurrentHashMap; import java.util.concurrent.ExecutionException; import java.util.regex.Matcher; @@ -1394,8 +1395,8 @@ private class SrmFilesystemExpander extends AbstractFilesystemExpander { private final boolean verboseList; - private final LoadingCache lsCache = CacheBuilder.newBuilder() - .build(new CacheLoader() { + private final LoadingCache lsCache = Caffeine.newBuilder() + .build(new CacheLoader<>() { @Override public TMetaDataPathDetail[] load(URI key) throws Exception { TMetaDataPathDetail[] contents = fs.list(key, verboseList); @@ -1408,8 +1409,8 @@ public TMetaDataPathDetail[] load(URI key) throws Exception { } }); - private final LoadingCache statCache = CacheBuilder.newBuilder() - .build(new CacheLoader() { + private final LoadingCache statCache = Caffeine.newBuilder() + .build(new CacheLoader<>() { @Override public TMetaDataPathDetail load(File key) throws Exception { return fs.stat(asURI(key)); @@ -1455,7 +1456,7 @@ private URI asURI(File directory) { return path; } - private RuntimeException propagate(ExecutionException e) + private RuntimeException propagate(CompletionException e) throws RemoteException, SRMException, InterruptedException { Throwable cause = e.getCause(); Throwables.throwIfInstanceOf(cause, RemoteException.class); @@ -1468,7 +1469,7 @@ protected TMetaDataPathDetail[] list(File directory) throws RemoteException, SRMException, InterruptedException { try { return lsCache.get(asURI(directory)); - } catch (ExecutionException e) { + } catch (CompletionException e) { throw propagate(e); } } @@ -1482,7 +1483,7 @@ protected TMetaDataPathDetail stat(File item) throws RemoteException, File absPath = resolveAgainstCwd(item); try { return statCache.get(absPath); - } catch (ExecutionException e) { + } catch (CompletionException e) { throw propagate(e); } } diff --git a/modules/srm-server/src/main/java/org/dcache/gridsite/InMemoryCredentialDelegationStore.java b/modules/srm-server/src/main/java/org/dcache/gridsite/InMemoryCredentialDelegationStore.java index e5a84e6ffb1..a121716e331 100644 --- a/modules/srm-server/src/main/java/org/dcache/gridsite/InMemoryCredentialDelegationStore.java +++ b/modules/srm-server/src/main/java/org/dcache/gridsite/InMemoryCredentialDelegationStore.java @@ -20,9 +20,9 @@ import static java.util.concurrent.TimeUnit.MILLISECONDS; import static org.dcache.gridsite.Utilities.assertThat; -import com.google.common.cache.Cache; -import com.google.common.cache.CacheBuilder; -import com.google.common.cache.RemovalListener; +import com.github.benmanes.caffeine.cache.Cache; +import com.github.benmanes.caffeine.cache.Caffeine; +import com.github.benmanes.caffeine.cache.RemovalListener; import org.dcache.delegation.gridsite2.DelegationException; import org.slf4j.Logger; import org.slf4j.LoggerFactory; @@ -48,16 +48,15 @@ public class InMemoryCredentialDelegationStore implements InMemoryCredentialDelegationStore.class); private final RemovalListener - LOG_REMOVALS = notification -> { - DelegationIdentity identity = notification.getKey(); - switch (notification.getCause()) { + LOG_REMOVALS = (key, value, cause) -> { + switch (cause) { case EXPIRED: LOGGER.debug("removing delegation from {}: client took" + - " too long to reply", identity.getDn()); + " too long to reply", key.getDn()); break; case SIZE: LOGGER.debug("removing delegation from {}: too many" + - " on-going delegations", identity.getDn()); + " on-going delegations", key.getDn()); break; } }; @@ -86,7 +85,7 @@ public long getMaxOngoing() { public void start() { - _storage = CacheBuilder.newBuilder(). + _storage = Caffeine.newBuilder(). maximumSize(_maxOngoing). expireAfterWrite(_expireAfter, MILLISECONDS). removalListener(LOG_REMOVALS). diff --git a/pom.xml b/pom.xml index 1f385b2de27..6efe9bb763e 100644 --- a/pom.xml +++ b/pom.xml @@ -254,7 +254,12 @@ com.google.guava guava - 32.0.0-jre + 32.1.2-jre + + + com.github.ben-manes.caffeine + caffeine + 3.1.8 eu.eu-emi.security diff --git a/skel/bin/chimera b/skel/bin/chimera index e8316e02ab8..6694a1ee69a 100755 --- a/skel/bin/chimera +++ b/skel/bin/chimera @@ -6,7 +6,7 @@ lib="$(getProperty dcache.paths.share.lib)" . ${lib}/utils.sh classpath=$(printLimitedClassPath dcache-vehicles dcache-chimera chimera HikariCP javassist \ - guava jline common-cli dcache-common acl-vehicles acl \ + guava caffeine jline common-cli dcache-common acl-vehicles acl \ slf4j-api logback-classic logback-core logback-console-config jcl-over-slf4j \ spring-core spring-beans spring-jdbc spring-tx \ postgresql h2 hsqldb curator-recipes)