Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Minor updates to JDBC caching client #8652

Merged
merged 3 commits into from
Aug 9, 2021
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
5 changes: 5 additions & 0 deletions plugin/trino-base-jdbc/pom.xml
Original file line number Diff line number Diff line change
Expand Up @@ -43,6 +43,11 @@
<artifactId>configuration</artifactId>
</dependency>

<dependency>
<groupId>io.airlift</groupId>
<artifactId>jmx</artifactId>
</dependency>

<dependency>
<groupId>io.airlift</groupId>
<artifactId>log</artifactId>
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -20,21 +20,27 @@
import io.airlift.units.Duration;
import io.airlift.units.MinDuration;

import javax.annotation.PostConstruct;
import javax.validation.constraints.Min;
import javax.validation.constraints.NotNull;
import javax.validation.constraints.Pattern;

import java.util.Set;

import static com.google.common.base.Strings.nullToEmpty;
import static java.util.concurrent.TimeUnit.MINUTES;
import static java.lang.String.format;
import static java.util.concurrent.TimeUnit.MILLISECONDS;
import static javax.validation.constraints.Pattern.Flag.CASE_INSENSITIVE;

public class BaseJdbcConfig
{
private String connectionUrl;
private Set<String> jdbcTypesMappedToVarchar = ImmutableSet.of();
private Duration metadataCacheTtl = new Duration(0, MINUTES);
public static final Duration CACHING_DISABLED = new Duration(0, MILLISECONDS);
private Duration metadataCacheTtl = CACHING_DISABLED;
private boolean cacheMissing;
public static final long DEFAULT_METADATA_CACHE_SIZE = 10000;
private long cacheMaximumSize = DEFAULT_METADATA_CACHE_SIZE;

@NotNull
// Some drivers match case insensitive in Driver.acceptURL
Expand Down Expand Up @@ -90,4 +96,27 @@ public BaseJdbcConfig setCacheMissing(boolean cacheMissing)
this.cacheMissing = cacheMissing;
return this;
}

@Min(1)
public long getCacheMaximumSize()
{
return cacheMaximumSize;
}

@Config("metadata.cache-maximum-size")
@ConfigDescription("Maximum number of objects stored in the metadata cache")
public BaseJdbcConfig setCacheMaximumSize(long cacheMaximumSize)
{
this.cacheMaximumSize = cacheMaximumSize;
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

do we want to reject configuration like

metadata.cache-maximum-size = 100
# metadata.cache-ttl is not set

?

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Yes, that is a good idea. As an admin, it would be nice to know that changing the cache size does not enable the cache unless cache-til is set.

I added a validation method that validates the cache config to do this.

return this;
}

@PostConstruct
public void validate()
{
if (metadataCacheTtl.equals(CACHING_DISABLED) && cacheMaximumSize != BaseJdbcConfig.DEFAULT_METADATA_CACHE_SIZE) {
throw new IllegalArgumentException(
format("metadata.cache-ttl must be set to a non-zero value when metadata.cache-maximum-size is set"));
}
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -19,6 +19,7 @@
import com.google.common.cache.CacheStats;
import com.google.common.collect.ImmutableMap;
import com.google.common.util.concurrent.UncheckedExecutionException;
import io.airlift.jmx.CacheStatsMBean;
import io.airlift.units.Duration;
import io.trino.plugin.base.session.SessionPropertiesProvider;
import io.trino.plugin.jdbc.IdentityCacheMapping.IdentityCacheKey;
Expand All @@ -38,6 +39,8 @@
import io.trino.spi.session.PropertyMetadata;
import io.trino.spi.statistics.TableStatistics;
import io.trino.spi.type.Type;
import org.weakref.jmx.Managed;
import org.weakref.jmx.Nested;

import javax.inject.Inject;

Expand All @@ -60,14 +63,14 @@
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.jdbc.BaseJdbcConfig.CACHING_DISABLED;
import static java.util.Objects.requireNonNull;
import static java.util.concurrent.TimeUnit.MILLISECONDS;

public class CachingJdbcClient
implements JdbcClient
{
private static final Object NULL_MARKER = new Object();
private static final Duration CACHING_DISABLED = new Duration(0, MILLISECONDS);

private final JdbcClient delegate;
private final List<PropertyMetadata<?>> sessionProperties;
Expand All @@ -87,15 +90,16 @@ public CachingJdbcClient(
IdentityCacheMapping identityMapping,
BaseJdbcConfig config)
{
this(delegate, sessionPropertiesProviders, identityMapping, config.getMetadataCacheTtl(), config.isCacheMissing());
this(delegate, sessionPropertiesProviders, identityMapping, config.getMetadataCacheTtl(), config.isCacheMissing(), config.getCacheMaximumSize());
}

public CachingJdbcClient(
JdbcClient delegate,
Set<SessionPropertiesProvider> sessionPropertiesProviders,
IdentityCacheMapping identityMapping,
Duration metadataCachingTtl,
boolean cacheMissing)
boolean cacheMissing,
long cacheMaximumSize)
{
this.delegate = requireNonNull(delegate, "delegate is null");
this.sessionProperties = requireNonNull(sessionPropertiesProviders, "sessionPropertiesProviders is null").stream()
Expand All @@ -112,6 +116,9 @@ public CachingJdbcClient(
// Disables the cache entirely
cacheBuilder.maximumSize(0);
}
else {
cacheBuilder.maximumSize(cacheMaximumSize);
}

schemaNamesCache = cacheBuilder.build();
tableNamesCache = cacheBuilder.build();
Expand Down Expand Up @@ -460,6 +467,16 @@ public OptionalLong delete(ConnectorSession session, JdbcTableHandle handle)
return deletedRowsCount;
}

@Managed
public void flushCache()
{
schemaNamesCache.invalidateAll();
tableNamesCache.invalidateAll();
tableHandleCache.invalidateAll();
columnsCache.invalidateAll();
statisticsCache.invalidateAll();
}

private IdentityCacheKey getIdentityKey(ConnectorSession session)
{
return identityMapping.getRemoteUserCacheKey(session.getIdentity());
Expand Down Expand Up @@ -683,4 +700,39 @@ public int hashCode()
return Objects.hash(tableHandle, tupleDomain);
}
}

@Managed
@Nested
public CacheStatsMBean getSchemaNamesStats()
{
return new CacheStatsMBean(schemaNamesCache);
}

@Managed
@Nested
public CacheStatsMBean getTableNamesCache()
{
return new CacheStatsMBean(tableNamesCache);
}

@Managed
@Nested
public CacheStatsMBean getTableHandleCache()
{
return new CacheStatsMBean(tableHandleCache);
}

@Managed
@Nested
public CacheStatsMBean getColumnsCache()
{
return new CacheStatsMBean(columnsCache);
}

@Managed
@Nested
public CacheStatsMBean getStatisticsCache()
{
return new CacheStatsMBean(statisticsCache);
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -45,7 +45,9 @@ public JdbcMetadata create(JdbcTransactionHandle transaction)
jdbcClient,
Set.of(),
new SingletonIdentityCacheMapping(),
new Duration(1, DAYS), true),
new Duration(1, DAYS),
true,
Integer.MAX_VALUE),
allowDropTable);
}

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -46,6 +46,8 @@ public void configure(Binder binder)
.as(generator -> generator.generatedNameOf(JdbcClient.class, catalogName.get().toString()));
newExporter(binder).export(Key.get(ConnectionFactory.class, StatsCollecting.class))
.as(generator -> generator.generatedNameOf(ConnectionFactory.class, catalogName.get().toString()));
newExporter(binder).export(JdbcClient.class)
.as(generator -> generator.generatedNameOf(CachingJdbcClient.class, catalogName.get().toString()));
}

@Provides
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -31,14 +31,17 @@

public class TestBaseJdbcConfig
{
private static final Duration ZERO = Duration.succinctDuration(0, MINUTES);

@Test
public void testDefaults()
{
assertRecordedDefaults(recordDefaults(BaseJdbcConfig.class)
.setConnectionUrl(null)
.setJdbcTypesMappedToVarchar("")
.setMetadataCacheTtl(new Duration(0, MINUTES))
.setCacheMissing(false));
.setMetadataCacheTtl(ZERO)
.setCacheMissing(false)
.setCacheMaximumSize(10000));
}

@Test
Expand All @@ -49,13 +52,15 @@ public void testExplicitPropertyMappings()
.put("jdbc-types-mapped-to-varchar", "mytype,struct_type1")
.put("metadata.cache-ttl", "1s")
.put("metadata.cache-missing", "true")
.put("metadata.cache-maximum-size", "5000")
.build();

BaseJdbcConfig expected = new BaseJdbcConfig()
.setConnectionUrl("jdbc:h2:mem:config")
.setJdbcTypesMappedToVarchar("mytype, struct_type1")
.setMetadataCacheTtl(new Duration(1, SECONDS))
.setCacheMissing(true);
.setCacheMissing(true)
.setCacheMaximumSize(5000);

assertFullMapping(properties, expected);

Expand All @@ -73,6 +78,24 @@ public void testConnectionUrlIsValid()
buildConfig(ImmutableMap.of("connection-url", "jdbc:protocol:"));
}

@Test
public void testCacheConfigValidation()
{
BaseJdbcConfig explicitCacheSize = new BaseJdbcConfig()
.setMetadataCacheTtl(new Duration(1, SECONDS))
.setCacheMaximumSize(5000);
explicitCacheSize.validate();
BaseJdbcConfig defaultCacheSize = new BaseJdbcConfig()
.setMetadataCacheTtl(new Duration(1, SECONDS));
defaultCacheSize.validate();
assertThatThrownBy(() -> new BaseJdbcConfig()
.setMetadataCacheTtl(ZERO)
.setCacheMaximumSize(100000)
.validate())
.isInstanceOf(IllegalArgumentException.class)
.hasMessageMatching("metadata.cache-ttl must be set to a non-zero value when metadata.cache-maximum-size is set");
}

private static void buildConfig(Map<String, String> properties)
{
ConfigurationFactory configurationFactory = new ConfigurationFactory(properties);
Expand Down
Loading