diff --git a/.mvn/modernizer/violations.xml b/.mvn/modernizer/violations.xml index 444193e5a1d1..2b3bf519ec6f 100644 --- a/.mvn/modernizer/violations.xml +++ b/.mvn/modernizer/violations.xml @@ -43,6 +43,22 @@ Prefer Math.toIntExact(long) + + com/google/common/cache/CacheBuilder.build:()Lcom/google/common/cache/Cache; + 1.8 + Guava Cache has concurrency issues around invalidation and ongoing loads. Use EvictableCache, EvictableLoadingCache, or SafeCaches to build caches. + See https://github.com/trinodb/trino/issues/10512 for more information and see https://github.com/trinodb/trino/issues/10512#issuecomment-1016221168 + for why Caffeine does not solve the problem. + + + + com/google/common/cache/CacheBuilder.build:(Lcom/google/common/cache/CacheLoader;)Lcom/google/common/cache/LoadingCache; + 1.8 + Guava LoadingCache has concurrency issues around invalidation and ongoing loads. Use EvictableCache, EvictableLoadingCache, or SafeCaches to build caches. + See https://github.com/trinodb/trino/issues/10512 for more information and see https://github.com/trinodb/trino/issues/10512#issuecomment-1016221168 + for why Caffeine does not solve the problem. + + org/testng/Assert.assertEquals:(Ljava/lang/Iterable;Ljava/lang/Iterable;)V 1.8 diff --git a/client/trino-cli/pom.xml b/client/trino-cli/pom.xml index 3b1d1fa730ec..50739e7502d7 100644 --- a/client/trino-cli/pom.xml +++ b/client/trino-cli/pom.xml @@ -76,6 +76,11 @@ antlr4-runtime + + org.gaul + modernizer-maven-annotations + + org.jline jline-reader diff --git a/client/trino-cli/src/main/java/io/trino/cli/TableNameCompleter.java b/client/trino-cli/src/main/java/io/trino/cli/TableNameCompleter.java index 003fd1b09c91..0029f0f07566 100644 --- a/client/trino-cli/src/main/java/io/trino/cli/TableNameCompleter.java +++ b/client/trino-cli/src/main/java/io/trino/cli/TableNameCompleter.java @@ -20,6 +20,7 @@ import com.google.common.util.concurrent.ThreadFactoryBuilder; import io.trino.client.QueryData; import io.trino.client.StatementClient; +import org.gaul.modernizer_maven_annotations.SuppressModernizer; import org.jline.reader.Candidate; import org.jline.reader.Completer; import org.jline.reader.LineReader; @@ -51,12 +52,21 @@ public TableNameCompleter(QueryRunner queryRunner) { this.queryRunner = requireNonNull(queryRunner, "queryRunner session was null!"); - tableCache = CacheBuilder.newBuilder() - .refreshAfterWrite(RELOAD_TIME_MINUTES, TimeUnit.MINUTES) - .build(asyncReloading(CacheLoader.from(this::listTables), executor)); + tableCache = buildUnsafeCache( + CacheBuilder.newBuilder() + .refreshAfterWrite(RELOAD_TIME_MINUTES, TimeUnit.MINUTES), + asyncReloading(CacheLoader.from(this::listTables), executor)); - functionCache = CacheBuilder.newBuilder() - .build(CacheLoader.from(this::listFunctions)); + functionCache = buildUnsafeCache( + CacheBuilder.newBuilder(), + CacheLoader.from(this::listFunctions)); + } + + // TODO extract safe caches implementations to a new module and use SafeCaches.buildNonEvictableCache hereAsyncCache + @SuppressModernizer + private static LoadingCache buildUnsafeCache(CacheBuilder cacheBuilder, CacheLoader cacheLoader) + { + return cacheBuilder.build(cacheLoader); } private List listTables(String schemaName) diff --git a/core/trino-main/pom.xml b/core/trino-main/pom.xml index 09dd8fc2ee7c..9ac55e29fc4e 100644 --- a/core/trino-main/pom.xml +++ b/core/trino-main/pom.xml @@ -299,6 +299,11 @@ 8.4.1 + + org.gaul + modernizer-maven-annotations + + org.jgrapht jgrapht-core diff --git a/core/trino-main/src/main/java/io/trino/execution/FailureInjector.java b/core/trino-main/src/main/java/io/trino/execution/FailureInjector.java index 43b74ce2cbd2..a6af6aac92fb 100644 --- a/core/trino-main/src/main/java/io/trino/execution/FailureInjector.java +++ b/core/trino-main/src/main/java/io/trino/execution/FailureInjector.java @@ -13,9 +13,9 @@ */ package io.trino.execution; -import com.google.common.cache.Cache; import com.google.common.cache.CacheBuilder; import io.airlift.units.Duration; +import io.trino.plugin.base.cache.NonEvictableCache; import io.trino.spi.ErrorCode; import io.trino.spi.ErrorCodeSupplier; import io.trino.spi.ErrorType; @@ -29,6 +29,7 @@ import static com.google.common.base.MoreObjects.toStringHelper; import static com.google.common.base.Preconditions.checkArgument; import static io.trino.execution.FailureInjector.InjectedFailureType.TASK_FAILURE; +import static io.trino.plugin.base.cache.SafeCaches.buildNonEvictableCache; import static io.trino.spi.ErrorType.EXTERNAL; import static io.trino.spi.ErrorType.INSUFFICIENT_RESOURCES; import static io.trino.spi.ErrorType.INTERNAL_ERROR; @@ -40,7 +41,7 @@ public class FailureInjector { public static final String FAILURE_INJECTION_MESSAGE = "This error is injected by the failure injection service"; - private final Cache failures; + private final NonEvictableCache failures; private final Duration requestTimeout; @Inject @@ -53,9 +54,8 @@ public FailureInjector(FailureInjectionConfig config) public FailureInjector(Duration expirationPeriod, Duration requestTimeout) { - failures = CacheBuilder.newBuilder() - .expireAfterWrite(expirationPeriod.toMillis(), MILLISECONDS) - .build(); + failures = buildNonEvictableCache(CacheBuilder.newBuilder() + .expireAfterWrite(expirationPeriod.toMillis(), MILLISECONDS)); this.requestTimeout = requireNonNull(requestTimeout, "requestTimeout is null"); } diff --git a/core/trino-main/src/main/java/io/trino/execution/SqlTaskManager.java b/core/trino-main/src/main/java/io/trino/execution/SqlTaskManager.java index 143841d5071c..564db52e75b4 100644 --- a/core/trino-main/src/main/java/io/trino/execution/SqlTaskManager.java +++ b/core/trino-main/src/main/java/io/trino/execution/SqlTaskManager.java @@ -16,7 +16,6 @@ import com.google.common.annotations.VisibleForTesting; import com.google.common.cache.CacheBuilder; import com.google.common.cache.CacheLoader; -import com.google.common.cache.LoadingCache; import com.google.common.collect.ImmutableList; import com.google.common.util.concurrent.ListenableFuture; import io.airlift.concurrent.ThreadPoolExecutorMBean; @@ -41,6 +40,7 @@ import io.trino.memory.MemoryPoolAssignmentsRequest; import io.trino.memory.NodeMemoryConfig; import io.trino.memory.QueryContext; +import io.trino.plugin.base.cache.NonEvictableLoadingCache; import io.trino.spi.QueryId; import io.trino.spi.TrinoException; import io.trino.spi.VersionEmbedder; @@ -81,6 +81,7 @@ import static io.trino.execution.SqlTask.createSqlTask; import static io.trino.memory.LocalMemoryManager.GENERAL_POOL; import static io.trino.memory.LocalMemoryManager.RESERVED_POOL; +import static io.trino.plugin.base.cache.SafeCaches.buildNonEvictableCache; import static io.trino.spi.StandardErrorCode.ABANDONED_TASK; import static io.trino.spi.StandardErrorCode.SERVER_SHUTTING_DOWN; import static java.lang.Math.min; @@ -105,8 +106,8 @@ public class SqlTaskManager private final Duration clientTimeout; private final LocalMemoryManager localMemoryManager; - private final LoadingCache queryContexts; - private final LoadingCache tasks; + private final NonEvictableLoadingCache queryContexts; + private final NonEvictableLoadingCache tasks; private final SqlTaskIoStats cachedStats = new SqlTaskIoStats(); private final SqlTaskIoStats finishedTaskStats = new SqlTaskIoStats(); @@ -165,10 +166,10 @@ public SqlTaskManager( queryMaxMemoryPerNode = maxQueryMemoryPerNode.toBytes(); queryMaxTotalMemoryPerNode = maxQueryTotalMemoryPerNode.toBytes(); - queryContexts = CacheBuilder.newBuilder().weakValues().build(CacheLoader.from( + queryContexts = buildNonEvictableCache(CacheBuilder.newBuilder().weakValues(), CacheLoader.from( queryId -> createQueryContext(queryId, localMemoryManager, localSpillManager, gcMonitor, maxQueryMemoryPerNode, maxQueryTotalMemoryPerNode, queryMaxMemoryPerTask, maxQuerySpillPerNode))); - tasks = CacheBuilder.newBuilder().build(CacheLoader.from( + tasks = buildNonEvictableCache(CacheBuilder.newBuilder(), CacheLoader.from( taskId -> createSqlTask( taskId, locationFactory.createLocalTaskLocation(taskId), diff --git a/core/trino-main/src/main/java/io/trino/execution/scheduler/TopologyAwareNodeSelectorFactory.java b/core/trino-main/src/main/java/io/trino/execution/scheduler/TopologyAwareNodeSelectorFactory.java index 1824a85b935e..e8efe86db40f 100644 --- a/core/trino-main/src/main/java/io/trino/execution/scheduler/TopologyAwareNodeSelectorFactory.java +++ b/core/trino-main/src/main/java/io/trino/execution/scheduler/TopologyAwareNodeSelectorFactory.java @@ -14,7 +14,6 @@ package io.trino.execution.scheduler; import com.google.common.base.Suppliers; -import com.google.common.cache.Cache; import com.google.common.cache.CacheBuilder; import com.google.common.collect.ImmutableList; import com.google.common.collect.ImmutableList.Builder; @@ -27,6 +26,7 @@ import io.trino.execution.NodeTaskMap; import io.trino.metadata.InternalNode; import io.trino.metadata.InternalNodeManager; +import io.trino.plugin.base.cache.NonEvictableCache; import io.trino.spi.HostAddress; import io.trino.spi.SplitWeight; @@ -46,6 +46,7 @@ import static com.google.common.collect.ImmutableSet.toImmutableSet; import static io.trino.SystemSessionProperties.getMaxUnacknowledgedSplitsPerTask; import static io.trino.metadata.NodeState.ACTIVE; +import static io.trino.plugin.base.cache.SafeCaches.buildNonEvictableCache; import static java.util.Objects.requireNonNull; public class TopologyAwareNodeSelectorFactory @@ -53,9 +54,9 @@ public class TopologyAwareNodeSelectorFactory { private static final Logger LOG = Logger.get(TopologyAwareNodeSelectorFactory.class); - private final Cache inaccessibleNodeLogCache = CacheBuilder.newBuilder() - .expireAfterWrite(30, TimeUnit.SECONDS) - .build(); + private final NonEvictableCache inaccessibleNodeLogCache = buildNonEvictableCache( + CacheBuilder.newBuilder() + .expireAfterWrite(30, TimeUnit.SECONDS)); private final NetworkTopology networkTopology; private final InternalNodeManager nodeManager; diff --git a/core/trino-main/src/main/java/io/trino/execution/scheduler/UniformNodeSelectorFactory.java b/core/trino-main/src/main/java/io/trino/execution/scheduler/UniformNodeSelectorFactory.java index 53725a5abc18..b7eec9f8ed78 100644 --- a/core/trino-main/src/main/java/io/trino/execution/scheduler/UniformNodeSelectorFactory.java +++ b/core/trino-main/src/main/java/io/trino/execution/scheduler/UniformNodeSelectorFactory.java @@ -15,7 +15,6 @@ import com.google.common.annotations.VisibleForTesting; import com.google.common.base.Suppliers; -import com.google.common.cache.Cache; import com.google.common.cache.CacheBuilder; import com.google.common.collect.ImmutableSetMultimap; import io.airlift.log.Logger; @@ -25,6 +24,7 @@ import io.trino.execution.NodeTaskMap; import io.trino.metadata.InternalNode; import io.trino.metadata.InternalNodeManager; +import io.trino.plugin.base.cache.NonEvictableCache; import io.trino.spi.HostAddress; import io.trino.spi.SplitWeight; @@ -42,6 +42,7 @@ import static com.google.common.collect.ImmutableSet.toImmutableSet; import static io.trino.SystemSessionProperties.getMaxUnacknowledgedSplitsPerTask; import static io.trino.metadata.NodeState.ACTIVE; +import static io.trino.plugin.base.cache.SafeCaches.buildNonEvictableCache; import static java.util.Objects.requireNonNull; import static java.util.concurrent.TimeUnit.MILLISECONDS; import static java.util.concurrent.TimeUnit.SECONDS; @@ -51,9 +52,9 @@ public class UniformNodeSelectorFactory { private static final Logger LOG = Logger.get(UniformNodeSelectorFactory.class); - private final Cache inaccessibleNodeLogCache = CacheBuilder.newBuilder() - .expireAfterWrite(30, TimeUnit.SECONDS) - .build(); + private final NonEvictableCache inaccessibleNodeLogCache = buildNonEvictableCache( + CacheBuilder.newBuilder() + .expireAfterWrite(30, TimeUnit.SECONDS)); private final InternalNodeManager nodeManager; private final int minCandidates; diff --git a/core/trino-main/src/main/java/io/trino/metadata/AbstractTypedJacksonModule.java b/core/trino-main/src/main/java/io/trino/metadata/AbstractTypedJacksonModule.java index d6a946f183f0..b99f6d2a9602 100644 --- a/core/trino-main/src/main/java/io/trino/metadata/AbstractTypedJacksonModule.java +++ b/core/trino-main/src/main/java/io/trino/metadata/AbstractTypedJacksonModule.java @@ -34,8 +34,9 @@ import com.fasterxml.jackson.databind.ser.BeanSerializerFactory; import com.fasterxml.jackson.databind.ser.std.StdSerializer; import com.fasterxml.jackson.databind.type.TypeFactory; -import com.google.common.cache.Cache; import com.google.common.cache.CacheBuilder; +import io.trino.plugin.base.cache.NonEvictableCache; +import io.trino.plugin.base.cache.SafeCaches; import java.io.IOException; import java.util.concurrent.ExecutionException; @@ -92,7 +93,7 @@ private static class InternalTypeSerializer extends StdSerializer { private final TypeSerializer typeSerializer; - private final Cache, JsonSerializer> serializerCache = CacheBuilder.newBuilder().build(); + private final NonEvictableCache, JsonSerializer> serializerCache = SafeCaches.buildNonEvictableCache(CacheBuilder.newBuilder()); public InternalTypeSerializer(Class baseClass, TypeIdResolver typeIdResolver) { diff --git a/core/trino-main/src/main/java/io/trino/metadata/FunctionRegistry.java b/core/trino-main/src/main/java/io/trino/metadata/FunctionRegistry.java index dc8218116b17..67aaf31168ac 100644 --- a/core/trino-main/src/main/java/io/trino/metadata/FunctionRegistry.java +++ b/core/trino-main/src/main/java/io/trino/metadata/FunctionRegistry.java @@ -13,7 +13,6 @@ */ package io.trino.metadata; -import com.google.common.cache.Cache; import com.google.common.cache.CacheBuilder; import com.google.common.collect.ImmutableList; import com.google.common.collect.ImmutableListMultimap; @@ -237,6 +236,7 @@ import io.trino.operator.window.RowNumberFunction; import io.trino.operator.window.SqlWindowFunction; import io.trino.operator.window.WindowFunctionSupplier; +import io.trino.plugin.base.cache.NonEvictableCache; import io.trino.spi.TrinoException; import io.trino.spi.block.BlockEncodingSerde; import io.trino.spi.function.InvocationConvention; @@ -341,6 +341,7 @@ import static io.trino.operator.scalar.TryCastFunction.TRY_CAST; import static io.trino.operator.scalar.ZipFunction.ZIP_FUNCTIONS; import static io.trino.operator.scalar.ZipWithFunction.ZIP_WITH_FUNCTION; +import static io.trino.plugin.base.cache.SafeCaches.buildNonEvictableCache; import static io.trino.type.DecimalCasts.BIGINT_TO_DECIMAL_CAST; import static io.trino.type.DecimalCasts.BOOLEAN_TO_DECIMAL_CAST; import static io.trino.type.DecimalCasts.DECIMAL_TO_BIGINT_CAST; @@ -380,9 +381,9 @@ @ThreadSafe public class FunctionRegistry { - private final Cache specializedScalarCache; - private final Cache specializedAggregationCache; - private final Cache specializedWindowCache; + private final NonEvictableCache specializedScalarCache; + private final NonEvictableCache specializedAggregationCache; + private final NonEvictableCache specializedWindowCache; private volatile FunctionMap functions = new FunctionMap(); public FunctionRegistry( @@ -398,20 +399,17 @@ public FunctionRegistry( // with generated classes and/or dynamically-created MethodHandles. // This might also mitigate problems like deoptimization storm or unintended interpreted execution. - specializedScalarCache = CacheBuilder.newBuilder() + specializedScalarCache = buildNonEvictableCache(CacheBuilder.newBuilder() .maximumSize(1000) - .expireAfterWrite(1, HOURS) - .build(); + .expireAfterWrite(1, HOURS)); - specializedAggregationCache = CacheBuilder.newBuilder() + specializedAggregationCache = buildNonEvictableCache(CacheBuilder.newBuilder() .maximumSize(1000) - .expireAfterWrite(1, HOURS) - .build(); + .expireAfterWrite(1, HOURS)); - specializedWindowCache = CacheBuilder.newBuilder() + specializedWindowCache = buildNonEvictableCache(CacheBuilder.newBuilder() .maximumSize(1000) - .expireAfterWrite(1, HOURS) - .build(); + .expireAfterWrite(1, HOURS)); FunctionListBuilder builder = new FunctionListBuilder() .window(RowNumberFunction.class) diff --git a/core/trino-main/src/main/java/io/trino/metadata/MetadataManager.java b/core/trino-main/src/main/java/io/trino/metadata/MetadataManager.java index 1162bfd1705b..89abd8c9dc40 100644 --- a/core/trino-main/src/main/java/io/trino/metadata/MetadataManager.java +++ b/core/trino-main/src/main/java/io/trino/metadata/MetadataManager.java @@ -14,7 +14,6 @@ package io.trino.metadata; import com.google.common.annotations.VisibleForTesting; -import com.google.common.cache.Cache; import com.google.common.cache.CacheBuilder; import com.google.common.collect.ImmutableList; import com.google.common.collect.ImmutableMap; @@ -32,6 +31,7 @@ import io.trino.metadata.ResolvedFunction.ResolvedFunctionDecoder; import io.trino.operator.aggregation.AggregationMetadata; import io.trino.operator.window.WindowFunctionSupplier; +import io.trino.plugin.base.cache.NonEvictableCache; import io.trino.spi.QueryId; import io.trino.spi.TrinoException; import io.trino.spi.block.Block; @@ -147,6 +147,7 @@ import static io.trino.metadata.RedirectionAwareTableHandle.withRedirectionTo; import static io.trino.metadata.Signature.mangleOperatorName; import static io.trino.metadata.SignatureBinder.applyBoundVariables; +import static io.trino.plugin.base.cache.SafeCaches.buildNonEvictableCache; import static io.trino.spi.StandardErrorCode.FUNCTION_IMPLEMENTATION_ERROR; import static io.trino.spi.StandardErrorCode.FUNCTION_IMPLEMENTATION_MISSING; import static io.trino.spi.StandardErrorCode.FUNCTION_NOT_FOUND; @@ -180,8 +181,8 @@ public final class MetadataManager private final ResolvedFunctionDecoder functionDecoder; - private final Cache operatorCache; - private final Cache coercionCache; + private final NonEvictableCache operatorCache; + private final NonEvictableCache coercionCache; @Inject public MetadataManager( @@ -204,13 +205,8 @@ public MetadataManager( functionDecoder = new ResolvedFunctionDecoder(typeManager::getType); - operatorCache = CacheBuilder.newBuilder() - .maximumSize(1000) - .build(); - - coercionCache = CacheBuilder.newBuilder() - .maximumSize(1000) - .build(); + operatorCache = buildNonEvictableCache(CacheBuilder.newBuilder().maximumSize(1000)); + coercionCache = buildNonEvictableCache(CacheBuilder.newBuilder().maximumSize(1000)); } public static MetadataManager createTestMetadataManager() diff --git a/core/trino-main/src/main/java/io/trino/metadata/TypeRegistry.java b/core/trino-main/src/main/java/io/trino/metadata/TypeRegistry.java index 3898bf0b3c5e..4aa5df08681c 100644 --- a/core/trino-main/src/main/java/io/trino/metadata/TypeRegistry.java +++ b/core/trino-main/src/main/java/io/trino/metadata/TypeRegistry.java @@ -14,13 +14,13 @@ package io.trino.metadata; import com.google.common.base.Joiner; -import com.google.common.cache.Cache; import com.google.common.cache.CacheBuilder; import com.google.common.collect.HashMultimap; import com.google.common.collect.ImmutableList; import com.google.common.collect.Multimap; import com.google.common.util.concurrent.UncheckedExecutionException; import io.trino.FeaturesConfig; +import io.trino.plugin.base.cache.NonEvictableCache; import io.trino.spi.function.OperatorType; import io.trino.spi.type.ParametricType; import io.trino.spi.type.Type; @@ -53,6 +53,7 @@ import static com.google.common.base.Preconditions.checkArgument; import static com.google.common.base.Preconditions.checkState; import static com.google.common.base.Throwables.throwIfUnchecked; +import static io.trino.plugin.base.cache.SafeCaches.buildNonEvictableCache; import static io.trino.spi.function.InvocationConvention.InvocationArgumentConvention.BOXED_NULLABLE; import static io.trino.spi.function.InvocationConvention.InvocationArgumentConvention.NEVER_NULL; import static io.trino.spi.function.InvocationConvention.InvocationReturnConvention.FAIL_ON_NULL; @@ -112,7 +113,7 @@ public final class TypeRegistry private final ConcurrentMap types = new ConcurrentHashMap<>(); private final ConcurrentMap parametricTypes = new ConcurrentHashMap<>(); - private final Cache parametricTypeCache; + private final NonEvictableCache parametricTypeCache; private final TypeManager typeManager; private final TypeOperators typeOperators; @@ -164,9 +165,7 @@ public TypeRegistry(TypeOperators typeOperators, FeaturesConfig featuresConfig) addParametricType(TIME); addParametricType(TIME_WITH_TIME_ZONE); - parametricTypeCache = CacheBuilder.newBuilder() - .maximumSize(1000) - .build(); + parametricTypeCache = buildNonEvictableCache(CacheBuilder.newBuilder().maximumSize(1000)); typeManager = new InternalTypeManager(this, typeOperators); diff --git a/core/trino-main/src/main/java/io/trino/server/security/oauth2/OAuth2TokenExchange.java b/core/trino-main/src/main/java/io/trino/server/security/oauth2/OAuth2TokenExchange.java index 335f7d6b8ea4..9ec3a952be50 100644 --- a/core/trino-main/src/main/java/io/trino/server/security/oauth2/OAuth2TokenExchange.java +++ b/core/trino-main/src/main/java/io/trino/server/security/oauth2/OAuth2TokenExchange.java @@ -20,6 +20,7 @@ import com.google.common.util.concurrent.ListenableFuture; import com.google.common.util.concurrent.SettableFuture; import io.airlift.units.Duration; +import org.gaul.modernizer_maven_annotations.SuppressModernizer; import javax.annotation.PreDestroy; import javax.inject.Inject; @@ -50,10 +51,11 @@ public class OAuth2TokenExchange public OAuth2TokenExchange(OAuth2Config config) { long challengeTimeoutMillis = config.getChallengeTimeout().toMillis(); - this.cache = CacheBuilder.newBuilder() - .expireAfterWrite(challengeTimeoutMillis + (MAX_POLL_TIME.toMillis() * 10), MILLISECONDS) - .>removalListener(notification -> notification.getValue().set(TOKEN_POLL_TIMED_OUT)) - .build(new CacheLoader<>() + this.cache = buildUnsafeCache( + CacheBuilder.newBuilder() + .expireAfterWrite(challengeTimeoutMillis + (MAX_POLL_TIME.toMillis() * 10), MILLISECONDS) + .removalListener(notification -> notification.getValue().set(TOKEN_POLL_TIMED_OUT)), + new CacheLoader<>() { @Override public SettableFuture load(String authIdHash) @@ -66,6 +68,13 @@ public SettableFuture load(String authIdHash) }); } + // TODO (https://github.com/trinodb/trino/issues/10685) Investigate cache correctness with respect to invalidation + @SuppressModernizer + private static LoadingCache buildUnsafeCache(CacheBuilder cacheBuilder, CacheLoader cacheLoader) + { + return cacheBuilder.build(cacheLoader); + } + @PreDestroy public void stop() { diff --git a/core/trino-main/src/main/java/io/trino/spiller/FileSingleStreamSpillerFactory.java b/core/trino-main/src/main/java/io/trino/spiller/FileSingleStreamSpillerFactory.java index 409ab63c6253..43a5fd86129d 100644 --- a/core/trino-main/src/main/java/io/trino/spiller/FileSingleStreamSpillerFactory.java +++ b/core/trino-main/src/main/java/io/trino/spiller/FileSingleStreamSpillerFactory.java @@ -16,7 +16,6 @@ import com.google.common.annotations.VisibleForTesting; import com.google.common.cache.CacheBuilder; import com.google.common.cache.CacheLoader; -import com.google.common.cache.LoadingCache; import com.google.common.collect.ImmutableList; import com.google.common.util.concurrent.ListeningExecutorService; import com.google.inject.Inject; @@ -26,6 +25,7 @@ import io.trino.execution.buffer.PagesSerdeFactory; import io.trino.memory.context.LocalMemoryContext; import io.trino.operator.SpillContext; +import io.trino.plugin.base.cache.NonKeyEvictableLoadingCache; import io.trino.spi.TrinoException; import io.trino.spi.block.BlockEncodingSerde; import io.trino.spi.type.Type; @@ -44,6 +44,7 @@ import static com.google.common.util.concurrent.MoreExecutors.listeningDecorator; import static io.airlift.concurrent.Threads.daemonThreadsNamed; import static io.trino.FeaturesConfig.SPILLER_SPILL_PATH; +import static io.trino.plugin.base.cache.SafeCaches.buildNonEvictableCacheWithWeakInvalidateAll; import static io.trino.spi.StandardErrorCode.OUT_OF_SPILL_SPACE; import static java.lang.String.format; import static java.nio.file.Files.createDirectories; @@ -77,7 +78,7 @@ public class FileSingleStreamSpillerFactory private final double maxUsedSpaceThreshold; private final boolean spillEncryptionEnabled; private int roundRobinIndex; - private final LoadingCache spillPathHealthCache; + private final NonKeyEvictableLoadingCache spillPathHealthCache; @Inject public FileSingleStreamSpillerFactory(BlockEncodingSerde blockEncodingSerde, SpillerStats spillerStats, FeaturesConfig featuresConfig, NodeSpillConfig nodeSpillConfig) @@ -124,9 +125,10 @@ public FileSingleStreamSpillerFactory( this.spillEncryptionEnabled = spillEncryptionEnabled; this.roundRobinIndex = 0; - this.spillPathHealthCache = CacheBuilder.newBuilder() - .expireAfterWrite(SPILL_PATH_HEALTH_EXPIRY_INTERVAL) - .build(CacheLoader.from(path -> isAccessible(path) && isSeeminglyHealthy(path))); + this.spillPathHealthCache = buildNonEvictableCacheWithWeakInvalidateAll( + CacheBuilder.newBuilder() + .expireAfterWrite(SPILL_PATH_HEALTH_EXPIRY_INTERVAL), + CacheLoader.from(path -> isAccessible(path) && isSeeminglyHealthy(path))); } @PostConstruct diff --git a/core/trino-main/src/main/java/io/trino/sql/gen/ExpressionCompiler.java b/core/trino-main/src/main/java/io/trino/sql/gen/ExpressionCompiler.java index af95dac084d4..73b9b3b74233 100644 --- a/core/trino-main/src/main/java/io/trino/sql/gen/ExpressionCompiler.java +++ b/core/trino-main/src/main/java/io/trino/sql/gen/ExpressionCompiler.java @@ -16,7 +16,6 @@ import com.google.common.annotations.VisibleForTesting; import com.google.common.cache.CacheBuilder; import com.google.common.cache.CacheLoader; -import com.google.common.cache.LoadingCache; import com.google.common.collect.ImmutableList; import io.airlift.bytecode.ClassDefinition; import io.airlift.bytecode.CompilationException; @@ -26,6 +25,7 @@ import io.trino.operator.project.PageFilter; import io.trino.operator.project.PageProcessor; import io.trino.operator.project.PageProjection; +import io.trino.plugin.base.cache.NonEvictableLoadingCache; import io.trino.spi.TrinoException; import io.trino.sql.relational.RowExpression; import org.weakref.jmx.Managed; @@ -45,6 +45,7 @@ import static io.airlift.bytecode.Access.PUBLIC; import static io.airlift.bytecode.Access.a; import static io.airlift.bytecode.ParameterizedType.type; +import static io.trino.plugin.base.cache.SafeCaches.buildNonEvictableCache; import static io.trino.spi.StandardErrorCode.COMPILER_ERROR; import static io.trino.spi.type.BooleanType.BOOLEAN; import static io.trino.sql.gen.BytecodeUtils.invoke; @@ -56,7 +57,7 @@ public class ExpressionCompiler { private final PageFunctionCompiler pageFunctionCompiler; - private final LoadingCache> cursorProcessors; + private final NonEvictableLoadingCache> cursorProcessors; private final CacheStatsMBean cacheStatsMBean; @Inject @@ -64,10 +65,10 @@ public ExpressionCompiler(Metadata metadata, PageFunctionCompiler pageFunctionCo { requireNonNull(metadata, "metadata is null"); this.pageFunctionCompiler = requireNonNull(pageFunctionCompiler, "pageFunctionCompiler is null"); - this.cursorProcessors = CacheBuilder.newBuilder() - .recordStats() - .maximumSize(1000) - .build(CacheLoader.from(key -> compile(key.getFilter(), key.getProjections(), new CursorProcessorCompiler(metadata), CursorProcessor.class))); + this.cursorProcessors = buildNonEvictableCache(CacheBuilder.newBuilder() + .recordStats() + .maximumSize(1000), + CacheLoader.from(key -> compile(key.getFilter(), key.getProjections(), new CursorProcessorCompiler(metadata), CursorProcessor.class))); this.cacheStatsMBean = new CacheStatsMBean(cursorProcessors); } diff --git a/core/trino-main/src/main/java/io/trino/sql/gen/JoinCompiler.java b/core/trino-main/src/main/java/io/trino/sql/gen/JoinCompiler.java index e3f525831bfa..589f8ec6797b 100644 --- a/core/trino-main/src/main/java/io/trino/sql/gen/JoinCompiler.java +++ b/core/trino-main/src/main/java/io/trino/sql/gen/JoinCompiler.java @@ -15,7 +15,6 @@ import com.google.common.cache.CacheBuilder; import com.google.common.cache.CacheLoader; -import com.google.common.cache.LoadingCache; import com.google.common.collect.ImmutableList; import io.airlift.bytecode.BytecodeBlock; import io.airlift.bytecode.BytecodeNode; @@ -40,6 +39,7 @@ import io.trino.operator.join.JoinHashSupplier; import io.trino.operator.join.LookupSourceSupplier; import io.trino.operator.join.PagesHash; +import io.trino.plugin.base.cache.NonEvictableLoadingCache; import io.trino.spi.Page; import io.trino.spi.PageBuilder; import io.trino.spi.block.Block; @@ -81,6 +81,7 @@ import static io.airlift.bytecode.expression.BytecodeExpressions.invokeDynamic; import static io.airlift.bytecode.expression.BytecodeExpressions.newInstance; import static io.airlift.bytecode.expression.BytecodeExpressions.notEqual; +import static io.trino.plugin.base.cache.SafeCaches.buildNonEvictableCache; import static io.trino.spi.function.InvocationConvention.InvocationArgumentConvention.BLOCK_POSITION; import static io.trino.spi.function.InvocationConvention.InvocationReturnConvention.FAIL_ON_NULL; import static io.trino.spi.function.InvocationConvention.InvocationReturnConvention.NULLABLE_RETURN; @@ -95,16 +96,18 @@ public class JoinCompiler { private final TypeOperators typeOperators; - private final LoadingCache lookupSourceFactories = CacheBuilder.newBuilder() - .recordStats() - .maximumSize(1000) - .build(CacheLoader.from(key -> + private final NonEvictableLoadingCache lookupSourceFactories = buildNonEvictableCache( + CacheBuilder.newBuilder() + .recordStats() + .maximumSize(1000), + CacheLoader.from(key -> internalCompileLookupSourceFactory(key.getTypes(), key.getOutputChannels(), key.getJoinChannels(), key.getSortChannel()))); - private final LoadingCache> hashStrategies = CacheBuilder.newBuilder() - .recordStats() - .maximumSize(1000) - .build(CacheLoader.from(key -> + private final NonEvictableLoadingCache> hashStrategies = buildNonEvictableCache( + CacheBuilder.newBuilder() + .recordStats() + .maximumSize(1000), + CacheLoader.from(key -> internalCompileHashStrategy(key.getTypes(), key.getOutputChannels(), key.getJoinChannels(), key.getSortChannel()))); @Inject diff --git a/core/trino-main/src/main/java/io/trino/sql/gen/JoinFilterFunctionCompiler.java b/core/trino-main/src/main/java/io/trino/sql/gen/JoinFilterFunctionCompiler.java index 30d0f545bf08..5639ba605a98 100644 --- a/core/trino-main/src/main/java/io/trino/sql/gen/JoinFilterFunctionCompiler.java +++ b/core/trino-main/src/main/java/io/trino/sql/gen/JoinFilterFunctionCompiler.java @@ -15,7 +15,6 @@ import com.google.common.cache.CacheBuilder; import com.google.common.cache.CacheLoader; -import com.google.common.cache.LoadingCache; import com.google.common.collect.ImmutableList; import com.google.common.collect.ImmutableMap; import com.google.common.collect.ImmutableSet; @@ -34,6 +33,7 @@ import io.trino.operator.join.InternalJoinFilterFunction; import io.trino.operator.join.JoinFilterFunction; import io.trino.operator.join.StandardJoinFilterFunction; +import io.trino.plugin.base.cache.NonEvictableLoadingCache; import io.trino.spi.Page; import io.trino.spi.block.Block; import io.trino.spi.connector.ConnectorSession; @@ -62,6 +62,7 @@ import static io.airlift.bytecode.ParameterizedType.type; import static io.airlift.bytecode.expression.BytecodeExpressions.constantFalse; import static io.airlift.bytecode.expression.BytecodeExpressions.constantInt; +import static io.trino.plugin.base.cache.SafeCaches.buildNonEvictableCache; import static io.trino.sql.gen.BytecodeUtils.invoke; import static io.trino.sql.gen.LambdaExpressionExtractor.extractLambdaExpressions; import static io.trino.util.CompilerUtils.defineClass; @@ -78,10 +79,11 @@ public JoinFilterFunctionCompiler(Metadata metadata) this.metadata = metadata; } - private final LoadingCache joinFilterFunctionFactories = CacheBuilder.newBuilder() - .recordStats() - .maximumSize(1000) - .build(CacheLoader.from(key -> internalCompileFilterFunctionFactory(key.getFilter(), key.getLeftBlocksSize()))); + private final NonEvictableLoadingCache joinFilterFunctionFactories = buildNonEvictableCache( + CacheBuilder.newBuilder() + .recordStats() + .maximumSize(1000), + CacheLoader.from(key -> internalCompileFilterFunctionFactory(key.getFilter(), key.getLeftBlocksSize()))); @Managed @Nested diff --git a/core/trino-main/src/main/java/io/trino/sql/gen/OrderingCompiler.java b/core/trino-main/src/main/java/io/trino/sql/gen/OrderingCompiler.java index 728984138673..f2aa2d090c81 100644 --- a/core/trino-main/src/main/java/io/trino/sql/gen/OrderingCompiler.java +++ b/core/trino-main/src/main/java/io/trino/sql/gen/OrderingCompiler.java @@ -16,7 +16,6 @@ import com.google.common.annotations.VisibleForTesting; import com.google.common.cache.CacheBuilder; import com.google.common.cache.CacheLoader; -import com.google.common.cache.LoadingCache; import com.google.common.collect.ImmutableList; import io.airlift.bytecode.BytecodeBlock; import io.airlift.bytecode.ClassDefinition; @@ -35,6 +34,7 @@ import io.trino.operator.SimplePageWithPositionComparator; import io.trino.operator.SimplePagesIndexComparator; import io.trino.operator.SyntheticAddress; +import io.trino.plugin.base.cache.NonEvictableLoadingCache; import io.trino.spi.Page; import io.trino.spi.block.Block; import io.trino.spi.connector.SortOrder; @@ -59,6 +59,7 @@ import static io.airlift.bytecode.expression.BytecodeExpressions.constantInt; import static io.airlift.bytecode.expression.BytecodeExpressions.invokeDynamic; import static io.airlift.bytecode.expression.BytecodeExpressions.invokeStatic; +import static io.trino.plugin.base.cache.SafeCaches.buildNonEvictableCache; import static io.trino.spi.function.InvocationConvention.InvocationArgumentConvention.BLOCK_POSITION; import static io.trino.spi.function.InvocationConvention.InvocationReturnConvention.FAIL_ON_NULL; import static io.trino.spi.function.InvocationConvention.simpleConvention; @@ -71,15 +72,17 @@ public class OrderingCompiler { private static final Logger log = Logger.get(OrderingCompiler.class); - private final LoadingCache pagesIndexOrderings = CacheBuilder.newBuilder() - .recordStats() - .maximumSize(1000) - .build(CacheLoader.from(key -> internalCompilePagesIndexOrdering(key.getSortTypes(), key.getSortChannels(), key.getSortOrders()))); - - private final LoadingCache pageWithPositionComparators = CacheBuilder.newBuilder() - .recordStats() - .maximumSize(1000) - .build(CacheLoader.from(key -> internalCompilePageWithPositionComparator(key.getSortTypes(), key.getSortChannels(), key.getSortOrders()))); + private final NonEvictableLoadingCache pagesIndexOrderings = buildNonEvictableCache( + CacheBuilder.newBuilder() + .recordStats() + .maximumSize(1000), + CacheLoader.from(key -> internalCompilePagesIndexOrdering(key.getSortTypes(), key.getSortChannels(), key.getSortOrders()))); + + private final NonEvictableLoadingCache pageWithPositionComparators = buildNonEvictableCache( + CacheBuilder.newBuilder() + .recordStats() + .maximumSize(1000), + CacheLoader.from(key -> internalCompilePageWithPositionComparator(key.getSortTypes(), key.getSortChannels(), key.getSortOrders()))); private final TypeOperators typeOperators; diff --git a/core/trino-main/src/main/java/io/trino/sql/gen/PageFunctionCompiler.java b/core/trino-main/src/main/java/io/trino/sql/gen/PageFunctionCompiler.java index 586dfa1c05d3..52dd8f4e776f 100644 --- a/core/trino-main/src/main/java/io/trino/sql/gen/PageFunctionCompiler.java +++ b/core/trino-main/src/main/java/io/trino/sql/gen/PageFunctionCompiler.java @@ -16,7 +16,6 @@ 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.ImmutableList; import com.google.common.collect.ImmutableMap; import com.google.common.collect.ImmutableSet; @@ -42,6 +41,7 @@ import io.trino.operator.project.PageFilter; import io.trino.operator.project.PageProjection; import io.trino.operator.project.SelectedPositions; +import io.trino.plugin.base.cache.NonEvictableLoadingCache; import io.trino.spi.Page; import io.trino.spi.TrinoException; import io.trino.spi.block.Block; @@ -88,6 +88,7 @@ import static io.airlift.bytecode.expression.BytecodeExpressions.newArray; import static io.airlift.bytecode.expression.BytecodeExpressions.not; import static io.trino.operator.project.PageFieldsToInputParametersRewriter.rewritePageFieldsToInputParameters; +import static io.trino.plugin.base.cache.SafeCaches.buildNonEvictableCache; import static io.trino.spi.StandardErrorCode.COMPILER_ERROR; import static io.trino.sql.gen.BytecodeUtils.generateWrite; import static io.trino.sql.gen.BytecodeUtils.invoke; @@ -102,8 +103,8 @@ public class PageFunctionCompiler { private final Metadata metadata; - private final LoadingCache> projectionCache; - private final LoadingCache> filterCache; + private final NonEvictableLoadingCache> projectionCache; + private final NonEvictableLoadingCache> filterCache; private final CacheStatsMBean projectionCacheStats; private final CacheStatsMBean filterCacheStats; @@ -119,10 +120,11 @@ public PageFunctionCompiler(Metadata metadata, int expressionCacheSize) this.metadata = requireNonNull(metadata, "metadata is null"); if (expressionCacheSize > 0) { - projectionCache = CacheBuilder.newBuilder() - .recordStats() - .maximumSize(expressionCacheSize) - .build(CacheLoader.from(projection -> compileProjectionInternal(projection, Optional.empty()))); + projectionCache = buildNonEvictableCache( + CacheBuilder.newBuilder() + .recordStats() + .maximumSize(expressionCacheSize), + CacheLoader.from(projection -> compileProjectionInternal(projection, Optional.empty()))); projectionCacheStats = new CacheStatsMBean(projectionCache); } else { @@ -131,10 +133,11 @@ public PageFunctionCompiler(Metadata metadata, int expressionCacheSize) } if (expressionCacheSize > 0) { - filterCache = CacheBuilder.newBuilder() - .recordStats() - .maximumSize(expressionCacheSize) - .build(CacheLoader.from(filter -> compileFilterInternal(filter, Optional.empty()))); + filterCache = buildNonEvictableCache( + CacheBuilder.newBuilder() + .recordStats() + .maximumSize(expressionCacheSize), + CacheLoader.from(filter -> compileFilterInternal(filter, Optional.empty()))); filterCacheStats = new CacheStatsMBean(filterCache); } else { diff --git a/core/trino-main/src/main/java/io/trino/type/BlockTypeOperators.java b/core/trino-main/src/main/java/io/trino/type/BlockTypeOperators.java index dad7c299d231..9926d9993625 100644 --- a/core/trino-main/src/main/java/io/trino/type/BlockTypeOperators.java +++ b/core/trino-main/src/main/java/io/trino/type/BlockTypeOperators.java @@ -13,9 +13,9 @@ */ package io.trino.type; -import com.google.common.cache.Cache; import com.google.common.cache.CacheBuilder; import com.google.common.util.concurrent.UncheckedExecutionException; +import io.trino.plugin.base.cache.NonKeyEvictableCache; import io.trino.spi.block.Block; import io.trino.spi.connector.SortOrder; import io.trino.spi.function.InvocationConvention; @@ -34,6 +34,7 @@ import java.util.function.Supplier; import static com.google.common.base.Throwables.throwIfUnchecked; +import static io.trino.plugin.base.cache.SafeCaches.buildNonEvictableCacheWithWeakInvalidateAll; import static io.trino.spi.function.InvocationConvention.InvocationArgumentConvention.BLOCK_POSITION; import static io.trino.spi.function.InvocationConvention.InvocationReturnConvention.FAIL_ON_NULL; import static io.trino.spi.function.InvocationConvention.InvocationReturnConvention.NULLABLE_RETURN; @@ -54,7 +55,7 @@ public final class BlockTypeOperators private static final InvocationConvention ORDERING_CONVENTION = simpleConvention(FAIL_ON_NULL, BLOCK_POSITION, BLOCK_POSITION); private static final InvocationConvention LESS_THAN_CONVENTION = simpleConvention(FAIL_ON_NULL, BLOCK_POSITION, BLOCK_POSITION); - private final Cache, GeneratedBlockOperator> generatedBlockOperatorCache; + private final NonKeyEvictableCache, GeneratedBlockOperator> generatedBlockOperatorCache; private final TypeOperators typeOperators; public BlockTypeOperators() @@ -66,10 +67,10 @@ public BlockTypeOperators() public BlockTypeOperators(TypeOperators typeOperators) { this.typeOperators = requireNonNull(typeOperators, "typeOperators is null"); - this.generatedBlockOperatorCache = CacheBuilder.newBuilder() - .maximumSize(10_000) - .expireAfterWrite(2, TimeUnit.HOURS) - .build(); + this.generatedBlockOperatorCache = buildNonEvictableCacheWithWeakInvalidateAll( + CacheBuilder.newBuilder() + .maximumSize(10_000) + .expireAfterWrite(2, TimeUnit.HOURS)); } public BlockPositionEqual getEqualOperator(Type type) diff --git a/core/trino-main/src/main/java/io/trino/type/TypeOperatorsCache.java b/core/trino-main/src/main/java/io/trino/type/TypeOperatorsCache.java index 027f3adda002..0a2f43258b6e 100644 --- a/core/trino-main/src/main/java/io/trino/type/TypeOperatorsCache.java +++ b/core/trino-main/src/main/java/io/trino/type/TypeOperatorsCache.java @@ -13,9 +13,9 @@ */ package io.trino.type; -import com.google.common.cache.Cache; import com.google.common.cache.CacheBuilder; import com.google.common.util.concurrent.UncheckedExecutionException; +import io.trino.plugin.base.cache.NonKeyEvictableCache; import org.weakref.jmx.Managed; import java.util.concurrent.ExecutionException; @@ -23,13 +23,14 @@ import java.util.function.Supplier; import static com.google.common.base.Throwables.throwIfUnchecked; +import static io.trino.plugin.base.cache.SafeCaches.buildNonEvictableCacheWithWeakInvalidateAll; public class TypeOperatorsCache implements BiFunction, Object> { - private final Cache cache = CacheBuilder.newBuilder() - .maximumSize(10_000) - .build(); + private final NonKeyEvictableCache cache = buildNonEvictableCacheWithWeakInvalidateAll( + CacheBuilder.newBuilder() + .maximumSize(10_000)); @Override public Object apply(Object operatorConvention, Supplier supplier) diff --git a/core/trino-main/src/main/java/io/trino/util/FastutilSetHelper.java b/core/trino-main/src/main/java/io/trino/util/FastutilSetHelper.java index 32f69afca3a9..3bda4f6aa3aa 100644 --- a/core/trino-main/src/main/java/io/trino/util/FastutilSetHelper.java +++ b/core/trino-main/src/main/java/io/trino/util/FastutilSetHelper.java @@ -13,9 +13,9 @@ */ package io.trino.util; -import com.google.common.cache.Cache; import com.google.common.cache.CacheBuilder; import com.google.common.util.concurrent.UncheckedExecutionException; +import io.trino.plugin.base.cache.NonEvictableCache; import io.trino.spi.type.Type; import it.unimi.dsi.fastutil.Hash; import it.unimi.dsi.fastutil.booleans.BooleanOpenHashSet; @@ -36,6 +36,7 @@ import static com.google.common.base.Throwables.throwIfUnchecked; import static com.google.common.base.Verify.verifyNotNull; +import static io.trino.plugin.base.cache.SafeCaches.buildNonEvictableCache; import static io.trino.util.SingleAccessMethodCompiler.compileSingleAccessMethod; import static java.lang.Boolean.TRUE; import static java.lang.invoke.MethodType.methodType; @@ -238,10 +239,10 @@ public boolean equals(Object a, Object b) private static class MethodGenerator { - private static final Cache, GeneratedMethod> generatedMethodCache = CacheBuilder.newBuilder() - .maximumSize(1_000) - .expireAfterWrite(2, TimeUnit.HOURS) - .build(); + private static final NonEvictableCache, GeneratedMethod> generatedMethodCache = buildNonEvictableCache( + CacheBuilder.newBuilder() + .maximumSize(1_000) + .expireAfterWrite(2, TimeUnit.HOURS)); private static T getGeneratedMethod(Type type, Class operatorInterface, MethodHandle methodHandle) { diff --git a/core/trino-main/src/test/java/io/trino/operator/MockExchangeRequestProcessor.java b/core/trino-main/src/test/java/io/trino/operator/MockExchangeRequestProcessor.java index 8b5761391d23..7edb1e133fb0 100644 --- a/core/trino-main/src/test/java/io/trino/operator/MockExchangeRequestProcessor.java +++ b/core/trino-main/src/test/java/io/trino/operator/MockExchangeRequestProcessor.java @@ -45,6 +45,7 @@ import static io.trino.TrinoMediaTypes.TRINO_PAGES; import static io.trino.execution.buffer.PagesSerdeUtil.calculateChecksum; import static io.trino.execution.buffer.TestingPagesSerdeFactory.testingPagesSerde; +import static io.trino.plugin.base.cache.SafeCaches.buildNonEvictableCache; import static io.trino.server.InternalHeaders.TRINO_BUFFER_COMPLETE; import static io.trino.server.InternalHeaders.TRINO_PAGE_NEXT_TOKEN; import static io.trino.server.InternalHeaders.TRINO_PAGE_TOKEN; @@ -60,7 +61,7 @@ public class MockExchangeRequestProcessor private static final String TASK_INSTANCE_ID = "task-instance-id"; private static final PagesSerde PAGES_SERDE = testingPagesSerde(); - private final LoadingCache buffers = CacheBuilder.newBuilder().build(CacheLoader.from(MockBuffer::new)); + private final LoadingCache buffers = buildNonEvictableCache(CacheBuilder.newBuilder(), CacheLoader.from(MockBuffer::new)); private final DataSize expectedMaxSize; diff --git a/core/trino-main/src/test/java/io/trino/operator/TestExchangeOperator.java b/core/trino-main/src/test/java/io/trino/operator/TestExchangeOperator.java index 30456f19a8c0..e4f95b774a1c 100644 --- a/core/trino-main/src/test/java/io/trino/operator/TestExchangeOperator.java +++ b/core/trino-main/src/test/java/io/trino/operator/TestExchangeOperator.java @@ -55,6 +55,7 @@ import static io.trino.operator.ExchangeOperator.REMOTE_CONNECTOR_ID; import static io.trino.operator.PageAssertions.assertPageEquals; import static io.trino.operator.TestingTaskBuffer.PAGE; +import static io.trino.plugin.base.cache.SafeCaches.buildNonEvictableCacheWithWeakInvalidateAll; import static io.trino.spi.type.VarcharType.VARCHAR; import static io.trino.testing.TestingTaskContext.createTaskContext; import static java.util.concurrent.Executors.newScheduledThreadPool; @@ -72,7 +73,8 @@ public class TestExchangeOperator private static final TaskId TASK_2_ID = new TaskId(new StageId("query", 0), 1, 0); private static final TaskId TASK_3_ID = new TaskId(new StageId("query", 0), 2, 0); - private final LoadingCache taskBuffers = CacheBuilder.newBuilder().build(CacheLoader.from(TestingTaskBuffer::new)); + private final LoadingCache taskBuffers = buildNonEvictableCacheWithWeakInvalidateAll( + CacheBuilder.newBuilder(), CacheLoader.from(TestingTaskBuffer::new)); private ScheduledExecutorService scheduler; private ScheduledExecutorService scheduledExecutor; @@ -123,6 +125,7 @@ public void tearDown() @BeforeMethod public void setUpMethod() { + // the test class is single-threaded, so there should be no ongoing loads and invalidation should be effective taskBuffers.invalidateAll(); } diff --git a/core/trino-main/src/test/java/io/trino/operator/TestMergeOperator.java b/core/trino-main/src/test/java/io/trino/operator/TestMergeOperator.java index f765f212224c..a569fdee5600 100644 --- a/core/trino-main/src/test/java/io/trino/operator/TestMergeOperator.java +++ b/core/trino-main/src/test/java/io/trino/operator/TestMergeOperator.java @@ -52,6 +52,7 @@ import static io.trino.operator.OperatorAssertion.assertOperatorIsBlocked; import static io.trino.operator.OperatorAssertion.assertOperatorIsUnblocked; import static io.trino.operator.PageAssertions.assertPageEquals; +import static io.trino.plugin.base.cache.SafeCaches.buildNonEvictableCache; import static io.trino.spi.connector.SortOrder.ASC_NULLS_FIRST; import static io.trino.spi.connector.SortOrder.DESC_NULLS_FIRST; import static io.trino.spi.type.BigintType.BIGINT; @@ -85,7 +86,7 @@ public void setUp() executor = newSingleThreadScheduledExecutor(daemonThreadsNamed("test-merge-operator-%s")); serdeFactory = new TestingPagesSerdeFactory(); - taskBuffers = CacheBuilder.newBuilder().build(CacheLoader.from(TestingTaskBuffer::new)); + taskBuffers = buildNonEvictableCache(CacheBuilder.newBuilder(), CacheLoader.from(TestingTaskBuffer::new)); httpClient = new TestingHttpClient(new TestingExchangeHttpClientHandler(taskBuffers), executor); exchangeClientFactory = new DirectExchangeClientFactory(new NodeInfo("test"), new FeaturesConfig(), new DirectExchangeClientConfig(), httpClient, executor); orderingCompiler = new OrderingCompiler(new TypeOperators()); diff --git a/lib/trino-plugin-toolkit/pom.xml b/lib/trino-plugin-toolkit/pom.xml index ebb2211fb649..58e337c5528f 100644 --- a/lib/trino-plugin-toolkit/pom.xml +++ b/lib/trino-plugin-toolkit/pom.xml @@ -114,6 +114,11 @@ joda-time + + org.gaul + modernizer-maven-annotations + + org.weakref jmxutils @@ -146,13 +151,6 @@ test - - org.gaul - modernizer-maven-annotations - 2.1.0 - test - - org.testng testng diff --git a/lib/trino-plugin-toolkit/src/main/java/io/trino/plugin/base/cache/EvictableCache.java b/lib/trino-plugin-toolkit/src/main/java/io/trino/plugin/base/cache/EvictableCache.java index 43e03d6e05b2..b1eb6f7320f3 100644 --- a/lib/trino-plugin-toolkit/src/main/java/io/trino/plugin/base/cache/EvictableCache.java +++ b/lib/trino-plugin-toolkit/src/main/java/io/trino/plugin/base/cache/EvictableCache.java @@ -18,6 +18,7 @@ import com.google.common.cache.CacheBuilder; import com.google.common.cache.CacheStats; import com.google.common.util.concurrent.SettableFuture; +import org.gaul.modernizer_maven_annotations.SuppressModernizer; import javax.annotation.CheckForNull; @@ -61,7 +62,13 @@ public static EvictableCache buildWith(CacheBuilder cacheBuilder) { requireNonNull(cacheBuilder, "cacheBuilder is null"); - this.delegate = cacheBuilder.build(); + this.delegate = buildUnsafeCache(cacheBuilder); + } + + @SuppressModernizer // CacheBuilder.build() is forbidden, advising to use this class as a safety-adding wrapper. + private static Cache buildUnsafeCache(CacheBuilder cacheBuilder) + { + return cacheBuilder.build(); } @CheckForNull diff --git a/lib/trino-plugin-toolkit/src/main/java/io/trino/plugin/base/cache/EvictableLoadingCache.java b/lib/trino-plugin-toolkit/src/main/java/io/trino/plugin/base/cache/EvictableLoadingCache.java index a9b532638b14..a225ecec766e 100644 --- a/lib/trino-plugin-toolkit/src/main/java/io/trino/plugin/base/cache/EvictableLoadingCache.java +++ b/lib/trino-plugin-toolkit/src/main/java/io/trino/plugin/base/cache/EvictableLoadingCache.java @@ -23,6 +23,7 @@ import com.google.common.collect.ImmutableList; import com.google.common.collect.ImmutableMap; import com.google.common.util.concurrent.ListenableFuture; +import org.gaul.modernizer_maven_annotations.SuppressModernizer; import java.util.ArrayList; import java.util.Collection; @@ -77,7 +78,13 @@ public static LoadingCache build( return new EvictableLoadingCache<>( EvictableCache.buildWith(tokenCache), - dataCache.build(new TokenCacheLoader<>(cacheLoader))); + buildUnsafeCache(dataCache, new TokenCacheLoader<>(cacheLoader))); + } + + @SuppressModernizer // CacheBuilder.build(CacheLoader) is forbidden, advising to use this class as a safety-adding wrapper. + private static LoadingCache buildUnsafeCache(CacheBuilder cacheBuilder, CacheLoader cacheLoader) + { + return cacheBuilder.build(cacheLoader); } // Token is a freshness marker. tokenCache keeps the fresh token for given key. diff --git a/lib/trino-plugin-toolkit/src/main/java/io/trino/plugin/base/cache/NonEvictableCache.java b/lib/trino-plugin-toolkit/src/main/java/io/trino/plugin/base/cache/NonEvictableCache.java new file mode 100644 index 000000000000..beefc7981c18 --- /dev/null +++ b/lib/trino-plugin-toolkit/src/main/java/io/trino/plugin/base/cache/NonEvictableCache.java @@ -0,0 +1,44 @@ +/* + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package io.trino.plugin.base.cache; + +import com.google.common.cache.Cache; + +/** + * A {@link com.google.common.cache.Cache} that does not support eviction. + */ +public interface NonEvictableCache + extends Cache +{ + /** + * @deprecated Not supported. Use {@link EvictableCache} cache implementation instead. + */ + @Deprecated + @Override + void invalidate(Object key); + + /** + * @deprecated Not supported. Use {@link EvictableCache} cache implementation instead. + */ + @Deprecated + @Override + void invalidateAll(Iterable keys); + + /** + * @deprecated Not supported. Use {@link EvictableCache} cache implementation instead. + */ + @Deprecated + @Override + void invalidateAll(); +} diff --git a/lib/trino-plugin-toolkit/src/main/java/io/trino/plugin/base/cache/NonEvictableCacheImpl.java b/lib/trino-plugin-toolkit/src/main/java/io/trino/plugin/base/cache/NonEvictableCacheImpl.java new file mode 100644 index 000000000000..47c7779e744d --- /dev/null +++ b/lib/trino-plugin-toolkit/src/main/java/io/trino/plugin/base/cache/NonEvictableCacheImpl.java @@ -0,0 +1,35 @@ +/* + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package io.trino.plugin.base.cache; + +import com.google.common.cache.Cache; + +// package-private. The interface provides deprecation and javadoc to help at call sites +final class NonEvictableCacheImpl + extends NonKeyEvictableCacheImpl + implements NonEvictableCache +{ + NonEvictableCacheImpl(Cache delegate) + { + super(delegate); + } + + @Override + public void invalidateAll() + { + throw new UnsupportedOperationException("invalidateAll does not invalidate ongoing loads, so a stale value may remain in the cache for ever. " + + "Use EvictableCache if you need invalidation, or use SafeCaches.buildNonEvictableCacheWithWeakInvalidateAll() " + + "if invalidateAll is not required for correctness"); + } +} diff --git a/lib/trino-plugin-toolkit/src/main/java/io/trino/plugin/base/cache/NonEvictableLoadingCache.java b/lib/trino-plugin-toolkit/src/main/java/io/trino/plugin/base/cache/NonEvictableLoadingCache.java new file mode 100644 index 000000000000..f7aa40e96e82 --- /dev/null +++ b/lib/trino-plugin-toolkit/src/main/java/io/trino/plugin/base/cache/NonEvictableLoadingCache.java @@ -0,0 +1,28 @@ +/* + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package io.trino.plugin.base.cache; + +/** + * A {@link com.google.common.cache.LoadingCache} that does not support eviction. + */ +public interface NonEvictableLoadingCache + extends NonKeyEvictableLoadingCache +{ + /** + * @deprecated Not supported. Use {@link EvictableLoadingCache} cache implementation instead. + */ + @Deprecated + @Override + void invalidateAll(); +} diff --git a/lib/trino-plugin-toolkit/src/main/java/io/trino/plugin/base/cache/NonEvictableLoadingCacheImpl.java b/lib/trino-plugin-toolkit/src/main/java/io/trino/plugin/base/cache/NonEvictableLoadingCacheImpl.java new file mode 100644 index 000000000000..69ade57346b8 --- /dev/null +++ b/lib/trino-plugin-toolkit/src/main/java/io/trino/plugin/base/cache/NonEvictableLoadingCacheImpl.java @@ -0,0 +1,35 @@ +/* + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package io.trino.plugin.base.cache; + +import com.google.common.cache.LoadingCache; + +// package-private. The interface provides deprecation and javadoc to help at call sites +final class NonEvictableLoadingCacheImpl + extends NonKeyEvictableLoadingCacheImpl + implements NonEvictableLoadingCache +{ + NonEvictableLoadingCacheImpl(LoadingCache delegate) + { + super(delegate); + } + + @Override + public void invalidateAll() + { + throw new UnsupportedOperationException("invalidateAll does not invalidate ongoing loads, so a stale value may remain in the cache for ever. " + + "Use EvictableLoadingCache if you need invalidation, or use SafeCaches.buildNonEvictableCacheWithWeakInvalidateAll() " + + "if invalidateAll is not required for correctness"); + } +} diff --git a/lib/trino-plugin-toolkit/src/main/java/io/trino/plugin/base/cache/NonKeyEvictableCache.java b/lib/trino-plugin-toolkit/src/main/java/io/trino/plugin/base/cache/NonKeyEvictableCache.java new file mode 100644 index 000000000000..7a1ba409aa7e --- /dev/null +++ b/lib/trino-plugin-toolkit/src/main/java/io/trino/plugin/base/cache/NonKeyEvictableCache.java @@ -0,0 +1,45 @@ +/* + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package io.trino.plugin.base.cache; + +import com.google.common.cache.Cache; + +/** + * A {@link com.google.common.cache.Cache} that does not support key-based eviction. + */ +public interface NonKeyEvictableCache + extends Cache +{ + /** + * @deprecated Not supported. Use {@link EvictableCache} cache implementation instead. + */ + @Deprecated + @Override + void invalidate(Object key); + + /** + * @deprecated Not supported. Use {@link EvictableCache} cache implementation instead. + */ + @Deprecated + @Override + void invalidateAll(Iterable keys); + + /** + * Invalidates all live entries in the cache. Ongoing loads may not be invalidated, so subsequent + * get from the cache is not guaranteed to return fresh state. Must not be relied on for correctness, + * but can be used for manual intervention, e.g. as a method exposed over JMX. + */ + @Override + void invalidateAll(); +} diff --git a/lib/trino-plugin-toolkit/src/main/java/io/trino/plugin/base/cache/NonKeyEvictableCacheImpl.java b/lib/trino-plugin-toolkit/src/main/java/io/trino/plugin/base/cache/NonKeyEvictableCacheImpl.java new file mode 100644 index 000000000000..9ccf3edcc100 --- /dev/null +++ b/lib/trino-plugin-toolkit/src/main/java/io/trino/plugin/base/cache/NonKeyEvictableCacheImpl.java @@ -0,0 +1,52 @@ +/* + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package io.trino.plugin.base.cache; + +import com.google.common.cache.Cache; +import com.google.common.cache.ForwardingCache; + +import static java.util.Objects.requireNonNull; + +// package-private. The interface provides deprecation and javadoc to help at call sites +class NonKeyEvictableCacheImpl + extends ForwardingCache + implements NonKeyEvictableCache +{ + private final Cache delegate; + + NonKeyEvictableCacheImpl(Cache delegate) + { + this.delegate = requireNonNull(delegate, "delegate is null"); + } + + @Override + protected Cache delegate() + { + return delegate; + } + + @Override + public void invalidate(Object key) + { + throw new UnsupportedOperationException("invalidate(key) does not invalidate ongoing loads, so a stale value may remain in the cache for ever. " + + "Use EvictableCache if you need invalidation"); + } + + @Override + public void invalidateAll(Iterable keys) + { + throw new UnsupportedOperationException("invalidateAll(keys) does not invalidate ongoing loads, so a stale value may remain in the cache for ever. " + + "Use EvictableCache if you need invalidation"); + } +} diff --git a/lib/trino-plugin-toolkit/src/main/java/io/trino/plugin/base/cache/NonKeyEvictableLoadingCache.java b/lib/trino-plugin-toolkit/src/main/java/io/trino/plugin/base/cache/NonKeyEvictableLoadingCache.java new file mode 100644 index 000000000000..0c16b1c05ca8 --- /dev/null +++ b/lib/trino-plugin-toolkit/src/main/java/io/trino/plugin/base/cache/NonKeyEvictableLoadingCache.java @@ -0,0 +1,45 @@ +/* + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package io.trino.plugin.base.cache; + +import com.google.common.cache.LoadingCache; + +/** + * A {@link com.google.common.cache.LoadingCache} that does not support key-based eviction. + */ +public interface NonKeyEvictableLoadingCache + extends LoadingCache +{ + /** + * @deprecated Not supported. Use {@link EvictableLoadingCache} cache implementation instead. + */ + @Deprecated + @Override + void invalidate(Object key); + + /** + * @deprecated Not supported. Use {@link EvictableLoadingCache} cache implementation instead. + */ + @Deprecated + @Override + void invalidateAll(Iterable keys); + + /** + * Invalidates all live entries in the cache. Ongoing loads may not be invalidated, so subsequent + * get from the cache is not guaranteed to return fresh state. Must not be relied on for correctness, + * but can be used for manual intervention, e.g. as a method exposed over JMX. + */ + @Override + void invalidateAll(); +} diff --git a/lib/trino-plugin-toolkit/src/main/java/io/trino/plugin/base/cache/NonKeyEvictableLoadingCacheImpl.java b/lib/trino-plugin-toolkit/src/main/java/io/trino/plugin/base/cache/NonKeyEvictableLoadingCacheImpl.java new file mode 100644 index 000000000000..b68c1991ce48 --- /dev/null +++ b/lib/trino-plugin-toolkit/src/main/java/io/trino/plugin/base/cache/NonKeyEvictableLoadingCacheImpl.java @@ -0,0 +1,52 @@ +/* + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package io.trino.plugin.base.cache; + +import com.google.common.cache.ForwardingLoadingCache; +import com.google.common.cache.LoadingCache; + +import static java.util.Objects.requireNonNull; + +// package-private. The interface provides deprecation and javadoc to help at call sites +class NonKeyEvictableLoadingCacheImpl + extends ForwardingLoadingCache + implements NonKeyEvictableLoadingCache +{ + private final LoadingCache delegate; + + NonKeyEvictableLoadingCacheImpl(LoadingCache delegate) + { + this.delegate = requireNonNull(delegate, "delegate is null"); + } + + @Override + protected LoadingCache delegate() + { + return delegate; + } + + @Override + public void invalidate(Object key) + { + throw new UnsupportedOperationException("invalidate(key) does not invalidate ongoing loads, so a stale value may remain in the cache for ever. " + + "Use EvictableLoadingCache if you need invalidation"); + } + + @Override + public void invalidateAll(Iterable keys) + { + throw new UnsupportedOperationException("invalidateAll(keys) does not invalidate ongoing loads, so a stale value may remain in the cache for ever. " + + "Use EvictableLoadingCache if you need invalidation"); + } +} diff --git a/lib/trino-plugin-toolkit/src/main/java/io/trino/plugin/base/cache/SafeCaches.java b/lib/trino-plugin-toolkit/src/main/java/io/trino/plugin/base/cache/SafeCaches.java new file mode 100644 index 000000000000..b049d216927b --- /dev/null +++ b/lib/trino-plugin-toolkit/src/main/java/io/trino/plugin/base/cache/SafeCaches.java @@ -0,0 +1,73 @@ +/* + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package io.trino.plugin.base.cache; + +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 org.gaul.modernizer_maven_annotations.SuppressModernizer; + +/** + * @see EvictableCache + * @see EvictableLoadingCache + */ +public final class SafeCaches +{ + private SafeCaches() {} + + public static NonEvictableCache buildNonEvictableCache(CacheBuilder cacheBuilder) + { + return new NonEvictableCacheImpl<>(buildUnsafeCache(cacheBuilder)); + } + + /** + * Builds a cache that supports {@link Cache#invalidateAll()} with best-effort semantics: + * there is no guarantee that cache is empty after {@code invalidateAll()} returns, or that + * subsequent read will not see stale state. + */ + public static NonKeyEvictableCache buildNonEvictableCacheWithWeakInvalidateAll(CacheBuilder cacheBuilder) + { + return new NonKeyEvictableCacheImpl<>(buildUnsafeCache(cacheBuilder)); + } + + public static NonEvictableLoadingCache buildNonEvictableCache(CacheBuilder cacheBuilder, CacheLoader cacheLoader) + { + return new NonEvictableLoadingCacheImpl<>(buildUnsafeCache(cacheBuilder, cacheLoader)); + } + + /** + * Builds a cache that supports {@link Cache#invalidateAll()} with best-effort semantics: + * there is no guarantee that cache is empty after {@code invalidateAll()} returns, or that + * subsequent read will not see stale state. + */ + public static NonKeyEvictableLoadingCache buildNonEvictableCacheWithWeakInvalidateAll( + CacheBuilder cacheBuilder, + CacheLoader cacheLoader) + { + return new NonKeyEvictableLoadingCacheImpl<>(buildUnsafeCache(cacheBuilder, cacheLoader)); + } + + @SuppressModernizer // CacheBuilder.build() is forbidden, advising to use this class as a safety-adding wrapper. + private static Cache buildUnsafeCache(CacheBuilder cacheBuilder) + { + return cacheBuilder.build(); + } + + @SuppressModernizer // CacheBuilder.build(CacheLoader) is forbidden, advising to use this class as a safety-adding wrapper. + private static LoadingCache buildUnsafeCache(CacheBuilder cacheBuilder, CacheLoader cacheLoader) + { + return cacheBuilder.build(cacheLoader); + } +} diff --git a/plugin/trino-accumulo/src/main/java/io/trino/plugin/accumulo/index/ColumnCardinalityCache.java b/plugin/trino-accumulo/src/main/java/io/trino/plugin/accumulo/index/ColumnCardinalityCache.java index 595f3faf0c5a..e5fcadd3d07c 100644 --- a/plugin/trino-accumulo/src/main/java/io/trino/plugin/accumulo/index/ColumnCardinalityCache.java +++ b/plugin/trino-accumulo/src/main/java/io/trino/plugin/accumulo/index/ColumnCardinalityCache.java @@ -15,7 +15,6 @@ 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.ImmutableMultimap; import com.google.common.collect.Iterables; @@ -27,6 +26,7 @@ import io.airlift.units.Duration; import io.trino.plugin.accumulo.conf.AccumuloConfig; import io.trino.plugin.accumulo.model.AccumuloColumnConstraint; +import io.trino.plugin.base.cache.NonEvictableLoadingCache; import io.trino.spi.TrinoException; import org.apache.accumulo.core.client.BatchScanner; import org.apache.accumulo.core.client.Connector; @@ -63,6 +63,7 @@ import static io.trino.plugin.accumulo.index.Indexer.CARDINALITY_CQ_AS_TEXT; import static io.trino.plugin.accumulo.index.Indexer.getIndexColumnFamily; import static io.trino.plugin.accumulo.index.Indexer.getMetricsTableName; +import static io.trino.plugin.base.cache.SafeCaches.buildNonEvictableCache; import static io.trino.spi.StandardErrorCode.FUNCTION_IMPLEMENTATION_ERROR; import static java.lang.Long.parseLong; import static java.nio.charset.StandardCharsets.UTF_8; @@ -83,7 +84,7 @@ public class ColumnCardinalityCache private final Connector connector; private final ExecutorService coreExecutor; private final BoundedExecutor executorService; - private final LoadingCache cache; + private final NonEvictableLoadingCache cache; @Inject public ColumnCardinalityCache(Connector connector, AccumuloConfig config) @@ -97,10 +98,11 @@ public ColumnCardinalityCache(Connector connector, AccumuloConfig config) this.executorService = new BoundedExecutor(coreExecutor, 4 * Runtime.getRuntime().availableProcessors()); LOG.debug("Created new cache size %d expiry %s", size, expireDuration); - cache = CacheBuilder.newBuilder() - .maximumSize(size) - .expireAfterWrite(expireDuration.toMillis(), MILLISECONDS) - .build(new CardinalityCacheLoader()); + cache = buildNonEvictableCache( + CacheBuilder.newBuilder() + .maximumSize(size) + .expireAfterWrite(expireDuration.toMillis(), MILLISECONDS), + new CardinalityCacheLoader()); } @PreDestroy diff --git a/plugin/trino-base-jdbc/src/main/java/io/trino/plugin/jdbc/mapping/CachingIdentifierMapping.java b/plugin/trino-base-jdbc/src/main/java/io/trino/plugin/jdbc/mapping/CachingIdentifierMapping.java index da6caaa579b0..544fa5b569e7 100644 --- a/plugin/trino-base-jdbc/src/main/java/io/trino/plugin/jdbc/mapping/CachingIdentifierMapping.java +++ b/plugin/trino-base-jdbc/src/main/java/io/trino/plugin/jdbc/mapping/CachingIdentifierMapping.java @@ -14,11 +14,11 @@ package io.trino.plugin.jdbc.mapping; import com.google.common.base.CharMatcher; -import com.google.common.cache.Cache; import com.google.common.cache.CacheBuilder; import com.google.common.collect.ImmutableList; import com.google.common.collect.ImmutableMap; import com.google.common.collect.ImmutableSet; +import io.trino.plugin.base.cache.NonKeyEvictableCache; import io.trino.plugin.jdbc.BaseJdbcClient; import io.trino.plugin.jdbc.mapping.IdentifierMappingModule.ForCachingIdentifierMapping; import io.trino.spi.TrinoException; @@ -43,6 +43,7 @@ import static com.google.common.base.MoreObjects.firstNonNull; import static com.google.common.base.Preconditions.checkArgument; import static com.google.common.base.Verify.verify; +import static io.trino.plugin.base.cache.SafeCaches.buildNonEvictableCacheWithWeakInvalidateAll; import static io.trino.plugin.jdbc.JdbcErrorCode.JDBC_ERROR; import static java.util.Objects.requireNonNull; import static java.util.concurrent.TimeUnit.MILLISECONDS; @@ -50,8 +51,8 @@ public final class CachingIdentifierMapping implements IdentifierMapping { - private final Cache remoteSchemaNames; - private final Cache remoteTableNames; + private final NonKeyEvictableCache remoteSchemaNames; + private final NonKeyEvictableCache remoteTableNames; private final IdentifierMapping identifierMapping; private final Provider baseJdbcClient; @@ -64,8 +65,8 @@ public CachingIdentifierMapping( requireNonNull(mappingConfig, "mappingConfig is null"); CacheBuilder remoteNamesCacheBuilder = CacheBuilder.newBuilder() .expireAfterWrite(mappingConfig.getCaseInsensitiveNameMatchingCacheTtl().toMillis(), MILLISECONDS); - this.remoteSchemaNames = remoteNamesCacheBuilder.build(); - this.remoteTableNames = remoteNamesCacheBuilder.build(); + this.remoteSchemaNames = buildNonEvictableCacheWithWeakInvalidateAll(remoteNamesCacheBuilder); + this.remoteTableNames = buildNonEvictableCacheWithWeakInvalidateAll(remoteNamesCacheBuilder); this.identifierMapping = requireNonNull(identifierMapping, "identifierMapping is null"); this.baseJdbcClient = requireNonNull(baseJdbcClient, "baseJdbcClient is null"); diff --git a/plugin/trino-bigquery/pom.xml b/plugin/trino-bigquery/pom.xml index 9e87257c4424..08ec9c0fd97b 100644 --- a/plugin/trino-bigquery/pom.xml +++ b/plugin/trino-bigquery/pom.xml @@ -54,6 +54,11 @@ + + io.trino + trino-plugin-toolkit + + io.airlift bootstrap diff --git a/plugin/trino-bigquery/src/main/java/io/trino/plugin/bigquery/BigQueryClientFactory.java b/plugin/trino-bigquery/src/main/java/io/trino/plugin/bigquery/BigQueryClientFactory.java index f45bbac4e556..316d8778534e 100644 --- a/plugin/trino-bigquery/src/main/java/io/trino/plugin/bigquery/BigQueryClientFactory.java +++ b/plugin/trino-bigquery/src/main/java/io/trino/plugin/bigquery/BigQueryClientFactory.java @@ -18,8 +18,8 @@ import com.google.auth.oauth2.ServiceAccountCredentials; import com.google.cloud.bigquery.BigQuery; import com.google.cloud.bigquery.BigQueryOptions; -import com.google.common.cache.Cache; import com.google.common.cache.CacheBuilder; +import io.trino.plugin.base.cache.NonEvictableCache; import io.trino.spi.connector.ConnectorSession; import javax.inject.Inject; @@ -27,6 +27,7 @@ import java.util.Optional; import java.util.concurrent.ExecutionException; +import static io.trino.plugin.base.cache.SafeCaches.buildNonEvictableCache; import static java.util.Objects.requireNonNull; import static java.util.concurrent.TimeUnit.MILLISECONDS; @@ -37,7 +38,7 @@ public class BigQueryClientFactory private final BigQueryConfig bigQueryConfig; private final ViewMaterializationCache materializationCache; private final HeaderProvider headerProvider; - private final Cache clientCache; + private final NonEvictableCache clientCache; @Inject public BigQueryClientFactory( @@ -56,7 +57,7 @@ public BigQueryClientFactory( CacheBuilder cacheBuilder = CacheBuilder.newBuilder() .expireAfterWrite(bigQueryConfig.getServiceCacheTtl().toMillis(), MILLISECONDS); - clientCache = cacheBuilder.build(); + clientCache = buildNonEvictableCache(cacheBuilder); } public BigQueryClient create(ConnectorSession session) diff --git a/plugin/trino-bigquery/src/main/java/io/trino/plugin/bigquery/ViewMaterializationCache.java b/plugin/trino-bigquery/src/main/java/io/trino/plugin/bigquery/ViewMaterializationCache.java index 0c047633f8d0..d339929be26f 100644 --- a/plugin/trino-bigquery/src/main/java/io/trino/plugin/bigquery/ViewMaterializationCache.java +++ b/plugin/trino-bigquery/src/main/java/io/trino/plugin/bigquery/ViewMaterializationCache.java @@ -21,10 +21,10 @@ import com.google.cloud.bigquery.Table; import com.google.cloud.bigquery.TableId; import com.google.cloud.bigquery.TableInfo; -import com.google.common.cache.Cache; import com.google.common.cache.CacheBuilder; import io.airlift.log.Logger; import io.airlift.units.Duration; +import io.trino.plugin.base.cache.NonEvictableCache; import io.trino.spi.TrinoException; import io.trino.spi.connector.SchemaTableName; import io.trino.spi.connector.TableNotFoundException; @@ -35,6 +35,7 @@ import java.util.concurrent.Callable; import java.util.concurrent.ExecutionException; +import static io.trino.plugin.base.cache.SafeCaches.buildNonEvictableCache; import static io.trino.plugin.bigquery.BigQueryErrorCode.BIGQUERY_VIEW_DESTINATION_TABLE_CREATION_FAILED; import static io.trino.plugin.bigquery.BigQueryUtil.convertToBigQueryException; import static java.lang.String.format; @@ -47,7 +48,7 @@ public class ViewMaterializationCache { private static final Logger log = Logger.get(ViewMaterializationCache.class); - private final Cache destinationTableCache; + private final NonEvictableCache destinationTableCache; private final Optional viewMaterializationProject; private final Optional viewMaterializationDataset; @@ -55,10 +56,10 @@ public class ViewMaterializationCache public ViewMaterializationCache(BigQueryConfig config) { requireNonNull(config, "config is null"); - this.destinationTableCache = CacheBuilder.newBuilder() - .expireAfterWrite(config.getViewsCacheTtl().toMillis(), MILLISECONDS) - .maximumSize(1000) - .build(); + this.destinationTableCache = buildNonEvictableCache( + CacheBuilder.newBuilder() + .expireAfterWrite(config.getViewsCacheTtl().toMillis(), MILLISECONDS) + .maximumSize(1000)); this.viewMaterializationProject = config.getViewMaterializationProject(); this.viewMaterializationDataset = config.getViewMaterializationDataset(); } diff --git a/plugin/trino-google-sheets/src/main/java/io/trino/plugin/google/sheets/SheetsClient.java b/plugin/trino-google-sheets/src/main/java/io/trino/plugin/google/sheets/SheetsClient.java index f61c7ea79ae1..65c332cf1b1f 100644 --- a/plugin/trino-google-sheets/src/main/java/io/trino/plugin/google/sheets/SheetsClient.java +++ b/plugin/trino-google-sheets/src/main/java/io/trino/plugin/google/sheets/SheetsClient.java @@ -21,13 +21,13 @@ import com.google.api.services.sheets.v4.SheetsScopes; import com.google.common.cache.CacheBuilder; import com.google.common.cache.CacheLoader; -import com.google.common.cache.LoadingCache; import com.google.common.collect.ImmutableList; import com.google.common.collect.ImmutableMap; import com.google.common.collect.ImmutableSet; import com.google.common.util.concurrent.UncheckedExecutionException; import io.airlift.json.JsonCodec; import io.airlift.log.Logger; +import io.trino.plugin.base.cache.NonEvictableLoadingCache; import io.trino.spi.TrinoException; import io.trino.spi.type.VarcharType; @@ -46,8 +46,8 @@ import static com.google.api.client.googleapis.javanet.GoogleNetHttpTransport.newTrustedTransport; import static com.google.common.base.Throwables.throwIfInstanceOf; -import static com.google.common.cache.CacheLoader.from; import static com.google.common.collect.ImmutableList.toImmutableList; +import static io.trino.plugin.base.cache.SafeCaches.buildNonEvictableCache; import static io.trino.plugin.google.sheets.SheetsErrorCode.SHEETS_BAD_CREDENTIALS_ERROR; import static io.trino.plugin.google.sheets.SheetsErrorCode.SHEETS_METASTORE_ERROR; import static io.trino.plugin.google.sheets.SheetsErrorCode.SHEETS_TABLE_LOAD_ERROR; @@ -65,8 +65,8 @@ public class SheetsClient private static final List SCOPES = ImmutableList.of(SheetsScopes.SPREADSHEETS_READONLY); - private final LoadingCache> tableSheetMappingCache; - private final LoadingCache>> sheetDataCache; + private final NonEvictableLoadingCache> tableSheetMappingCache; + private final NonEvictableLoadingCache>> sheetDataCache; private final String metadataSheetId; private final String credentialsFilePath; @@ -91,8 +91,9 @@ public SheetsClient(SheetsConfig config, JsonCodec long expiresAfterWriteMillis = config.getSheetsDataExpireAfterWrite().toMillis(); long maxCacheSize = config.getSheetsDataMaxCacheSize(); - this.tableSheetMappingCache = newCacheBuilder(expiresAfterWriteMillis, maxCacheSize) - .build(new CacheLoader<>() + this.tableSheetMappingCache = buildNonEvictableCache( + newCacheBuilder(expiresAfterWriteMillis, maxCacheSize), + new CacheLoader<>() { @Override public Optional load(String tableName) @@ -107,7 +108,9 @@ public Map> loadAll(Iterable tableLis } }); - this.sheetDataCache = newCacheBuilder(expiresAfterWriteMillis, maxCacheSize).build(from(this::readAllValuesFromSheetExpression)); + this.sheetDataCache = buildNonEvictableCache( + newCacheBuilder(expiresAfterWriteMillis, maxCacheSize), + CacheLoader.from(this::readAllValuesFromSheetExpression)); } public Optional getTable(String tableName) diff --git a/plugin/trino-hive/src/main/java/io/trino/plugin/hive/CachingDirectoryLister.java b/plugin/trino-hive/src/main/java/io/trino/plugin/hive/CachingDirectoryLister.java index 8983f44467ff..0b2e41c533e2 100644 --- a/plugin/trino-hive/src/main/java/io/trino/plugin/hive/CachingDirectoryLister.java +++ b/plugin/trino-hive/src/main/java/io/trino/plugin/hive/CachingDirectoryLister.java @@ -13,11 +13,11 @@ */ package io.trino.plugin.hive; -import com.google.common.cache.Cache; import com.google.common.cache.CacheBuilder; import com.google.common.cache.Weigher; import com.google.common.collect.ImmutableList; import io.airlift.units.Duration; +import io.trino.plugin.base.cache.NonKeyEvictableCache; import io.trino.plugin.hive.metastore.Table; import io.trino.spi.connector.SchemaTablePrefix; import org.apache.hadoop.fs.FileSystem; @@ -36,11 +36,13 @@ import static com.google.common.base.Preconditions.checkArgument; import static com.google.common.collect.ImmutableList.toImmutableList; +import static io.trino.plugin.base.cache.SafeCaches.buildNonEvictableCacheWithWeakInvalidateAll; public class CachingDirectoryLister implements DirectoryLister { - private final Cache> cache; + // TODO (https://github.com/trinodb/trino/issues/10621) this cache lacks invalidation + private final NonKeyEvictableCache> cache; private final List tablePrefixes; @Inject @@ -51,12 +53,11 @@ public CachingDirectoryLister(HiveConfig hiveClientConfig) public CachingDirectoryLister(Duration expireAfterWrite, long maxSize, List tables) { - this.cache = CacheBuilder.newBuilder() + this.cache = buildNonEvictableCacheWithWeakInvalidateAll(CacheBuilder.newBuilder() .maximumWeight(maxSize) .weigher((Weigher>) (key, value) -> value.size()) .expireAfterWrite(expireAfterWrite.toMillis(), TimeUnit.MILLISECONDS) - .recordStats() - .build(); + .recordStats()); this.tablePrefixes = tables.stream() .map(CachingDirectoryLister::parseTableName) .collect(toImmutableList()); diff --git a/plugin/trino-hive/src/main/java/io/trino/plugin/hive/metastore/RecordingHiveMetastore.java b/plugin/trino-hive/src/main/java/io/trino/plugin/hive/metastore/RecordingHiveMetastore.java index da3ae85a8344..67708dc3f65d 100644 --- a/plugin/trino-hive/src/main/java/io/trino/plugin/hive/metastore/RecordingHiveMetastore.java +++ b/plugin/trino-hive/src/main/java/io/trino/plugin/hive/metastore/RecordingHiveMetastore.java @@ -20,6 +20,7 @@ import com.google.common.cache.CacheBuilder; import io.airlift.json.JsonCodec; import io.airlift.units.Duration; +import io.trino.plugin.base.cache.NonEvictableCache; import io.trino.plugin.hive.ForRecordingHiveMetastore; import io.trino.plugin.hive.HiveType; import io.trino.plugin.hive.PartitionStatistics; @@ -51,6 +52,7 @@ import static com.google.common.collect.ImmutableList.toImmutableList; import static com.google.common.collect.ImmutableMap.toImmutableMap; import static com.google.common.collect.ImmutableSet.toImmutableSet; +import static io.trino.plugin.base.cache.SafeCaches.buildNonEvictableCache; import static io.trino.plugin.hive.metastore.HivePartitionName.hivePartitionName; import static io.trino.plugin.hive.metastore.HiveTableName.hiveTableName; import static io.trino.plugin.hive.metastore.PartitionFilter.partitionFilter; @@ -70,21 +72,21 @@ public class RecordingHiveMetastore private volatile Optional> allDatabases = Optional.empty(); private volatile Optional> allRoles = Optional.empty(); - private final Cache> databaseCache; - private final Cache> tableCache; - private final Cache> supportedColumnStatisticsCache; - private final Cache tableStatisticsCache; - private final Cache, Map> partitionStatisticsCache; - private final Cache> allTablesCache; - private final Cache> tablesWithParameterCache; - private final Cache> allViewsCache; - private final Cache> partitionCache; - private final Cache>> partitionNamesCache; - private final Cache>> partitionNamesByPartsCache; - private final Cache, Map>> partitionsByNamesCache; - private final Cache> tablePrivilegesCache; - private final Cache> roleGrantsCache; - private final Cache> grantedPrincipalsCache; + private final NonEvictableCache> databaseCache; + private final NonEvictableCache> tableCache; + private final NonEvictableCache> supportedColumnStatisticsCache; + private final NonEvictableCache tableStatisticsCache; + private final NonEvictableCache, Map> partitionStatisticsCache; + private final NonEvictableCache> allTablesCache; + private final NonEvictableCache> tablesWithParameterCache; + private final NonEvictableCache> allViewsCache; + private final NonEvictableCache> partitionCache; + private final NonEvictableCache>> partitionNamesCache; + private final NonEvictableCache>> partitionNamesByPartsCache; + private final NonEvictableCache, Map>> partitionsByNamesCache; + private final NonEvictableCache> tablePrivilegesCache; + private final NonEvictableCache> roleGrantsCache; + private final NonEvictableCache> grantedPrincipalsCache; @Inject public RecordingHiveMetastore(@ForRecordingHiveMetastore HiveMetastore delegate, RecordingMetastoreConfig config, JsonCodec recordingCodec) @@ -143,16 +145,14 @@ void loadRecording() grantedPrincipalsCache.putAll(toMap(recording.getGrantedPrincipals())); } - private static Cache createCache(boolean reply, Duration recordingDuration) + private static NonEvictableCache createCache(boolean reply, Duration recordingDuration) { if (reply) { - return CacheBuilder.newBuilder() - .build(); + return buildNonEvictableCache(CacheBuilder.newBuilder()); } - return CacheBuilder.newBuilder() - .expireAfterWrite(recordingDuration.toMillis(), MILLISECONDS) - .build(); + return buildNonEvictableCache(CacheBuilder.newBuilder() + .expireAfterWrite(recordingDuration.toMillis(), MILLISECONDS)); } @Managed diff --git a/plugin/trino-hive/src/main/java/io/trino/plugin/hive/metastore/thrift/ThriftHiveMetastore.java b/plugin/trino-hive/src/main/java/io/trino/plugin/hive/metastore/thrift/ThriftHiveMetastore.java index 5de93baf6baf..425b5d30655a 100644 --- a/plugin/trino-hive/src/main/java/io/trino/plugin/hive/metastore/thrift/ThriftHiveMetastore.java +++ b/plugin/trino-hive/src/main/java/io/trino/plugin/hive/metastore/thrift/ThriftHiveMetastore.java @@ -15,7 +15,6 @@ import com.google.common.cache.CacheBuilder; import com.google.common.cache.CacheLoader; -import com.google.common.cache.LoadingCache; import com.google.common.collect.ImmutableList; import com.google.common.collect.ImmutableMap; import com.google.common.collect.ImmutableSet; @@ -23,6 +22,7 @@ import com.google.common.util.concurrent.UncheckedExecutionException; import io.airlift.log.Logger; import io.airlift.units.Duration; +import io.trino.plugin.base.cache.NonEvictableLoadingCache; import io.trino.plugin.hive.HdfsEnvironment; import io.trino.plugin.hive.HdfsEnvironment.HdfsContext; import io.trino.plugin.hive.HiveBasicStatistics; @@ -127,10 +127,10 @@ import static com.google.common.collect.ImmutableSet.toImmutableSet; import static com.google.common.collect.Iterables.getOnlyElement; import static com.google.common.collect.Sets.difference; +import static io.trino.plugin.base.cache.SafeCaches.buildNonEvictableCache; import static io.trino.plugin.hive.HiveErrorCode.HIVE_METASTORE_ERROR; import static io.trino.plugin.hive.HiveErrorCode.HIVE_TABLE_LOCK_NOT_ACQUIRED; import static io.trino.plugin.hive.ViewReaderUtil.PRESTO_VIEW_FLAG; -import static io.trino.plugin.hive.metastore.HivePrivilegeInfo.HivePrivilege; import static io.trino.plugin.hive.metastore.HivePrivilegeInfo.HivePrivilege.OWNERSHIP; import static io.trino.plugin.hive.metastore.MetastoreUtil.partitionKeyFilterToStringList; import static io.trino.plugin.hive.metastore.thrift.ThriftMetastoreUtil.createMetastoreColumnStatistics; @@ -180,7 +180,7 @@ public class ThriftHiveMetastore private final int maxRetries; private final boolean impersonationEnabled; private final boolean authenticationEnabled; - private final LoadingCache delegationTokenCache; + private final NonEvictableLoadingCache delegationTokenCache; private final boolean deleteFilesOnDrop; private final boolean translateHiveViews; @@ -238,10 +238,11 @@ public ThriftHiveMetastore( this.maxWaitForLock = thriftConfig.getMaxWaitForTransactionLock(); this.authenticationEnabled = authenticationEnabled; - this.delegationTokenCache = CacheBuilder.newBuilder() - .expireAfterWrite(thriftConfig.getDelegationTokenCacheTtl().toMillis(), MILLISECONDS) - .maximumSize(thriftConfig.getDelegationTokenCacheMaximumSize()) - .build(CacheLoader.from(this::loadDelegationToken)); + this.delegationTokenCache = buildNonEvictableCache( + CacheBuilder.newBuilder() + .expireAfterWrite(thriftConfig.getDelegationTokenCacheTtl().toMillis(), MILLISECONDS) + .maximumSize(thriftConfig.getDelegationTokenCacheMaximumSize()), + CacheLoader.from(this::loadDelegationToken)); this.assumeCanonicalPartitionKeys = thriftConfig.isAssumeCanonicalPartitionKeys(); } diff --git a/plugin/trino-kafka/src/main/java/io/trino/plugin/kafka/schema/confluent/ConfluentAvroReaderSupplier.java b/plugin/trino-kafka/src/main/java/io/trino/plugin/kafka/schema/confluent/ConfluentAvroReaderSupplier.java index 2b8b5ba3ceaf..d8df3539bea0 100644 --- a/plugin/trino-kafka/src/main/java/io/trino/plugin/kafka/schema/confluent/ConfluentAvroReaderSupplier.java +++ b/plugin/trino-kafka/src/main/java/io/trino/plugin/kafka/schema/confluent/ConfluentAvroReaderSupplier.java @@ -15,10 +15,10 @@ import com.google.common.cache.CacheBuilder; import com.google.common.cache.CacheLoader; -import com.google.common.cache.LoadingCache; import io.confluent.kafka.schemaregistry.client.SchemaRegistryClient; import io.confluent.kafka.schemaregistry.client.rest.exceptions.RestClientException; import io.trino.decoder.avro.AvroReaderSupplier; +import io.trino.plugin.base.cache.NonEvictableLoadingCache; import io.trino.spi.TrinoException; import org.apache.avro.Schema; import org.apache.avro.generic.GenericDatumReader; @@ -30,6 +30,7 @@ import java.nio.ByteBuffer; import static com.google.common.base.Preconditions.checkState; +import static io.trino.plugin.base.cache.SafeCaches.buildNonEvictableCache; import static io.trino.spi.StandardErrorCode.GENERIC_INTERNAL_ERROR; import static java.lang.String.format; import static java.util.Objects.requireNonNull; @@ -39,15 +40,15 @@ public class ConfluentAvroReaderSupplier { private final Schema targetSchema; private final SchemaRegistryClient schemaRegistryClient; - private final LoadingCache> avroRecordReaderCache; + private final NonEvictableLoadingCache> avroRecordReaderCache; private ConfluentAvroReaderSupplier(Schema targetSchema, SchemaRegistryClient schemaRegistryClient) { this.targetSchema = requireNonNull(targetSchema, "targetSchema is null"); this.schemaRegistryClient = requireNonNull(schemaRegistryClient, "schemaRegistryClient is null"); - avroRecordReaderCache = CacheBuilder.newBuilder() - .maximumSize(1000) - .build(CacheLoader.from(this::lookupReader)); + avroRecordReaderCache = buildNonEvictableCache( + CacheBuilder.newBuilder().maximumSize(1000), + CacheLoader.from(this::lookupReader)); } private GenericDatumReader lookupReader(int id) diff --git a/plugin/trino-local-file/pom.xml b/plugin/trino-local-file/pom.xml index efbc7c33d4dd..7e365f2ce158 100644 --- a/plugin/trino-local-file/pom.xml +++ b/plugin/trino-local-file/pom.xml @@ -18,6 +18,11 @@ + + io.trino + trino-plugin-toolkit + + io.airlift bootstrap diff --git a/plugin/trino-local-file/src/main/java/io/trino/plugin/localfile/LocalFileTables.java b/plugin/trino-local-file/src/main/java/io/trino/plugin/localfile/LocalFileTables.java index 41e510177e47..a05ea0b56e32 100644 --- a/plugin/trino-local-file/src/main/java/io/trino/plugin/localfile/LocalFileTables.java +++ b/plugin/trino-local-file/src/main/java/io/trino/plugin/localfile/LocalFileTables.java @@ -15,10 +15,10 @@ import com.google.common.cache.CacheBuilder; import com.google.common.cache.CacheLoader; -import com.google.common.cache.LoadingCache; import com.google.common.collect.ImmutableList; import com.google.common.collect.ImmutableMap; import com.google.common.util.concurrent.UncheckedExecutionException; +import io.trino.plugin.base.cache.NonEvictableLoadingCache; import io.trino.spi.TrinoException; import io.trino.spi.connector.ColumnMetadata; import io.trino.spi.connector.SchemaTableName; @@ -33,6 +33,7 @@ import static com.google.common.base.Preconditions.checkArgument; import static com.google.common.base.Throwables.throwIfInstanceOf; +import static io.trino.plugin.base.cache.SafeCaches.buildNonEvictableCache; import static io.trino.plugin.localfile.LocalFileMetadata.PRESTO_LOGS_SCHEMA; import static io.trino.plugin.localfile.LocalFileMetadata.SERVER_ADDRESS_COLUMN; import static io.trino.plugin.localfile.LocalFileTables.HttpRequestLogTable.getSchemaTableName; @@ -49,7 +50,7 @@ public class LocalFileTables private final Map tables; private final Map> tableColumns; - private final LoadingCache> cachedFiles; + private final NonEvictableLoadingCache> cachedFiles; @Inject public LocalFileTables(LocalFileConfig config) @@ -78,9 +79,10 @@ public LocalFileTables(LocalFileConfig config) tableColumns = tableColumnsBuilder.buildOrThrow(); tableDataLocations = dataLocationBuilder.buildOrThrow(); - cachedFiles = CacheBuilder.newBuilder() - .expireAfterWrite(10, SECONDS) - .build(CacheLoader.from(key -> tableDataLocations.get(key).files())); + cachedFiles = buildNonEvictableCache( + CacheBuilder.newBuilder() + .expireAfterWrite(10, SECONDS), + CacheLoader.from(key -> tableDataLocations.get(key).files())); } public LocalFileTableHandle getTable(SchemaTableName tableName) diff --git a/plugin/trino-ml/pom.xml b/plugin/trino-ml/pom.xml index 70cae334047e..ba201ae1e9d2 100644 --- a/plugin/trino-ml/pom.xml +++ b/plugin/trino-ml/pom.xml @@ -22,6 +22,11 @@ trino-array + + io.trino + trino-plugin-toolkit + + io.airlift concurrent diff --git a/plugin/trino-ml/src/main/java/io/trino/plugin/ml/MLFunctions.java b/plugin/trino-ml/src/main/java/io/trino/plugin/ml/MLFunctions.java index 3ef4a80a5f86..dc72ed81ed0e 100644 --- a/plugin/trino-ml/src/main/java/io/trino/plugin/ml/MLFunctions.java +++ b/plugin/trino-ml/src/main/java/io/trino/plugin/ml/MLFunctions.java @@ -13,11 +13,11 @@ */ package io.trino.plugin.ml; -import com.google.common.cache.Cache; import com.google.common.cache.CacheBuilder; import com.google.common.hash.HashCode; import io.airlift.slice.Slice; import io.airlift.slice.Slices; +import io.trino.plugin.base.cache.NonEvictableCache; import io.trino.plugin.ml.type.RegressorType; import io.trino.spi.block.Block; import io.trino.spi.function.ScalarFunction; @@ -27,13 +27,14 @@ import java.util.concurrent.ExecutionException; import static com.google.common.base.Preconditions.checkArgument; +import static io.trino.plugin.base.cache.SafeCaches.buildNonEvictableCache; import static io.trino.plugin.ml.type.ClassifierType.BIGINT_CLASSIFIER; import static io.trino.plugin.ml.type.ClassifierType.VARCHAR_CLASSIFIER; import static io.trino.plugin.ml.type.RegressorType.REGRESSOR; public final class MLFunctions { - private static final Cache MODEL_CACHE = CacheBuilder.newBuilder().maximumSize(5).build(); + private static final NonEvictableCache MODEL_CACHE = buildNonEvictableCache(CacheBuilder.newBuilder().maximumSize(5)); private static final String MAP_BIGINT_DOUBLE = "map(bigint,double)"; private MLFunctions() diff --git a/plugin/trino-password-authenticators/pom.xml b/plugin/trino-password-authenticators/pom.xml index 1ec97d90a661..4b02f5b73bc2 100644 --- a/plugin/trino-password-authenticators/pom.xml +++ b/plugin/trino-password-authenticators/pom.xml @@ -18,6 +18,11 @@ + + io.trino + trino-plugin-toolkit + + io.airlift bootstrap diff --git a/plugin/trino-password-authenticators/src/main/java/io/trino/plugin/password/file/PasswordStore.java b/plugin/trino-password-authenticators/src/main/java/io/trino/plugin/password/file/PasswordStore.java index b5253b6deb3b..d69821a531d2 100644 --- a/plugin/trino-password-authenticators/src/main/java/io/trino/plugin/password/file/PasswordStore.java +++ b/plugin/trino-password-authenticators/src/main/java/io/trino/plugin/password/file/PasswordStore.java @@ -17,8 +17,8 @@ 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 io.trino.plugin.base.cache.NonEvictableLoadingCache; import io.trino.plugin.password.Credential; import io.trino.spi.TrinoException; @@ -29,6 +29,7 @@ import java.util.List; import java.util.Map; +import static io.trino.plugin.base.cache.SafeCaches.buildNonEvictableCache; import static io.trino.plugin.password.file.EncryptionUtil.doesBCryptPasswordMatch; import static io.trino.plugin.password.file.EncryptionUtil.doesPBKDF2PasswordMatch; import static io.trino.plugin.password.file.EncryptionUtil.getHashingAlgorithm; @@ -41,7 +42,7 @@ public class PasswordStore private static final Splitter LINE_SPLITTER = Splitter.on(":").limit(2); private final Map credentials; - private final LoadingCache cache; + private final NonEvictableLoadingCache cache; public PasswordStore(File file, int cacheMaxSize) { @@ -52,9 +53,9 @@ public PasswordStore(File file, int cacheMaxSize) public PasswordStore(List lines, int cacheMaxSize) { credentials = loadPasswordFile(lines); - cache = CacheBuilder.newBuilder() - .maximumSize(cacheMaxSize) - .build(CacheLoader.from(this::matches)); + cache = buildNonEvictableCache( + CacheBuilder.newBuilder().maximumSize(cacheMaxSize), + CacheLoader.from(this::matches)); } public boolean authenticate(String user, String password) diff --git a/plugin/trino-password-authenticators/src/main/java/io/trino/plugin/password/ldap/LdapAuthenticator.java b/plugin/trino-password-authenticators/src/main/java/io/trino/plugin/password/ldap/LdapAuthenticator.java index 12b563c43a40..d6ed41351978 100644 --- a/plugin/trino-password-authenticators/src/main/java/io/trino/plugin/password/ldap/LdapAuthenticator.java +++ b/plugin/trino-password-authenticators/src/main/java/io/trino/plugin/password/ldap/LdapAuthenticator.java @@ -17,9 +17,10 @@ import com.google.common.base.CharMatcher; 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 io.airlift.log.Logger; +import io.trino.plugin.base.cache.NonKeyEvictableLoadingCache; +import io.trino.plugin.base.cache.SafeCaches; import io.trino.plugin.password.Credential; import io.trino.spi.classloader.ThreadContextClassLoader; import io.trino.spi.security.AccessDeniedException; @@ -56,7 +57,7 @@ public class LdapAuthenticator private final Optional bindDistinguishedName; private final Optional bindPassword; - private final LoadingCache authenticationCache; + private final NonKeyEvictableLoadingCache authenticationCache; @Inject public LdapAuthenticator(LdapAuthenticatorClient client, LdapConfig ldapConfig) @@ -82,9 +83,10 @@ public LdapAuthenticator(LdapAuthenticatorClient client, LdapConfig ldapConfig) bindDistinguishedName.isPresent() || !userBindSearchPatterns.isEmpty(), "Either user bind search pattern or bind distinguished name must be provided"); - this.authenticationCache = CacheBuilder.newBuilder() - .expireAfterWrite(ldapConfig.getLdapCacheTtl().toMillis(), MILLISECONDS) - .build(CacheLoader.from(bindDistinguishedName.isPresent() + this.authenticationCache = SafeCaches.buildNonEvictableCacheWithWeakInvalidateAll( + CacheBuilder.newBuilder() + .expireAfterWrite(ldapConfig.getLdapCacheTtl().toMillis(), MILLISECONDS), + CacheLoader.from(bindDistinguishedName.isPresent() ? this::authenticateWithBindDistinguishedName : this::authenticateWithUserBind)); } diff --git a/plugin/trino-password-authenticators/src/main/java/io/trino/plugin/password/salesforce/SalesforceBasicAuthenticator.java b/plugin/trino-password-authenticators/src/main/java/io/trino/plugin/password/salesforce/SalesforceBasicAuthenticator.java index b512e7994f5a..4ca777c5c9d2 100644 --- a/plugin/trino-password-authenticators/src/main/java/io/trino/plugin/password/salesforce/SalesforceBasicAuthenticator.java +++ b/plugin/trino-password-authenticators/src/main/java/io/trino/plugin/password/salesforce/SalesforceBasicAuthenticator.java @@ -15,7 +15,6 @@ import com.google.common.cache.CacheBuilder; import com.google.common.cache.CacheLoader; -import com.google.common.cache.LoadingCache; import com.google.common.collect.ImmutableSet; import com.google.common.escape.Escaper; import com.google.common.util.concurrent.UncheckedExecutionException; @@ -23,6 +22,8 @@ import io.airlift.http.client.Request; import io.airlift.http.client.StringResponseHandler; import io.airlift.log.Logger; +import io.trino.plugin.base.cache.NonEvictableLoadingCache; +import io.trino.plugin.base.cache.SafeCaches; import io.trino.plugin.password.Credential; import io.trino.spi.security.AccessDeniedException; import io.trino.spi.security.BasicPrincipal; @@ -71,7 +72,7 @@ public class SalesforceBasicAuthenticator // Set of Salesforce orgs, which users must belong to in order to authN. private final Set allowedOrganizations; private final HttpClient httpClient; - private final LoadingCache userCache; + private final NonEvictableLoadingCache userCache; @Inject public SalesforceBasicAuthenticator(SalesforceConfig config, @SalesforceAuthenticationClient HttpClient httpClient) @@ -79,10 +80,11 @@ public SalesforceBasicAuthenticator(SalesforceConfig config, @SalesforceAuthenti this.allowedOrganizations = ImmutableSet.copyOf(config.getOrgSet()); this.httpClient = requireNonNull(httpClient, "httpClient is null"); - this.userCache = CacheBuilder.newBuilder() - .maximumSize(config.getCacheSize()) - .expireAfterWrite(config.getCacheExpireDuration().toMillis(), MILLISECONDS) - .build(CacheLoader.from(this::doLogin)); + this.userCache = SafeCaches.buildNonEvictableCache( + CacheBuilder.newBuilder() + .maximumSize(config.getCacheSize()) + .expireAfterWrite(config.getCacheExpireDuration().toMillis(), MILLISECONDS), + CacheLoader.from(this::doLogin)); } @Override diff --git a/plugin/trino-pinot/src/main/java/io/trino/plugin/pinot/PinotMetadata.java b/plugin/trino-pinot/src/main/java/io/trino/plugin/pinot/PinotMetadata.java index d304f52e7267..1502c88275a1 100755 --- a/plugin/trino-pinot/src/main/java/io/trino/plugin/pinot/PinotMetadata.java +++ b/plugin/trino-pinot/src/main/java/io/trino/plugin/pinot/PinotMetadata.java @@ -21,6 +21,7 @@ import com.google.common.collect.ImmutableMap; import com.google.common.collect.ImmutableSet; import io.airlift.log.Logger; +import io.trino.plugin.base.cache.NonEvictableLoadingCache; import io.trino.plugin.base.expression.AggregateFunctionRewriter; import io.trino.plugin.base.expression.AggregateFunctionRule; import io.trino.plugin.pinot.client.PinotClient; @@ -74,6 +75,7 @@ import static com.google.common.collect.ImmutableList.toImmutableList; import static com.google.common.collect.ImmutableMap.toImmutableMap; import static com.google.common.collect.Iterables.getOnlyElement; +import static io.trino.plugin.base.cache.SafeCaches.buildNonEvictableCache; import static io.trino.plugin.pinot.PinotColumnHandle.getPinotColumnsForPinotSchema; import static io.trino.plugin.pinot.PinotSessionProperties.isAggregationPushdownEnabled; import static io.trino.plugin.pinot.query.AggregateExpression.replaceIdentifier; @@ -90,8 +92,8 @@ public class PinotMetadata private static final String SCHEMA_NAME = "default"; private static final String PINOT_COLUMN_NAME_PROPERTY = "pinotColumnName"; - private final LoadingCache> pinotTableColumnCache; - private final LoadingCache> allTablesCache; + private final NonEvictableLoadingCache> pinotTableColumnCache; + private final NonEvictableLoadingCache> allTablesCache; private final int maxRowsPerBrokerQuery; private final AggregateFunctionRewriter aggregateFunctionRewriter; private final ImplementCountDistinct implementCountDistinct; @@ -106,22 +108,23 @@ public PinotMetadata( requireNonNull(pinotConfig, "pinot config"); this.pinotClient = requireNonNull(pinotClient, "pinotClient is null"); long metadataCacheExpiryMillis = pinotConfig.getMetadataCacheExpiry().roundTo(TimeUnit.MILLISECONDS); - this.allTablesCache = CacheBuilder.newBuilder() - .refreshAfterWrite(metadataCacheExpiryMillis, TimeUnit.MILLISECONDS) - .build(asyncReloading(CacheLoader.from(pinotClient::getAllTables), executor)); - this.pinotTableColumnCache = + this.allTablesCache = buildNonEvictableCache( CacheBuilder.newBuilder() - .refreshAfterWrite(metadataCacheExpiryMillis, TimeUnit.MILLISECONDS) - .build(asyncReloading(new CacheLoader<>() - { - @Override - public List load(String tableName) - throws Exception - { - Schema tablePinotSchema = pinotClient.getTableSchema(tableName); - return getPinotColumnsForPinotSchema(tablePinotSchema); - } - }, executor)); + .refreshAfterWrite(metadataCacheExpiryMillis, TimeUnit.MILLISECONDS), + asyncReloading(CacheLoader.from(pinotClient::getAllTables), executor)); + this.pinotTableColumnCache = buildNonEvictableCache( + CacheBuilder.newBuilder() + .refreshAfterWrite(metadataCacheExpiryMillis, TimeUnit.MILLISECONDS), + asyncReloading(new CacheLoader<>() + { + @Override + public List load(String tableName) + throws Exception + { + Schema tablePinotSchema = pinotClient.getTableSchema(tableName); + return getPinotColumnsForPinotSchema(tablePinotSchema); + } + }, executor)); executor.execute(() -> this.allTablesCache.refresh(ALL_TABLES_CACHE_KEY)); this.maxRowsPerBrokerQuery = pinotConfig.getMaxRowsForBrokerQueries(); diff --git a/plugin/trino-pinot/src/main/java/io/trino/plugin/pinot/client/PinotClient.java b/plugin/trino-pinot/src/main/java/io/trino/plugin/pinot/client/PinotClient.java index 3f31d5752e90..558664d3f8a6 100755 --- a/plugin/trino-pinot/src/main/java/io/trino/plugin/pinot/client/PinotClient.java +++ b/plugin/trino-pinot/src/main/java/io/trino/plugin/pinot/client/PinotClient.java @@ -20,7 +20,6 @@ import com.google.common.annotations.VisibleForTesting; import com.google.common.cache.CacheBuilder; import com.google.common.cache.CacheLoader; -import com.google.common.cache.LoadingCache; import com.google.common.collect.AbstractIterator; import com.google.common.collect.ImmutableList; import com.google.common.collect.ImmutableMap; @@ -35,6 +34,7 @@ import io.airlift.json.JsonCodecBinder; import io.airlift.json.JsonCodecFactory; import io.airlift.log.Logger; +import io.trino.plugin.base.cache.NonEvictableLoadingCache; import io.trino.plugin.pinot.ForPinot; import io.trino.plugin.pinot.PinotColumnHandle; import io.trino.plugin.pinot.PinotConfig; @@ -80,6 +80,7 @@ import static io.airlift.json.JsonCodec.jsonCodec; import static io.airlift.json.JsonCodec.listJsonCodec; import static io.airlift.json.JsonCodec.mapJsonCodec; +import static io.trino.plugin.base.cache.SafeCaches.buildNonEvictableCache; import static io.trino.plugin.pinot.PinotErrorCode.PINOT_EXCEPTION; import static io.trino.plugin.pinot.PinotErrorCode.PINOT_INVALID_CONFIGURATION; import static io.trino.plugin.pinot.PinotErrorCode.PINOT_UNABLE_TO_FIND_BROKER; @@ -109,7 +110,7 @@ public class PinotClient private final HttpClient httpClient; private final PinotHostMapper pinotHostMapper; - private final LoadingCache> brokersForTableCache; + private final NonEvictableLoadingCache> brokersForTableCache; private final JsonCodec tablesJsonCodec; private final JsonCodec brokersForTableJsonCodec; @@ -145,9 +146,10 @@ public PinotClient( this.controllerUrls = config.getControllerUrls(); this.httpClient = requireNonNull(httpClient, "httpClient is null"); - this.brokersForTableCache = CacheBuilder.newBuilder() - .expireAfterWrite(config.getMetadataCacheExpiry().roundTo(TimeUnit.MILLISECONDS), TimeUnit.MILLISECONDS) - .build((CacheLoader.from(this::getAllBrokersForTable))); + this.brokersForTableCache = buildNonEvictableCache( + CacheBuilder.newBuilder() + .expireAfterWrite(config.getMetadataCacheExpiry().roundTo(TimeUnit.MILLISECONDS), TimeUnit.MILLISECONDS), + CacheLoader.from(this::getAllBrokersForTable)); this.controllerAuthenticationProvider = controllerAuthenticationProvider; this.brokerAuthenticationProvider = brokerAuthenticationProvider; } diff --git a/plugin/trino-raptor-legacy/pom.xml b/plugin/trino-raptor-legacy/pom.xml index 8c0fc66713e8..6f5ff8a29350 100644 --- a/plugin/trino-raptor-legacy/pom.xml +++ b/plugin/trino-raptor-legacy/pom.xml @@ -151,6 +151,11 @@ 5.1.48 + + org.gaul + modernizer-maven-annotations + + org.jdbi jdbi3-core diff --git a/plugin/trino-raptor-legacy/src/main/java/io/trino/plugin/raptor/legacy/metadata/DatabaseShardManager.java b/plugin/trino-raptor-legacy/src/main/java/io/trino/plugin/raptor/legacy/metadata/DatabaseShardManager.java index ffcb3dfe5e34..36aece02661e 100644 --- a/plugin/trino-raptor-legacy/src/main/java/io/trino/plugin/raptor/legacy/metadata/DatabaseShardManager.java +++ b/plugin/trino-raptor-legacy/src/main/java/io/trino/plugin/raptor/legacy/metadata/DatabaseShardManager.java @@ -17,7 +17,6 @@ import com.google.common.base.Ticker; import com.google.common.cache.CacheBuilder; import com.google.common.cache.CacheLoader; -import com.google.common.cache.LoadingCache; import com.google.common.collect.ImmutableList; import com.google.common.collect.ImmutableSet; import com.google.common.collect.Iterables; @@ -25,6 +24,7 @@ import com.google.common.util.concurrent.UncheckedExecutionException; import io.airlift.log.Logger; import io.airlift.units.Duration; +import io.trino.plugin.base.cache.NonEvictableLoadingCache; import io.trino.plugin.raptor.legacy.NodeSupplier; import io.trino.plugin.raptor.legacy.RaptorColumnHandle; import io.trino.plugin.raptor.legacy.storage.organization.ShardOrganizerDao; @@ -64,6 +64,7 @@ import static com.google.common.base.Throwables.throwIfInstanceOf; import static com.google.common.base.Verify.verify; import static com.google.common.collect.Iterables.partition; +import static io.trino.plugin.base.cache.SafeCaches.buildNonEvictableCache; import static io.trino.plugin.raptor.legacy.RaptorErrorCode.RAPTOR_ERROR; import static io.trino.plugin.raptor.legacy.RaptorErrorCode.RAPTOR_EXTERNAL_BATCH_ALREADY_EXISTS; import static io.trino.plugin.raptor.legacy.storage.ColumnIndexStatsUtils.jdbcType; @@ -111,13 +112,13 @@ public class DatabaseShardManager private final Duration startupGracePeriod; private final long startTime; - private final LoadingCache nodeIdCache = CacheBuilder.newBuilder() - .maximumSize(10_000) - .build(CacheLoader.from(this::loadNodeId)); + private final NonEvictableLoadingCache nodeIdCache = buildNonEvictableCache( + CacheBuilder.newBuilder().maximumSize(10_000), + CacheLoader.from(this::loadNodeId)); - private final LoadingCache> bucketAssignmentsCache = CacheBuilder.newBuilder() - .expireAfterWrite(1, SECONDS) - .build(CacheLoader.from(this::loadBucketAssignments)); + private final NonEvictableLoadingCache> bucketAssignmentsCache = buildNonEvictableCache( + CacheBuilder.newBuilder().expireAfterWrite(1, SECONDS), + CacheLoader.from(this::loadBucketAssignments)); @Inject public DatabaseShardManager( diff --git a/plugin/trino-raptor-legacy/src/main/java/io/trino/plugin/raptor/legacy/storage/ShardRecoveryManager.java b/plugin/trino-raptor-legacy/src/main/java/io/trino/plugin/raptor/legacy/storage/ShardRecoveryManager.java index 0a09b31068d2..ad5475497d8a 100644 --- a/plugin/trino-raptor-legacy/src/main/java/io/trino/plugin/raptor/legacy/storage/ShardRecoveryManager.java +++ b/plugin/trino-raptor-legacy/src/main/java/io/trino/plugin/raptor/legacy/storage/ShardRecoveryManager.java @@ -28,6 +28,7 @@ import io.trino.plugin.raptor.legacy.util.PrioritizedFifoExecutor; import io.trino.spi.NodeManager; import io.trino.spi.TrinoException; +import org.gaul.modernizer_maven_annotations.SuppressModernizer; import org.weakref.jmx.Flatten; import org.weakref.jmx.Managed; @@ -416,7 +417,7 @@ private class MissingShardsQueue public MissingShardsQueue(PrioritizedFifoExecutor shardRecoveryExecutor) { requireNonNull(shardRecoveryExecutor, "shardRecoveryExecutor is null"); - this.queuedMissingShards = CacheBuilder.newBuilder().build(new CacheLoader<>() + this.queuedMissingShards = buildUnsafeCache(CacheBuilder.newBuilder(), new CacheLoader<>() { @Override public ListenableFuture load(MissingShard missingShard) @@ -427,14 +428,20 @@ public ListenableFuture load(MissingShard missingShard) missingShard.getShardXxhash64(), missingShard.isActive()); ListenableFuture future = shardRecoveryExecutor.submit(task); - // TODO this may not invalidate ongoing loads (https://github.com/trinodb/trino/issues/10512, https://github.com/google/guava/issues/1881). - // Determine whether this is OK here. + // TODO (https://github.com/trinodb/trino/issues/10688) invalidation here races with `.load()` completion future.addListener(() -> queuedMissingShards.invalidate(missingShard), directExecutor()); return future; } }); } + // TODO (https://github.com/trinodb/trino/issues/10688) there is a load/invalidation race, so it's an unsafe suppression + @SuppressModernizer + private LoadingCache buildUnsafeCache(CacheBuilder cacheBuilder, CacheLoader cacheLoader) + { + return cacheBuilder.build(cacheLoader); + } + public ListenableFuture submit(MissingShard shard) throws ExecutionException { diff --git a/plugin/trino-sqlserver/src/main/java/io/trino/plugin/sqlserver/SqlServerClient.java b/plugin/trino-sqlserver/src/main/java/io/trino/plugin/sqlserver/SqlServerClient.java index 4f8874b91908..b646bdcb28a1 100644 --- a/plugin/trino-sqlserver/src/main/java/io/trino/plugin/sqlserver/SqlServerClient.java +++ b/plugin/trino-sqlserver/src/main/java/io/trino/plugin/sqlserver/SqlServerClient.java @@ -16,13 +16,13 @@ import com.google.common.base.Enums; import com.google.common.base.Joiner; import com.google.common.base.Throwables; -import com.google.common.cache.Cache; import com.google.common.cache.CacheBuilder; import com.google.common.collect.ImmutableMap; import com.google.common.collect.ImmutableSet; import com.microsoft.sqlserver.jdbc.SQLServerException; import io.airlift.log.Logger; import io.airlift.slice.Slice; +import io.trino.plugin.base.cache.NonEvictableCache; import io.trino.plugin.base.expression.AggregateFunctionRewriter; import io.trino.plugin.base.expression.AggregateFunctionRule; import io.trino.plugin.jdbc.BaseJdbcClient; @@ -97,6 +97,7 @@ import static com.google.common.util.concurrent.MoreExecutors.directExecutor; import static com.microsoft.sqlserver.jdbc.SQLServerConnection.TRANSACTION_SNAPSHOT; import static io.airlift.slice.Slices.wrappedBuffer; +import static io.trino.plugin.base.cache.SafeCaches.buildNonEvictableCache; import static io.trino.plugin.jdbc.JdbcErrorCode.JDBC_ERROR; import static io.trino.plugin.jdbc.PredicatePushdownController.DISABLE_PUSHDOWN; import static io.trino.plugin.jdbc.StandardColumnMappings.bigintColumnMapping; @@ -183,10 +184,10 @@ public class SqlServerClient private static final Joiner DOT_JOINER = Joiner.on("."); private final boolean snapshotIsolationDisabled; - private final Cache snapshotIsolationEnabled = CacheBuilder.newBuilder() - .maximumSize(1) - .expireAfterWrite(ofMinutes(5)) - .build(); + private final NonEvictableCache snapshotIsolationEnabled = buildNonEvictableCache( + CacheBuilder.newBuilder() + .maximumSize(1) + .expireAfterWrite(ofMinutes(5))); private final AggregateFunctionRewriter aggregateFunctionRewriter; diff --git a/plugin/trino-thrift/src/main/java/io/trino/plugin/thrift/ThriftMetadata.java b/plugin/trino-thrift/src/main/java/io/trino/plugin/thrift/ThriftMetadata.java index 663597f03883..02ac44e287f9 100644 --- a/plugin/trino-thrift/src/main/java/io/trino/plugin/thrift/ThriftMetadata.java +++ b/plugin/trino-thrift/src/main/java/io/trino/plugin/thrift/ThriftMetadata.java @@ -15,12 +15,12 @@ import com.google.common.cache.CacheBuilder; import com.google.common.cache.CacheLoader; -import com.google.common.cache.LoadingCache; import com.google.common.collect.ImmutableList; import com.google.common.collect.ImmutableSet; import io.airlift.drift.TException; import io.airlift.drift.client.DriftClient; import io.airlift.units.Duration; +import io.trino.plugin.base.cache.NonEvictableLoadingCache; import io.trino.plugin.thrift.annotations.ForMetadataRefresh; import io.trino.plugin.thrift.api.TrinoThriftNullableSchemaName; import io.trino.plugin.thrift.api.TrinoThriftNullableTableMetadata; @@ -59,6 +59,7 @@ import static com.google.common.cache.CacheLoader.asyncReloading; import static com.google.common.collect.ImmutableList.toImmutableList; import static com.google.common.collect.ImmutableMap.toImmutableMap; +import static io.trino.plugin.base.cache.SafeCaches.buildNonEvictableCache; import static io.trino.plugin.thrift.ThriftErrorCode.THRIFT_SERVICE_INVALID_RESPONSE; import static io.trino.plugin.thrift.util.ThriftExceptions.toTrinoException; import static java.util.Objects.requireNonNull; @@ -75,7 +76,7 @@ public class ThriftMetadata private final DriftClient client; private final ThriftHeaderProvider thriftHeaderProvider; private final TypeManager typeManager; - private final LoadingCache> tableCache; + private final NonEvictableLoadingCache> tableCache; @Inject public ThriftMetadata( @@ -87,10 +88,11 @@ public ThriftMetadata( this.client = requireNonNull(client, "client is null"); this.thriftHeaderProvider = requireNonNull(thriftHeaderProvider, "thriftHeaderProvider is null"); this.typeManager = requireNonNull(typeManager, "typeManager is null"); - this.tableCache = CacheBuilder.newBuilder() - .expireAfterWrite(EXPIRE_AFTER_WRITE.toMillis(), MILLISECONDS) - .refreshAfterWrite(REFRESH_AFTER_WRITE.toMillis(), MILLISECONDS) - .build(asyncReloading(CacheLoader.from(this::getTableMetadataInternal), metadataRefreshExecutor)); + this.tableCache = buildNonEvictableCache( + CacheBuilder.newBuilder() + .expireAfterWrite(EXPIRE_AFTER_WRITE.toMillis(), MILLISECONDS) + .refreshAfterWrite(REFRESH_AFTER_WRITE.toMillis(), MILLISECONDS), + asyncReloading(CacheLoader.from(this::getTableMetadataInternal), metadataRefreshExecutor)); } @Override diff --git a/pom.xml b/pom.xml index 809e21592c8a..2ad442573bc3 100644 --- a/pom.xml +++ b/pom.xml @@ -1454,6 +1454,13 @@ 7.15.0 + + + org.gaul + modernizer-maven-annotations + 2.3.0 + + org.javassist