Skip to content

Commit 5eb949d

Browse files
authored
Include planner configuration in the QueryCacheKey (#3463)
This includes part of the planner configurations and the index fetch method in the plan cache primary key. It resolves #3479.
1 parent ac66a19 commit 5eb949d

File tree

23 files changed

+558
-371
lines changed

23 files changed

+558
-371
lines changed

fdb-record-layer-core/src/main/java/com/apple/foundationdb/record/query/plan/RecordQueryPlannerConfiguration.java

Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -281,6 +281,15 @@ public boolean isRuleEnabled(@Nonnull PlannerRule<?, ?> rule) {
281281
return !disabledTransformationRules.contains(rule.getClass().getSimpleName());
282282
}
283283

284+
/**
285+
* Returns the set of disabled transformation rules.
286+
* @return set of disabled transformation rules.
287+
*/
288+
@Nonnull
289+
public Set<String> getDisabledTransformationRules() {
290+
return disabledTransformationRules;
291+
}
292+
284293
/**
285294
* Return whether the query planner should defer cross products during join enumeration.
286295
* <br>

fdb-relational-api/src/main/java/com/apple/foundationdb/relational/api/Options.java

Lines changed: 6 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -133,7 +133,9 @@ public enum Name {
133133
* By default, no rules are disabled, and the user should be able to leave this
134134
* unset. This is intended as an escape hatch in case the introduction of a new
135135
* planner rule causes trouble for an existing query.
136-
*
136+
* <p>
137+
* This option is experimental, and is meant to be used for debugging purposes only.
138+
* </p>
137139
* Scope: Connection, Query
138140
*/
139141
DISABLED_PLANNER_RULES,
@@ -145,7 +147,9 @@ public enum Name {
145147
* the planning phase may now need to match a more complicated query, but it can
146148
* be used as a way to disable the rewrite phase if certain queries either
147149
* encounter an error or take too much time exploring different rewrites.
148-
*
150+
* <p>
151+
* This option is experimental, and is meant to be used for debugging purposes only.
152+
* </p>
149153
* Scope: Connection, Query
150154
*/
151155
DISABLE_PLANNER_REWRITING,

fdb-relational-core/src/main/java/com/apple/foundationdb/relational/recordlayer/AbstractEmbeddedStatement.java

Lines changed: 4 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -64,7 +64,8 @@ public AbstractEmbeddedStatement(@Nonnull final EmbeddedRelationalConnection con
6464
}
6565

6666
@Nonnull
67-
abstract PlanContext buildPlanContext(@Nonnull FDBRecordStoreBase<?> store) throws RelationalException;
67+
abstract PlanContext createPlanContext(@Nonnull FDBRecordStoreBase<?> store,
68+
@Nonnull Options options) throws RelationalException;
6869

6970
@SuppressWarnings("PMD.PreserveStackTrace")
7071
public boolean executeInternal(String sql) throws SQLException, RelationalException {
@@ -81,8 +82,8 @@ public boolean executeInternal(String sql) throws SQLException, RelationalExcept
8182
try (var schema = conn.getRecordLayerDatabase().loadSchema(conn.getSchema())) {
8283
final var planCacheMaybe = Optional.ofNullable(conn.getRecordLayerDatabase().getPlanCache());
8384
final var store = schema.loadStore().unwrap(FDBRecordStoreBase.class);
84-
final var planGenerator = PlanGenerator.of(planCacheMaybe,
85-
buildPlanContext(store),
85+
final var planGenerator = PlanGenerator.create(planCacheMaybe,
86+
createPlanContext(store, options),
8687
store.getRecordMetaData(),
8788
store.getRecordStoreState(), this.options);
8889
final Plan<?> plan = planGenerator.getPlan(sql);

fdb-relational-core/src/main/java/com/apple/foundationdb/relational/recordlayer/EmbeddedRelationalPreparedStatement.java

Lines changed: 3 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -23,6 +23,7 @@
2323
import com.apple.foundationdb.annotation.API;
2424

2525
import com.apple.foundationdb.record.provider.foundationdb.FDBRecordStoreBase;
26+
import com.apple.foundationdb.relational.api.Options;
2627
import com.apple.foundationdb.relational.api.RelationalPreparedStatement;
2728
import com.apple.foundationdb.relational.api.RelationalResultSet;
2829
import com.apple.foundationdb.relational.api.exceptions.ErrorCode;
@@ -216,9 +217,9 @@ public void setNull(String parameterName, int sqlType) throws SQLException {
216217

217218
@Override
218219
@Nonnull
219-
PlanContext buildPlanContext(final @Nonnull FDBRecordStoreBase<?> store) throws RelationalException {
220+
PlanContext createPlanContext(@Nonnull final FDBRecordStoreBase<?> store, @Nonnull final Options options) throws RelationalException {
220221
return PlanContext.builder()
221-
.fromRecordStore(store)
222+
.fromRecordStore(store, options)
222223
.fromDatabase(conn.getRecordLayerDatabase())
223224
.withMetricsCollector(Assert.notNullUnchecked(conn.getMetricCollector()))
224225
.withPreparedParameters(PreparedParams.of(parameters, namedParameters))

fdb-relational-core/src/main/java/com/apple/foundationdb/relational/recordlayer/EmbeddedRelationalStatement.java

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -58,9 +58,9 @@ public EmbeddedRelationalStatement(@Nonnull EmbeddedRelationalConnection conn) t
5858

5959
@Override
6060
@Nonnull
61-
PlanContext buildPlanContext(final @Nonnull FDBRecordStoreBase<?> store) throws RelationalException {
61+
PlanContext createPlanContext(@Nonnull final FDBRecordStoreBase<?> store, @Nonnull final Options options) throws RelationalException {
6262
return PlanContext.builder()
63-
.fromRecordStore(store)
63+
.fromRecordStore(store, options)
6464
.fromDatabase(conn.getRecordLayerDatabase())
6565
.withMetricsCollector(Assert.notNullUnchecked(conn.getMetricCollector()))
6666
.withSchemaTemplate(conn.getTransaction().getBoundSchemaTemplateMaybe().orElse(conn.getSchemaTemplate()))

fdb-relational-core/src/main/java/com/apple/foundationdb/relational/recordlayer/query/AstNormalizer.java

Lines changed: 40 additions & 40 deletions
Original file line numberDiff line numberDiff line change
@@ -59,7 +59,6 @@
5959
import java.sql.ResultSet;
6060
import java.sql.SQLException;
6161
import java.sql.Struct;
62-
import java.util.BitSet;
6362
import java.util.EnumSet;
6463
import java.util.HashMap;
6564
import java.util.Map;
@@ -78,7 +77,7 @@
7877
* <li>understand parameters necessary for execution: limit, offset, continuation, and explain flag. These parameters are
7978
* necessary for Relational to prepare the plan for execution.</li>
8079
* <li>process in-predicate and generate array literal of the in-list contains simple constants.</li>
81-
* <li>identify query caching flags that might influence its interaction with plan cache (see {@link Result.QueryCachingFlags}).</li>
80+
* <li>identify query caching flags that might influence its interaction with plan cache (see {@link NormalizationResult.QueryCachingFlags}).</li>
8281
* </ul>
8382
* <p>
8483
* The visitor is designed to be very fast;
@@ -135,7 +134,7 @@ public final class AstNormalizer extends RelationalParserBaseVisitor<Object> {
135134
private final PreparedParams preparedStatementParameters;
136135

137136
@Nonnull
138-
private final Set<Result.QueryCachingFlags> queryCachingFlags;
137+
private final Set<NormalizationResult.QueryCachingFlags> queryCachingFlags;
139138

140139
@Nonnull
141140
private final Options.Builder queryOptions;
@@ -165,7 +164,7 @@ private AstNormalizer(@Nonnull final PreparedParams preparedStatementParameters,
165164
this.preparedStatementParameters = preparedStatementParameters;
166165
allowTokenAddition = true;
167166
allowLiteralAddition = true;
168-
queryCachingFlags = EnumSet.noneOf(Result.QueryCachingFlags.class);
167+
queryCachingFlags = EnumSet.noneOf(NormalizationResult.QueryCachingFlags.class);
169168
queryOptions = Options.builder();
170169
this.caseSensitive = caseSensitive;
171170
}
@@ -224,7 +223,7 @@ public String getCanonicalSqlString() {
224223
}
225224

226225
@Nonnull
227-
public Set<Result.QueryCachingFlags> getQueryCachingFlags() {
226+
public Set<NormalizationResult.QueryCachingFlags> getQueryCachingFlags() {
228227
return queryCachingFlags;
229228
}
230229

@@ -267,7 +266,7 @@ public Void visitLimitClauseAtom(RelationalParser.LimitClauseAtomContext ctx) {
267266
@Override
268267
public Object visitQuery(@Nonnull RelationalParser.QueryContext ctx) {
269268
if (queryCachingFlags.isEmpty()) {
270-
queryCachingFlags.add(Result.QueryCachingFlags.IS_DQL_STATEMENT);
269+
queryCachingFlags.add(NormalizationResult.QueryCachingFlags.IS_DQL_STATEMENT);
271270
}
272271
if (ctx.ctes() != null) {
273272
visit(ctx.ctes());
@@ -296,7 +295,7 @@ public RelationalExpression visitQueryOptions(@Nonnull RelationalParser.QueryOpt
296295
public Object visitQueryOption(@Nonnull RelationalParser.QueryOptionContext ctx) {
297296
try {
298297
if (ctx.NOCACHE() != null) {
299-
queryCachingFlags.add(Result.QueryCachingFlags.WITH_NO_CACHE_OPTION);
298+
queryCachingFlags.add(NormalizationResult.QueryCachingFlags.WITH_NO_CACHE_OPTION);
300299
}
301300
if (ctx.LOG() != null) {
302301
queryOptions.withOption(Options.Name.LOG_QUERY, true);
@@ -315,37 +314,37 @@ public Object visitQueryOption(@Nonnull RelationalParser.QueryOptionContext ctx)
315314

316315
@Override
317316
public Object visitDdlStatement(@Nonnull RelationalParser.DdlStatementContext ctx) {
318-
queryCachingFlags.add(Result.QueryCachingFlags.IS_DDL_STATEMENT);
317+
queryCachingFlags.add(NormalizationResult.QueryCachingFlags.IS_DDL_STATEMENT);
319318
return visitChildren(ctx);
320319
}
321320

322321
@Override
323322
public Object visitInsertStatement(final RelationalParser.InsertStatementContext ctx) {
324-
queryCachingFlags.add(Result.QueryCachingFlags.IS_INSERT_STATEMENT);
323+
queryCachingFlags.add(NormalizationResult.QueryCachingFlags.IS_INSERT_STATEMENT);
325324
return super.visitInsertStatement(ctx);
326325
}
327326

328327
@Override
329328
public Object visitUpdateStatement(final RelationalParser.UpdateStatementContext ctx) {
330-
queryCachingFlags.add(Result.QueryCachingFlags.IS_UPDATE_STATEMENT);
329+
queryCachingFlags.add(NormalizationResult.QueryCachingFlags.IS_UPDATE_STATEMENT);
331330
return super.visitUpdateStatement(ctx);
332331
}
333332

334333
@Override
335334
public Object visitDeleteStatement(final RelationalParser.DeleteStatementContext ctx) {
336-
queryCachingFlags.add(Result.QueryCachingFlags.IS_DELETE_STATEMENT);
335+
queryCachingFlags.add(NormalizationResult.QueryCachingFlags.IS_DELETE_STATEMENT);
337336
return super.visitDeleteStatement(ctx);
338337
}
339338

340339
@Override
341340
public Object visitAdministrationStatement(@Nonnull RelationalParser.AdministrationStatementContext ctx) {
342-
queryCachingFlags.add(Result.QueryCachingFlags.IS_ADMIN_STATEMENT);
341+
queryCachingFlags.add(NormalizationResult.QueryCachingFlags.IS_ADMIN_STATEMENT);
343342
return visitChildren(ctx);
344343
}
345344

346345
@Override
347346
public Object visitUtilityStatement(@Nonnull RelationalParser.UtilityStatementContext ctx) {
348-
queryCachingFlags.add(Result.QueryCachingFlags.IS_UTILITY_STATEMENT);
347+
queryCachingFlags.add(NormalizationResult.QueryCachingFlags.IS_UTILITY_STATEMENT);
349348
return visitChildren(ctx);
350349
}
351350

@@ -486,8 +485,8 @@ public Object visitInPredicate(@Nonnull RelationalParser.InPredicateContext ctx)
486485

487486
@Override
488487
public Object visitExecuteContinuationStatement(@Nonnull RelationalParser.ExecuteContinuationStatementContext ctx) {
489-
queryCachingFlags.add(Result.QueryCachingFlags.IS_EXECUTE_CONTINUATION_STATEMENT);
490-
queryCachingFlags.add(Result.QueryCachingFlags.WITH_NO_CACHE_OPTION);
488+
queryCachingFlags.add(NormalizationResult.QueryCachingFlags.IS_EXECUTE_CONTINUATION_STATEMENT);
489+
queryCachingFlags.add(NormalizationResult.QueryCachingFlags.WITH_NO_CACHE_OPTION);
491490
if (ctx.queryOptions() != null) {
492491
ctx.queryOptions().accept(this);
493492
}
@@ -575,10 +574,10 @@ private void processLiteral(@Nonnull final Object literal, final int tokenIndex,
575574
* @return The query parse tree along with contextual information required for planning and executing it.
576575
*/
577576
@Nonnull
578-
public static Result normalizeQuery(@Nonnull final PlanContext context,
579-
@Nonnull final String query,
580-
boolean isCaseSensitive,
581-
@Nonnull final PlanHashable.PlanHashMode currentPlanHashMode) throws RelationalException {
577+
public static NormalizationResult normalizeQuery(@Nonnull final PlanContext context,
578+
@Nonnull final String query,
579+
boolean isCaseSensitive,
580+
@Nonnull final PlanHashable.PlanHashMode currentPlanHashMode) throws RelationalException {
582581
// lexing, parsing, and normalization are profiled through the metric collector.
583582
final var metricCollector = context.getMetricsCollector();
584583
final var rootContext = metricCollector.clock(RelationalMetric.RelationalEvent.LEX_PARSE,
@@ -588,7 +587,7 @@ public static Result normalizeQuery(@Nonnull final PlanContext context,
588587
context.getSchemaTemplate(), rootContext,
589588
PreparedParams.copyOf(context.getPreparedStatementParameters()),
590589
context.getUserVersion(),
591-
context.getSchemaTemplate().getIndexEntriesAsBitset(context.getPlannerConfiguration().getReadableIndexes()),
590+
context.getPlannerConfiguration(),
592591
isCaseSensitive,
593592
currentPlanHashMode,
594593
query
@@ -597,14 +596,14 @@ public static Result normalizeQuery(@Nonnull final PlanContext context,
597596

598597
@Nonnull
599598
@VisibleForTesting
600-
public static Result normalizeAst(@Nonnull final SchemaTemplate schemaTemplate,
601-
@Nonnull final RelationalParser.RootContext context,
602-
@Nonnull final PreparedParams preparedStatementParameters,
603-
int userVersion,
604-
@Nonnull final BitSet readableIndexes,
605-
boolean caseSensitive,
606-
@Nonnull final PlanHashable.PlanHashMode currentPlanHashMode,
607-
@Nonnull final String query) {
599+
public static NormalizationResult normalizeAst(@Nonnull final SchemaTemplate schemaTemplate,
600+
@Nonnull final RelationalParser.RootContext context,
601+
@Nonnull final PreparedParams preparedStatementParameters,
602+
int userVersion,
603+
@Nonnull final PlannerConfiguration plannerConfiguration,
604+
boolean caseSensitive,
605+
@Nonnull final PlanHashable.PlanHashMode currentPlanHashMode,
606+
@Nonnull final String query) {
608607
final var astNormalizer = new AstNormalizer(preparedStatementParameters, caseSensitive, currentPlanHashMode);
609608
astNormalizer.visit(context);
610609
final var recordLayerSchemaTemplate = Assert.castUnchecked(schemaTemplate, RecordLayerSchemaTemplate.class);
@@ -632,19 +631,19 @@ public static Result normalizeAst(@Nonnull final SchemaTemplate schemaTemplate,
632631
final var compiledFunction = recordLayerRoutine.getCompilableSqlFunctionSupplier().get();
633632
astNormalizer.queryHasherContextBuilder.getLiteralsBuilder().importLiterals(compiledFunction.getAuxiliaryLiterals());
634633
}
635-
return new Result(
634+
return new NormalizationResult(
636635
recordLayerSchemaTemplate.getName(),
637-
QueryCacheKey.of(astNormalizer.getCanonicalSqlString(), astNormalizer.getHash(),
638-
recordLayerSchemaTemplate.getVersion(), readableIndexes, userVersion,
639-
recordLayerSchemaTemplate.getTransactionBoundMetadataAsString()),
636+
QueryCacheKey.of(astNormalizer.getCanonicalSqlString(), plannerConfiguration,
637+
recordLayerSchemaTemplate.getTransactionBoundMetadataAsString(), astNormalizer.getHash(),
638+
recordLayerSchemaTemplate.getVersion(), userVersion),
640639
astNormalizer.getQueryExecutionParameters(),
641640
context,
642641
astNormalizer.getQueryCachingFlags(),
643642
astNormalizer.getQueryOptions(),
644643
query);
645644
}
646645

647-
public static final class Result {
646+
public static final class NormalizationResult {
648647

649648
/**
650649
* A set of flags that determine how the query should interact with the plan cache.
@@ -687,13 +686,13 @@ public enum QueryCachingFlags {
687686
@Nonnull
688687
private final String query;
689688

690-
public Result(@Nonnull final String schemaTemplateName,
691-
@Nonnull final QueryCacheKey queryCacheKey,
692-
@Nonnull final QueryExecutionContext queryExecutionContext,
693-
@Nonnull final ParseTree parseTree,
694-
@Nonnull final Set<QueryCachingFlags> queryCachingFlags,
695-
@Nonnull final Options queryOptions,
696-
@Nonnull final String query) {
689+
public NormalizationResult(@Nonnull final String schemaTemplateName,
690+
@Nonnull final QueryCacheKey queryCacheKey,
691+
@Nonnull final QueryExecutionContext queryExecutionContext,
692+
@Nonnull final ParseTree parseTree,
693+
@Nonnull final Set<QueryCachingFlags> queryCachingFlags,
694+
@Nonnull final Options queryOptions,
695+
@Nonnull final String query) {
697696
this.schemaTemplateName = schemaTemplateName;
698697
this.queryCacheKey = queryCacheKey;
699698
this.queryExecutionContext = queryExecutionContext;
@@ -703,6 +702,7 @@ public Result(@Nonnull final String schemaTemplateName,
703702
this.query = query;
704703
}
705704

705+
@Nonnull
706706
public String getSchemaTemplateName() {
707707
return schemaTemplateName;
708708
}

0 commit comments

Comments
 (0)