diff options
author | Mihai Andrei <mihai.andrei@mongodb.com> | 2023-02-07 00:58:25 +0000 |
---|---|---|
committer | Evergreen Agent <no-reply@evergreen.mongodb.com> | 2023-02-07 02:32:02 +0000 |
commit | b185d04364c298e701943a1e800c4036ce8df6e7 (patch) | |
tree | 6a91575c0096863e38b1b0fd12d1bfd90d55ac7f /jstests | |
parent | 967a6745ba487edaff558e36fdc572c6ca066fea (diff) | |
download | mongo-b185d04364c298e701943a1e800c4036ce8df6e7.tar.gz |
SERVER-71798 Expand the set of queries eligible for SBE in the 6.3 release
Diffstat (limited to 'jstests')
75 files changed, 567 insertions, 548 deletions
diff --git a/jstests/aggregation/add_with_date.js b/jstests/aggregation/add_with_date.js index b80c304e42c..4d76a6908d7 100644 --- a/jstests/aggregation/add_with_date.js +++ b/jstests/aggregation/add_with_date.js @@ -28,8 +28,6 @@ assert.commandWorked(coll.insert({ nanDecimal: NumberDecimal("NaN"), })); -const isSBEEnabled = checkSBEEnabled(db, ["featureFlagSbeFull"]); - // Adding a Decimal128 value to a date literal. assert.eq(ISODate("2019-01-30T07:30:10.957Z"), getResultOfExpression({$add: ["$decimalVal", ISODate("2019-01-30T07:30:10.137Z")]})); diff --git a/jstests/aggregation/explain_limit.js b/jstests/aggregation/explain_limit.js index 7ce18401062..5e017f9b74e 100644 --- a/jstests/aggregation/explain_limit.js +++ b/jstests/aggregation/explain_limit.js @@ -18,7 +18,7 @@ let coll = db.explain_limit; const kCollSize = 105; const kLimit = 10; -const isSBEEnabled = checkSBEEnabled(db, ["featureFlagSbeFull"]); +const isSBEEnabled = checkSBEEnabled(db); // Return whether or explain() was successful and contained the appropriate fields given the // requested verbosity. Checks that the number of documents examined and returned are correct given diff --git a/jstests/aggregation/optimize_away_pipeline.js b/jstests/aggregation/optimize_away_pipeline.js index 065691a0663..453ee78db40 100644 --- a/jstests/aggregation/optimize_away_pipeline.js +++ b/jstests/aggregation/optimize_away_pipeline.js @@ -639,33 +639,66 @@ function assertProjectionIsNotRemoved(pipeline, projectionType = "PROJECTION_SIM assertProjectionCanBeRemovedBeforeGroup( [{$project: {a: 1, b: 1}}, {$group: {_id: "$a", s: {$sum: "$b"}}}]); -assertProjectionCanBeRemovedBeforeGroup( - [{$project: {'a.b': 1, 'b.c': 1}}, {$group: {_id: "$a.b", s: {$sum: "$b.c"}}}], - "PROJECTION_DEFAULT"); - -// Test that an inclusion projection is NOT optimized away if it is NOT redundant. This one fails to -// include a dependency of the $group and so will have an impact on the query results. +// Test that an inclusion projection is NOT optimized away if it is NOT redundant. This one +// fails to include a dependency of the $group and so will have an impact on the query results. assertProjectionIsNotRemoved([{$project: {a: 1}}, {$group: {_id: "$a", s: {$sum: "$b"}}}]); -// Test similar cases with dotted paths. -assertProjectionIsNotRemoved([{$project: {'a.b': 1}}, {$group: {_id: "$a.b", s: {$sum: "$b"}}}], - "PROJECTION_DEFAULT"); -assertProjectionIsNotRemoved([{$project: {'a.b': 1}}, {$group: {_id: "$a.b", s: {$sum: "$a.c"}}}], - "PROJECTION_DEFAULT"); // TODO SERVER-67323 This one could be removed, but is left for future work. assertProjectionIsNotRemoved( [{$project: {a: 1, b: 1}}, {$group: {_id: "$a.b", s: {$sum: "$b.c"}}}]); -// Spinoff on the one above: Without supporting this kind of prefixing analysis, we can confuse -// ourselves with our dependency analysis. If the $group depends on both "path" and "path.subpath" -// then it will generate a $project on only "path" to express its dependency set. We then fail to -// optimize that out. +// If the $group depends on both "path" and "path.subpath" then it will generate a $project on only +// "path" to express its dependency set. We then fail to optimize that out. As a future improvement, +// we could improve the optimizer to ensure that a projection stage is not present in the resulting +// plan. pipeline = [{$group: {_id: "$a.b", s: {$first: "$a"}}}]; // TODO SERVER-XYZ Assert this can be optimized out. // assertProjectionCanBeRemovedBeforeGroup(pipeline, "PROJECTION_DEFAULT"); // assertProjectionCanBeRemovedBeforeGroup(pipeline, "PROJECTION_SIMPLE"); assertProjectionIsNotRemoved(pipeline); +// Though $group is generally eligible for pushdown into SBE, such a pushdown may be inhibited by +// dotted as well as computed projections. As such we only run the test cases below if SBE is fully +// enabled. +const sbeFull = checkSBEEnabled(db, ["featureFlagSbeFull"], true /* checkAllNodes */); +if (sbeFull) { + assertProjectionCanBeRemovedBeforeGroup( + [{$project: {'a.b': 1, 'b.c': 1}}, {$group: {_id: "$a.b", s: {$sum: "$b.c"}}}], + "PROJECTION_DEFAULT"); + + // Test that a computed projection at the front of the pipeline is pushed down, even if there's + // no finite dependency set. + pipeline = [{$project: {x: {$add: ["$a", 1]}}}]; + assertPipelineDoesNotUseAggregation( + {pipeline: pipeline, expectedStages: ["COLLSCAN", "PROJECTION_DEFAULT"]}); + + // The projections below are not removed because they fail to include the $group's dependencies. + assertProjectionIsNotRemoved([{$project: {'a.b': 1}}, {$group: {_id: "$a.b", s: {$sum: "$b"}}}], + "PROJECTION_DEFAULT"); + assertProjectionIsNotRemoved( + [{$project: {'a.b': 1}}, {$group: {_id: "$a.b", s: {$sum: "$a.c"}}}], "PROJECTION_DEFAULT"); + + pipeline = [{$project: {a: {$add: ["$a", 1]}}}, {$group: {_id: "$a", s: {$sum: "$b"}}}]; + assertPipelineIfGroupPushdown( + // Test that a computed projection at the front of the pipeline is pushed down when there's + // a finite dependency set. Additionally, the group pushdown shouldn't erase the computed + // projection. + function() { + explain = coll.explain().aggregate(pipeline); + assertPipelineDoesNotUseAggregation( + {pipeline: pipeline, expectedStages: ["COLLSCAN", "PROJECTION_DEFAULT", "GROUP"]}); + }, + // Test that a computed projection at the front of the pipeline is pushed down when there's + // a finite dependency set. + function() { + explain = coll.explain().aggregate(pipeline); + assertPipelineUsesAggregation({ + pipeline: pipeline, + expectedStages: ["COLLSCAN", "PROJECTION_DEFAULT", "$group"], + }); + }); +} + // We generate a projection stage from dependency analysis, even if the pipeline begins with an // exclusion projection. pipeline = [{$project: {c: 0}}, {$group: {_id: "$a", b: {$sum: "$b"}}}]; @@ -696,32 +729,6 @@ pipeline = [{$project: {x: 0}}]; assertPipelineDoesNotUseAggregation( {pipeline: pipeline, expectedStages: ["PROJECTION_SIMPLE", "COLLSCAN"]}); -// Test that a computed projection at the front of the pipeline is pushed down, even if there's no -// finite dependency set. -pipeline = [{$project: {x: {$add: ["$a", 1]}}}]; -assertPipelineDoesNotUseAggregation( - {pipeline: pipeline, expectedStages: ["COLLSCAN", "PROJECTION_DEFAULT"]}); - -pipeline = [{$project: {a: {$add: ["$a", 1]}}}, {$group: {_id: "$a", s: {$sum: "$b"}}}]; -assertPipelineIfGroupPushdown( - // Test that a computed projection at the front of the pipeline is pushed down when there's a - // finite dependency set. Additionally, the group pushdown shouldn't erase the computed - // projection. - function() { - explain = coll.explain().aggregate(pipeline); - assertPipelineDoesNotUseAggregation( - {pipeline: pipeline, expectedStages: ["COLLSCAN", "PROJECTION_DEFAULT", "GROUP"]}); - }, - // Test that a computed projection at the front of the pipeline is pushed down when there's a - // finite dependency set. - function() { - explain = coll.explain().aggregate(pipeline); - assertPipelineUsesAggregation({ - pipeline: pipeline, - expectedStages: ["COLLSCAN", "PROJECTION_DEFAULT", "$group"], - }); - }); - // getMore cases. // Test getMore on a collection with an optimized away pipeline. diff --git a/jstests/core/columnstore/column_scan_skip_row_store_projection.js b/jstests/core/columnstore/column_scan_skip_row_store_projection.js index b69e515d7ef..8124af3e446 100644 --- a/jstests/core/columnstore/column_scan_skip_row_store_projection.js +++ b/jstests/core/columnstore/column_scan_skip_row_store_projection.js @@ -30,8 +30,8 @@ load("jstests/libs/sbe_util.js"); // For checkSBEEnabled. load("jstests/libs/clustered_collections/clustered_collection_util.js"); load("jstests/libs/columnstore_util.js"); // For setUpServerForColumnStoreIndexTest. -const columnstoreEnabled = checkSBEEnabled( - db, ["featureFlagColumnstoreIndexes", "featureFlagSbeFull"], true /* checkAllNodes */); +const columnstoreEnabled = + checkSBEEnabled(db, ["featureFlagColumnstoreIndexes"], true /* checkAllNodes */); if (!columnstoreEnabled) { jsTestLog("Skipping columnstore index test since the feature flag is not enabled."); return; diff --git a/jstests/core/columnstore/column_store_index_compression.js b/jstests/core/columnstore/column_store_index_compression.js index c66c12abef0..52b74a23a10 100644 --- a/jstests/core/columnstore/column_store_index_compression.js +++ b/jstests/core/columnstore/column_store_index_compression.js @@ -8,7 +8,6 @@ * # Column store indexes are still under a feature flag and require full SBE. * uses_column_store_index, * featureFlagColumnstoreIndexes, - * featureFlagSbeFull, * * # In passthrough suites, this test makes direct connections to mongod instances that compose * # the passthrough fixture in order to perform additional validation. Tenant migration, @@ -28,8 +27,8 @@ load("jstests/libs/fixture_helpers.js"); // For isMongos load("jstests/libs/index_catalog_helpers.js"); // For IndexCatalogHelpers load("jstests/libs/sbe_util.js"); // For checkSBEEnabled. -const columnstoreEnabled = checkSBEEnabled( - db, ["featureFlagColumnstoreIndexes", "featureFlagSbeFull"], true /* checkAllNodes */); +const columnstoreEnabled = + checkSBEEnabled(db, ["featureFlagColumnstoreIndexes"], true /* checkAllNodes */); if (!columnstoreEnabled) { jsTestLog("Skipping columnstore index test since the feature flag is not enabled."); return; diff --git a/jstests/core/columnstore/columnstore_eligibility.js b/jstests/core/columnstore/columnstore_eligibility.js index c65f4c50eff..791d9929608 100644 --- a/jstests/core/columnstore/columnstore_eligibility.js +++ b/jstests/core/columnstore/columnstore_eligibility.js @@ -25,8 +25,6 @@ if (!setUpServerForColumnStoreIndexTest(db)) { return; } -const sbeFull = checkSBEEnabled(db, ["featureFlagSbeFull"]); - const coll = db.columnstore_eligibility; coll.drop(); @@ -66,12 +64,35 @@ assert(planHasStage(db, explain, "COLUMN_SCAN"), explain); // will be applied after assembling an intermediate result containing both "a" and "b". explain = coll.find({$or: [{a: 2}, {b: 2}]}, {_id: 0, a: 1}).explain(); -// For top-level $or queries, COLUMN_SCAN is only used when sbeFull is also enabled due to a -// quirk in the engine selection logic. TODO: SERVER-XYZ. +// COLUMN_SCAN is used for top-level $or queries. +assert(planHasStage(db, explain, "COLUMN_SCAN"), explain); + +// COLUMN_SCAN is only used for for certain top-level $or queries when sbeFull is also enabled due +// to a quirk in the engine selection logic. +const sbeFull = checkSBEEnabled(db, ["featureFlagSbeFull"]); +explain = coll.explain().aggregate([ + {$match: {$or: [{a: {$gt: 0}}, {b: {$gt: 0}}]}}, + {$project: {_id: 0, computedField: {$add: ["$a", "$b"]}}}, +]); +let planHasColumnScan = planHasStage(db, explain, "COLUMN_SCAN"); + if (sbeFull) { - assert(planHasStage(db, explain, "COLUMN_SCAN"), explain); + assert(planHasColumnScan, explain); +} else { + assert(!planHasColumnScan, explain); +} + +explain = coll.explain().aggregate([ + {$match: {$or: [{a: {$gt: 0}}, {b: {$gt: 0}}]}}, + {$project: {_id: 0, computedField: {$add: ["$a", "$b"]}}}, + {$group: {_id: "$computedField"}} +]); +planHasColumnScan = planHasStage(db, explain, "COLUMN_SCAN"); + +if (sbeFull) { + assert(planHasColumnScan, explain); } else { - assert(planHasStage(db, explain, "COLLSCAN"), explain); + assert(!planHasColumnScan, explain); } // Simplest case: just scan "a" column. diff --git a/jstests/core/computed_projections.js b/jstests/core/computed_projections.js index 06ea2476bd9..fd432771f44 100644 --- a/jstests/core/computed_projections.js +++ b/jstests/core/computed_projections.js @@ -2,14 +2,7 @@ "use strict"; load("jstests/aggregation/extras/utils.js"); // For arrayEq and orderedArrayEq. -load("jstests/libs/sbe_util.js"); // For checkSBEEnabledOnSomeNode. - -const isSBEEnabled = checkSBEEnabledOnSomeNode(db); -if (isSBEEnabled) { - // Override error-code-checking APIs. We only load this when SBE is explicitly enabled, because - // it causes failures in the parallel suites. - load("jstests/libs/sbe_assert_error_override.js"); -} +load("jstests/libs/sbe_assert_error_override.js"); // It is safe for other tests to run while this failpoint is active, so long as those tests do not // use documents containing a field with "POISON" as their name. Note that this command can fail. diff --git a/jstests/core/index/hidden_index.js b/jstests/core/index/hidden_index.js index e1edef07fe7..572d9016ae0 100644 --- a/jstests/core/index/hidden_index.js +++ b/jstests/core/index/hidden_index.js @@ -25,8 +25,7 @@ load("jstests/libs/sbe_util.js"); // For checkSBEEnabled. load("jstests/libs/columnstore_util.js"); // For setUpServerForColumnStoreIndexTest. const columnstoreEnabled = - checkSBEEnabled( - db, ["featureFlagColumnstoreIndexes", "featureFlagSbeFull"], true /* checkAllNodes */) && + checkSBEEnabled(db, ["featureFlagColumnstoreIndexes"], true /* checkAllNodes */) && setUpServerForColumnStoreIndexTest(db); const collName = "hidden_index"; diff --git a/jstests/core/index/index_filter_commands.js b/jstests/core/index/index_filter_commands.js index 1272cb2fd19..429a79adea8 100644 --- a/jstests/core/index/index_filter_commands.js +++ b/jstests/core/index/index_filter_commands.js @@ -33,7 +33,8 @@ * assumes_read_preference_unchanged, * assumes_unsharded_collection, * does_not_support_stepdowns, - * requires_fcv_60 + * # The SBE plan cache was first enabled in 6.3. + * requires_fcv_63, * ] */ @@ -344,7 +345,7 @@ assert.commandFailed( filters = getFilters(); assert.eq(0, filters.length, tojson(filters)); -if (checkSBEEnabled(db, ["featureFlagSbeFull"], true /* checkAllNodes */)) { +if (checkSBEEnabled(db)) { // // Test that planCacheSetFilter doesn't apply to the inner side of a $lookup. // diff --git a/jstests/core/index/index_filter_commands_invalidate_plan_cache_entries.js b/jstests/core/index/index_filter_commands_invalidate_plan_cache_entries.js index 059241284ac..bc2dc74c0e1 100644 --- a/jstests/core/index/index_filter_commands_invalidate_plan_cache_entries.js +++ b/jstests/core/index/index_filter_commands_invalidate_plan_cache_entries.js @@ -27,7 +27,7 @@ load("jstests/libs/sbe_util.js"); // For checkSBEEnabled. // For testing convenience this variable is made an integer "1" if SBE is fully enabled, because the // expected amount of plan cache entries differs between the SBE plan cache and the classic one. -const isSbeEnabled = checkSBEEnabled(db, ["featureFlagSbeFull"]) ? 1 : 0; +const isSbeEnabled = checkSBEEnabled(db) ? 1 : 0; const collName = "index_filter_commands_invalidate_plan_cache_entries"; const coll = db[collName]; diff --git a/jstests/core/index/indexj.js b/jstests/core/index/indexj.js index 3023b661e59..93034fec923 100644 --- a/jstests/core/index/indexj.js +++ b/jstests/core/index/indexj.js @@ -7,12 +7,15 @@ // # Different assertions are made depending on whether SBE or classic is used. Implicitly // # creating an index can change which engine is used. // assumes_no_implicit_index_creation, +// # This test assumes that either SBE or classic is fully enabled and that we're not running in +// # a mixed version cluster. +// requires_fcv_63, // ] (function() { "use strict"; -load("jstests/libs/sbe_explain_helpers.js"); // For engineSpecificAssertion. +load("jstests/libs/sbe_util.js"); // For 'checkSBEEnabled'. const t = db[jsTestName()]; t.drop(); @@ -56,42 +59,39 @@ assert.commandWorked(t.insert({a: 2, b: 2})); // SBE or the classic engine. This is because the classic engine will use a multi-interval index // scan whereas SBE will decompose the intervals into a set of single-interval bounds and will end // up examining 0 keys. -let assertFn = function(expectedKeys, numKeysExamined) { - return numKeysExamined === expectedKeys; -}; +const isSBEEnabled = checkSBEEnabled(db); +let expectedKeys = isSBEEnabled ? 0 : 3; let errMsg = function(actualNumKeys) { return "Chosen plan examined " + actualNumKeys + " keys"; }; -let sbeAssert = actualKeys => assertFn(0, actualKeys); -let classicAssert = actualKeys => assertFn(3, actualKeys); let numKeys = keysExamined({a: {$in: [1, 2]}, b: {$gt: 1, $lt: 2}}, {a: 1, b: 1}); -engineSpecificAssertion(classicAssert(numKeys), sbeAssert(numKeys), db, errMsg(numKeys)); +assert.eq(numKeys, expectedKeys, errMsg(numKeys)); numKeys = keysExamined({a: {$in: [1, 2]}, b: {$gt: 1, $lt: 2}}, {a: 1, b: 1}, {a: -1, b: -1}); -engineSpecificAssertion(classicAssert(numKeys), sbeAssert(numKeys), db, errMsg(numKeys)); +assert.eq(numKeys, expectedKeys, errMsg(numKeys)); assert.commandWorked(t.insert({a: 1, b: 1})); assert.commandWorked(t.insert({a: 1, b: 1})); numKeys = keysExamined({a: {$in: [1, 2]}, b: {$gt: 1, $lt: 2}}, {a: 1, b: 1}); -engineSpecificAssertion(classicAssert(numKeys), sbeAssert(numKeys), db, errMsg(numKeys)); +assert.eq(numKeys, expectedKeys, errMsg(numKeys)); numKeys = keysExamined({a: {$in: [1, 2]}, b: {$gt: 1, $lt: 2}}, {a: 1, b: 1}); -engineSpecificAssertion(classicAssert(numKeys), sbeAssert(numKeys), db, errMsg(numKeys)); +assert.eq(numKeys, expectedKeys, errMsg(numKeys)); numKeys = keysExamined({a: {$in: [1, 2]}, b: {$gt: 1, $lt: 2}}, {a: 1, b: 1}, {a: -1, b: -1}); -engineSpecificAssertion(classicAssert(numKeys), sbeAssert(numKeys), db, errMsg(numKeys)); +assert.eq(numKeys, expectedKeys, errMsg(numKeys)); // We examine one less key in the classic engine because the bounds are slightly tighter. -classicAssert = actualKeys => assertFn(2, actualKeys); -numKeys = keysExamined({a: {$in: [1, 1.9]}, b: {$gt: 1, $lt: 2}}, {a: 1, b: 1}); -engineSpecificAssertion(classicAssert(numKeys), sbeAssert(numKeys), db, errMsg(numKeys)); +if (!isSBEEnabled) { + expectedKeys = 2; +} +numKeys = keysExamined({a: {$in: [1, 1.9]}, b: {$gt: 1, $lt: 2}}, {a: 1, b: 1}); +assert.eq(numKeys, expectedKeys, errMsg(numKeys)); numKeys = keysExamined({a: {$in: [1.1, 2]}, b: {$gt: 1, $lt: 2}}, {a: 1, b: 1}, {a: -1, b: -1}); -engineSpecificAssertion(classicAssert(numKeys), sbeAssert(numKeys), db, errMsg(numKeys)); - +assert.eq(numKeys, expectedKeys, errMsg(numKeys)); assert.commandWorked(t.insert({a: 1, b: 1.5})); // We examine one extra key in both engines because we've inserted a document that falls within // both sets of bounds being scanned. -sbeAssert = actualKeys => assertFn(1, actualKeys); -classicAssert = actualKeys => assertFn(4, actualKeys); +expectedKeys = isSBEEnabled ? 1 : 4; numKeys = keysExamined({a: {$in: [1, 2]}, b: {$gt: 1, $lt: 2}}, {a: 1, b: 1}); -engineSpecificAssertion(classicAssert(numKeys), sbeAssert(numKeys), db, errMsg(numKeys)); +assert.eq(numKeys, expectedKeys, errMsg(numKeys)); })(); diff --git a/jstests/core/index/wildcard/wildcard_index_cached_plans.js b/jstests/core/index/wildcard/wildcard_index_cached_plans.js index f3a41f5361e..5e78a11d451 100644 --- a/jstests/core/index/wildcard/wildcard_index_cached_plans.js +++ b/jstests/core/index/wildcard/wildcard_index_cached_plans.js @@ -34,7 +34,7 @@ coll.drop(); assert.commandWorked(coll.createIndex({"b.$**": 1})); assert.commandWorked(coll.createIndex({"a": 1})); -const isSbeEnabled = checkSBEEnabled(db, ["featureFlagSbeFull"]); +const isSbeEnabled = checkSBEEnabled(db); // In order for the plan cache to be used, there must be more than one plan available. Insert // data into the collection such that the b.$** index will be far more selective than the index diff --git a/jstests/core/query/explode_for_sort_plan_cache.js b/jstests/core/query/explode_for_sort_plan_cache.js index 3d489ad9d54..2da78284a6a 100644 --- a/jstests/core/query/explode_for_sort_plan_cache.js +++ b/jstests/core/query/explode_for_sort_plan_cache.js @@ -11,7 +11,7 @@ * # If all chunks are moved off of a shard, it can cause the plan cache to miss commands. * assumes_balancer_off, * assumes_unsharded_collection, - * requires_fcv_62, + * requires_fcv_63, * # Plan cache state is node-local and will not get migrated alongside tenant data. * tenant_migration_incompatible, * # Part of this test does different checks depending on the engine used. If an implicit index @@ -65,7 +65,7 @@ const sortSpec = { // TODO SERVER-67576: remove this branch once explode for sort plans are supported by the SBE plan // cache. -if (checkSBEEnabled(db, ["featureFlagSbeFull"])) { +if (checkSBEEnabled(db)) { // Run the query for the first time and make sure the plan hasn't been cached. assert.eq(0, coll.find(querySpec).sort(sortSpec).itcount()); assertCacheEntryDoesNotExist(querySpec, sortSpec); diff --git a/jstests/core/query/expr/expr_index_use.js b/jstests/core/query/expr/expr_index_use.js index a0f85bc69c9..2eadaf645be 100644 --- a/jstests/core/query/expr/expr_index_use.js +++ b/jstests/core/query/expr/expr_index_use.js @@ -1,6 +1,7 @@ // Confirms expected index use when performing a match with a $expr statement. // @tags: [ // assumes_read_concern_local, +// requires_fcv_63, // ] (function() { @@ -92,10 +93,7 @@ function confirmExpectedExprExecution(expr, metricsToCheck, collation) { ]; assert.eq(metricsToCheck.nReturned, coll.aggregate(pipelineWithProject, aggOptions).itcount()); let explain = coll.explain("executionStats").aggregate(pipelineWithProject, aggOptions); - assert(getAggPlanStage(explain, "COLLSCAN", isSBEEnabled /* useQueryPlannerSection */) || - checkBothEnginesAreRunOnCluster(db) && - (getAggPlanStage(explain, "COLLSCAN", false /* useQueryPlannerSection */) || - getAggPlanStage(explain, "COLLSCAN", true /* useQueryPlannerSection */)), + assert(getAggPlanStage(explain, "COLLSCAN", isSBEEnabled /* useQueryPlannerSection */), explain); // Verifies that there are no rejected plans, and that the winning plan uses the expected diff --git a/jstests/core/query/idhack.js b/jstests/core/query/idhack.js index e60bd9c8a50..1ddab70d4cd 100644 --- a/jstests/core/query/idhack.js +++ b/jstests/core/query/idhack.js @@ -61,8 +61,7 @@ winningPlan = getWinningPlan(explain.queryPlanner); assert(!isIdhack(db, winningPlan), winningPlan); // Covered query returning _id field only can be handled by ID hack. -const isSbeEnabled = checkSBEEnabled(db, ["featureFlagSbeFull"]); -const parentStage = isSbeEnabled ? "PROJECTION_COVERED" : "FETCH"; +const parentStage = checkSBEEnabled(db) ? "PROJECTION_COVERED" : "FETCH"; explain = t.find(query, {_id: 1}).explain(); winningPlan = getWinningPlan(explain.queryPlanner); assert(isIdhack(db, winningPlan), winningPlan); diff --git a/jstests/core/query/null_query_semantics.js b/jstests/core/query/null_query_semantics.js index a99741853d2..71cd4b7c84f 100644 --- a/jstests/core/query/null_query_semantics.js +++ b/jstests/core/query/null_query_semantics.js @@ -790,8 +790,8 @@ const keyPatterns = [ ]; // Include Columnstore Index only if FF is enabled and collection is not clustered. -const columnstoreEnabled = checkSBEEnabled( - db, ["featureFlagColumnstoreIndexes", "featureFlagSbeFull"], true /* checkAllNodes */); +const columnstoreEnabled = + checkSBEEnabled(db, ["featureFlagColumnstoreIndexes"], true /* checkAllNodes */); if (columnstoreEnabled && setUpServerForColumnStoreIndexTest(db)) { keyPatterns.push({keyPattern: {"$**": "columnstore"}}); } diff --git a/jstests/core/query/or/or_to_in.js b/jstests/core/query/or/or_to_in.js index 5d3c745dc95..681e2af9e2a 100644 --- a/jstests/core/query/or/or_to_in.js +++ b/jstests/core/query/or/or_to_in.js @@ -4,6 +4,7 @@ // This test is not prepared to handle explain output for sharded collections. // @tags: [ // assumes_unsharded_collection, +// requires_fcv_63, // ] (function() { @@ -11,7 +12,6 @@ load("jstests/aggregation/extras/utils.js"); // For assertArrayEq. load("jstests/libs/analyze_plan.js"); -load("jstests/libs/sbe_util.js"); // For checkBothEnginesAreRunOnCluster. var coll = db.orToIn; coll.drop(); @@ -48,9 +48,7 @@ function assertEquivPlanAndResult(expectedQuery, actualQuery, supportWithCollati // Make sure both queries have the same access plan. const expectedPlan = getWinningPlan(expectedExplain.queryPlanner); const actualPlan = getWinningPlan(actualExplain.queryPlanner); - if (!checkBothEnginesAreRunOnCluster(db)) { - assert.docEq(expectedPlan, actualPlan); - } + assert.docEq(expectedPlan, actualPlan); // The queries must produce the same result. const expectedRes = coll.find(expectedQuery).toArray(); diff --git a/jstests/core/query/plan_cache/cached_plan_trial_does_not_discard_work.js b/jstests/core/query/plan_cache/cached_plan_trial_does_not_discard_work.js index f83b9e6a817..941ec0106b5 100644 --- a/jstests/core/query/plan_cache/cached_plan_trial_does_not_discard_work.js +++ b/jstests/core/query/plan_cache/cached_plan_trial_does_not_discard_work.js @@ -12,7 +12,8 @@ // assumes_read_preference_unchanged, // assumes_unsharded_collection, // does_not_support_stepdowns, -// requires_fcv_52, +// # The SBE plan cache was first enabled in 6.3. +// requires_fcv_63, // requires_profiling, // # Plan cache state is node-local and will not get migrated alongside tenant data. // tenant_migration_incompatible, @@ -25,7 +26,7 @@ load("jstests/libs/profiler.js"); // getLatestProfileEntry. load("jstests/libs/sbe_util.js"); // For checkSBEEnabled. -if (!checkSBEEnabled(db, ["featureFlagSbeFull"])) { +if (!checkSBEEnabled(db)) { jsTestLog("Skipping test because SBE is disabled"); return; } diff --git a/jstests/core/query/plan_cache/collation_plan_cache.js b/jstests/core/query/plan_cache/collation_plan_cache.js index da6c2f08081..99e983dd2fa 100644 --- a/jstests/core/query/plan_cache/collation_plan_cache.js +++ b/jstests/core/query/plan_cache/collation_plan_cache.js @@ -20,7 +20,6 @@ load("jstests/libs/analyze_plan.js"); // For getPlanCacheKeyFromExplain. load("jstests/libs/sbe_util.js"); // For checkSBEEnabled. -const isSbeEnabled = checkSBEEnabled(db, ["featureFlagSbeFull"]); var coll = db.collation_plan_cache; coll.drop(); @@ -54,6 +53,8 @@ assert.commandWorked( // The query shape should have been added. var shapes = coll.aggregate([{$planCacheStats: {}}]).toArray(); assert.eq(1, shapes.length, 'unexpected cache size after running query'); + +const isSbeEnabled = checkSBEEnabled(db); if (!isSbeEnabled) { assert.eq(shapes[0].createdFromQuery.query, {a: 'foo', b: 5}, shapes); assert.eq(shapes[0].createdFromQuery.sort, {}, shapes); diff --git a/jstests/core/query/plan_cache/plan_cache_clear.js b/jstests/core/query/plan_cache/plan_cache_clear.js index 7aee144bc89..d03330ab08e 100644 --- a/jstests/core/query/plan_cache/plan_cache_clear.js +++ b/jstests/core/query/plan_cache/plan_cache_clear.js @@ -15,6 +15,8 @@ // assumes_unsharded_collection, // # Plan cache state is node-local and will not get migrated alongside tenant data. // tenant_migration_incompatible, +// # The SBE plan cache was first enabled in 6.3. +// requires_fcv_63, // # TODO SERVER-67607: Test plan cache with CQF enabled. // cqf_incompatible, // ] @@ -104,7 +106,7 @@ const nonExistentColl = db.plan_cache_clear_nonexistent; nonExistentColl.drop(); assert.commandWorked(nonExistentColl.runCommand('planCacheClear')); -if (checkSBEEnabled(db, ["featureFlagSbeFull"], true /* checkAllNodes */)) { +if (checkSBEEnabled(db)) { // Plan cache commands should work against the main collection only, not foreignColl // collections, when $lookup is pushed down into SBE. const foreignColl = db.plan_cache_clear_foreign; diff --git a/jstests/core/query/plan_cache/plan_cache_list_plans.js b/jstests/core/query/plan_cache/plan_cache_list_plans.js index 6521aac3448..b0f7a24c615 100644 --- a/jstests/core/query/plan_cache/plan_cache_list_plans.js +++ b/jstests/core/query/plan_cache/plan_cache_list_plans.js @@ -29,7 +29,7 @@ load("jstests/libs/sbe_util.js"); // For checkSBEEnabled. let coll = db.jstests_plan_cache_list_plans; coll.drop(); -const isSbeEnabled = checkSBEEnabled(db, ["featureFlagSbeFull"]); +const isSbeEnabled = checkSBEEnabled(db); function dumpPlanCacheState() { return coll.aggregate([{$planCacheStats: {}}]).toArray(); diff --git a/jstests/core/query/plan_cache/plan_cache_list_shapes.js b/jstests/core/query/plan_cache/plan_cache_list_shapes.js index 7d348cc21a2..48535eae0c3 100644 --- a/jstests/core/query/plan_cache/plan_cache_list_shapes.js +++ b/jstests/core/query/plan_cache/plan_cache_list_shapes.js @@ -20,8 +20,8 @@ 'use strict'; load("jstests/libs/sbe_util.js"); // For checkSBEEnabled. -if (checkSBEEnabled(db, ["featureFlagSbeFull"])) { - jsTest.log("Skipping test because SBE is fully enabled."); +if (checkSBEEnabled(db)) { + jsTest.log("Skipping test because SBE is enabled."); return; } diff --git a/jstests/core/query/plan_cache/plan_cache_sbe.js b/jstests/core/query/plan_cache/plan_cache_sbe.js index aeb0609246c..2a35b786d70 100644 --- a/jstests/core/query/plan_cache/plan_cache_sbe.js +++ b/jstests/core/query/plan_cache/plan_cache_sbe.js @@ -12,8 +12,8 @@ * assumes_read_concern_unchanged, * assumes_read_preference_unchanged, * assumes_unsharded_collection, - * # The SBE plan cache was introduced in 6.0. - * requires_fcv_60, + * # The SBE plan cache was first enabled in 6.3. + * requires_fcv_63, * # Plan cache state is node-local and will not get migrated alongside tenant data. * tenant_migration_incompatible, * # TODO SERVER-67607: Test plan cache with CQF enabled. @@ -30,7 +30,7 @@ load("jstests/libs/sbe_util.js"); // For checkSBEEnabled. const coll = db.plan_cache_sbe; coll.drop(); -const isSbeEnabled = checkSBEEnabled(db, ["featureFlagSbeFull"], true /* checkAllNodes */); +const isSbeEnabled = checkSBEEnabled(db); assert.commandWorked(coll.insert({a: 1, b: 1})); diff --git a/jstests/core/query/plan_cache/plan_cache_shell_helpers.js b/jstests/core/query/plan_cache/plan_cache_shell_helpers.js index b663e09e90b..a102d8a001d 100644 --- a/jstests/core/query/plan_cache/plan_cache_shell_helpers.js +++ b/jstests/core/query/plan_cache/plan_cache_shell_helpers.js @@ -21,7 +21,7 @@ load('jstests/aggregation/extras/utils.js'); // For assertArrayEq. load("jstests/libs/analyze_plan.js"); // For getPlanCacheKeyFromShape. load("jstests/libs/sbe_util.js"); // For checkSBEEnabled. -const isSbeEnabled = checkSBEEnabled(db, ["featureFlagSbeFull"]); +const isSbeEnabled = checkSBEEnabled(db); var coll = db.jstests_plan_cache_shell_helpers; coll.drop(); diff --git a/jstests/core/query/project/projection_expr_mod.js b/jstests/core/query/project/projection_expr_mod.js index aa882d190b5..a8f2905bce5 100644 --- a/jstests/core/query/project/projection_expr_mod.js +++ b/jstests/core/query/project/projection_expr_mod.js @@ -4,14 +4,7 @@ "use strict"; load("jstests/aggregation/extras/utils.js"); // For assertArrayEq. -load("jstests/libs/sbe_util.js"); // For checkSBEEnabled. - -const isSBEEnabled = checkSBEEnabledOnSomeNode(db); -if (isSBEEnabled) { - // Override error-code-checking APIs. We only load this when SBE is explicitly enabled, because - // it causes failures in the parallel suites. - load("jstests/libs/sbe_assert_error_override.js"); -} +load("jstests/libs/sbe_assert_error_override.js"); const coll = db.projection_expr_mod; coll.drop(); diff --git a/jstests/core/query/project/projection_semantics.js b/jstests/core/query/project/projection_semantics.js index cf71f951755..1f811c84b36 100644 --- a/jstests/core/query/project/projection_semantics.js +++ b/jstests/core/query/project/projection_semantics.js @@ -6,7 +6,8 @@ * # We could potentially need to resume an index build in the event of a stepdown, which is not * # yet implemented. * does_not_support_stepdowns, - * requires_fcv_62, + * # Columnstore indexes were first enabled by default on 6.3. + * requires_fcv_63, * # Columnstore tests set server parameters to disable columnstore query planning heuristics - * # server parameters are stored in-memory only so are not transferred onto the recipient. * tenant_migration_incompatible, @@ -19,7 +20,7 @@ load("jstests/libs/sbe_util.js"); // For checkSBEEnabled. load("jstests/libs/columnstore_util.js"); // For setUpServerForColumnStoreIndexTest. -if (!checkSBEEnabled(db, ["featureFlagColumnstoreIndexes", "featureFlagSbeFull"])) { +if (!checkSBEEnabled(db, ["featureFlagColumnstoreIndexes"])) { jsTestLog("Skipping test since columnstore Indexes are not enabled"); return; } diff --git a/jstests/core/query/query_hash_stability.js b/jstests/core/query/query_hash_stability.js index aa0a3399e70..c358f1c7d34 100644 --- a/jstests/core/query/query_hash_stability.js +++ b/jstests/core/query/query_hash_stability.js @@ -112,7 +112,7 @@ assertPlanCacheField({ // SBE's planCacheKey encoding encodes "collection version" which will be increased after dropping // an index. -if (!checkSBEEnabled(db, ["featureFlagSbeFull"])) { +if (!checkSBEEnabled(db)) { // The 'planCacheKey' should be the same as what it was before we dropped the index. assertPlanCacheField({ firstExplain: initialExplain, diff --git a/jstests/core/sbe/from_plan_cache_flag.js b/jstests/core/sbe/from_plan_cache_flag.js index ef910b42513..15fee88f73c 100644 --- a/jstests/core/sbe/from_plan_cache_flag.js +++ b/jstests/core/sbe/from_plan_cache_flag.js @@ -1,8 +1,10 @@ -// The test runs commands that are not allowed with security token: setProfilingLevel. // @tags: [ +// # The test runs commands that are not allowed with security token: setProfilingLevel. // not_allowed_with_security_token, // requires_profiling, // does_not_support_stepdowns, +// # The SBE plan cache was first enabled in 6.3. +// requires_fcv_63, // # TODO SERVER-67607: Test plan cache with CQF enabled. // cqf_incompatible, // ] @@ -14,7 +16,7 @@ load("jstests/libs/sbe_util.js"); // For checkSBEEnabled. load("jstests/libs/profiler.js"); // For getLatestProfilerEntry. load("jstests/libs/sbe_util.js"); // For checkSBEEnabled. -if (!checkSBEEnabled(db, ["featureFlagSbeFull"], true /* checkAllNodes */)) { +if (!checkSBEEnabled(db)) { jsTest.log("Skip running the test because SBE is not enabled"); return; } @@ -33,11 +35,6 @@ assert.commandWorked(coll.insert({a: 2})); let pipeline = {$match: {a: 1}}; coll.aggregate([pipeline]).toArray(); let profileObj = getLatestProfilerEntry(testDB); -/* fromPlanCache can be undefined in the profiler entry. The first ! determines the - * profileObj.fromPlanCache value's associated true/false value (important in the case where - * undefined) and then returns the opposite of the associated true/false value. The second ! - * returns the opposite of the opposite value. In other words, the !! returns the boolean true/false - * association of a value. */ assert.eq(!!profileObj.fromPlanCache, false); coll.aggregate({$match: {a: 2}}).toArray(); diff --git a/jstests/core/sbe/plan_cache_sbe_with_or_queries.js b/jstests/core/sbe/plan_cache_sbe_with_or_queries.js index a4c474c82bd..f4a90d42dc1 100644 --- a/jstests/core/sbe/plan_cache_sbe_with_or_queries.js +++ b/jstests/core/sbe/plan_cache_sbe_with_or_queries.js @@ -7,7 +7,8 @@ // assumes_read_concern_unchanged, // assumes_unsharded_collection, // does_not_support_stepdowns, -// requires_fcv_60, +// # The SBE plan cache was first enabled in 6.3. +// requires_fcv_63, // # Plan cache state is node-local and will not get migrated alongside tenant data. // tenant_migration_incompatible, // # TODO SERVER-67607: Test plan cache with CQF enabled. @@ -20,7 +21,7 @@ load("jstests/libs/analyze_plan.js"); load("jstests/libs/sbe_util.js"); // For checkSBEEnabled. -if (!checkSBEEnabled(db, ["featureFlagSbeFull"], true /* checkAllNodes */)) { +if (!checkSBEEnabled(db)) { jsTest.log("Skip running the test because SBE is not enabled"); return; } diff --git a/jstests/core/sbe/sbe_explain_rejected_plans.js b/jstests/core/sbe/sbe_explain_rejected_plans.js index 0e858cfd48c..a6ae2575186 100644 --- a/jstests/core/sbe/sbe_explain_rejected_plans.js +++ b/jstests/core/sbe/sbe_explain_rejected_plans.js @@ -1,6 +1,9 @@ /** * Tests that SBE reports correct rejected plans when calling explain(). - * @tags: [assumes_unsharded_collection, requires_fcv_62] + * @tags: [ + * assumes_unsharded_collection, + * requires_fcv_63, + * ] */ (function() { "use strict"; @@ -9,9 +12,9 @@ load("jstests/libs/analyze_plan.js"); load("jstests/libs/collection_drop_recreate.js"); load("jstests/libs/sbe_util.js"); // For 'checkSBEEnabled'. -const isSBEEnabled = checkSBEEnabled(db, ["featureFlagSbeFull"]); +const isSBEEnabled = checkSBEEnabled(db); if (!isSBEEnabled) { - jsTestLog("Skipping test because the SBE feature flag is disabled"); + jsTestLog("Skipping test because SBE is disabled"); return; } diff --git a/jstests/core/sbe/sbe_ixscan_explain.js b/jstests/core/sbe/sbe_ixscan_explain.js index fee902af2b8..d79b8a209fc 100644 --- a/jstests/core/sbe/sbe_ixscan_explain.js +++ b/jstests/core/sbe/sbe_ixscan_explain.js @@ -3,7 +3,8 @@ // // @tags: [ // assumes_against_mongod_not_mongos, -// requires_fcv_51, +// # The SBE plan cache was first enabled in 6.3. +// requires_fcv_63, // ] (function() { @@ -12,9 +13,9 @@ load('jstests/libs/analyze_plan.js'); // For getPlanStages load("jstests/libs/sbe_util.js"); // For checkSBEEnabled. -const isSBEEnabled = checkSBEEnabled(db, ["featureFlagSbeFull"], true /* checkAllNodes */); +const isSBEEnabled = checkSBEEnabled(db); if (!isSBEEnabled) { - jsTestLog("Skipping test because the SBE feature flag is disabled"); + jsTestLog("Skipping test because SBE is disabled"); return; } diff --git a/jstests/core/sbe_plan_cache_autoparameterize_collscan.js b/jstests/core/sbe_plan_cache_autoparameterize_collscan.js index f5be457ce99..3294846e3bd 100644 --- a/jstests/core/sbe_plan_cache_autoparameterize_collscan.js +++ b/jstests/core/sbe_plan_cache_autoparameterize_collscan.js @@ -7,8 +7,8 @@ * assumes_read_preference_unchanged, * assumes_unsharded_collection, * does_not_support_stepdowns, - * # The SBE plan cache was introduced in 6.0. - * requires_fcv_60, + * # The SBE plan cache was enabled by default in 6.3. + * requires_fcv_63, * # Plan cache state is node-local and will not get migrated alongside tenant data. * tenant_migration_incompatible, * # TODO SERVER-67607: Test plan cache with CQF enabled. @@ -24,9 +24,9 @@ load("jstests/libs/analyze_plan.js"); load("jstests/libs/sbe_util.js"); // This test is specifically verifying the behavior of the SBE plan cache, which is only enabled -// when 'featureFlagSbeFull' is on. -if (!checkSBEEnabled(db, ["featureFlagSbeFull"], true /* checkAllNodes */)) { - jsTestLog("Skipping test because SBE is not fully enabled"); +// when SBE is enabled. +if (!checkSBEEnabled(db)) { + jsTestLog("Skipping test because SBE is not enabled"); return; } @@ -305,32 +305,35 @@ runTest({query: {a: {$exists: true}}, projection: {_id: 1}}, false); // Test that comparisons expressed as $expr are not auto-parameterized. -runTest({query: {$expr: {$eq: ["$a", 3]}}, projection: {_id: 1}}, - [{_id: 2}], - {query: {$expr: {$eq: ["$a", 4]}}, projection: {_id: 1}}, - [{_id: 3}, {_id: 4}], - false); -runTest({query: {$expr: {$lt: ["$a", 3]}, a: {$type: "number"}}, projection: {_id: 1}}, - [{_id: 0}, {_id: 1}], - {query: {$expr: {$lt: ["$a", 4]}, a: {$type: "number"}}, projection: {_id: 1}}, - [{_id: 0}, {_id: 1}, {_id: 2}], - false); -runTest({query: {$expr: {$lte: ["$a", 3]}, a: {$type: "number"}}, projection: {_id: 1}}, - [{_id: 0}, {_id: 1}, {_id: 2}], - {query: {$expr: {$lte: ["$a", 4]}, a: {$type: "number"}}, projection: {_id: 1}}, - [{_id: 0}, {_id: 1}, {_id: 2}, {_id: 3}, {_id: 4}], - false); -runTest({query: {$expr: {$gt: ["$a", 2]}, a: {$type: "number"}}, projection: {_id: 1}}, - [{_id: 2}, {_id: 3}, {_id: 4}, {_id: 5}, {_id: 6}], - {query: {$expr: {$gt: ["$a", 3]}, a: {$type: "number"}}, projection: {_id: 1}}, - [{_id: 3}, {_id: 4}, {_id: 5}, {_id: 6}], - false); -runTest({query: {$expr: {$gte: ["$a", 2]}, a: {$type: "number"}}, projection: {_id: 1}}, - [{_id: 1}, {_id: 2}, {_id: 3}, {_id: 4}, {_id: 5}, {_id: 6}], - {query: {$expr: {$gte: ["$a", 3]}, a: {$type: "number"}}, projection: {_id: 1}}, - [{_id: 2}, {_id: 3}, {_id: 4}, {_id: 5}, {_id: 6}], - false); - +if (checkSBEEnabled(db, ["featureFlagSbeFull"])) { + runTest({query: {$expr: {$eq: ["$a", 3]}}, projection: {_id: 1}}, + [{_id: 2}], + {query: {$expr: {$eq: ["$a", 4]}}, projection: {_id: 1}}, + [{_id: 3}, {_id: 4}], + false); + runTest({query: {$expr: {$lt: ["$a", 3]}, a: {$type: "number"}}, projection: {_id: 1}}, + [{_id: 0}, {_id: 1}], + {query: {$expr: {$lt: ["$a", 4]}, a: {$type: "number"}}, projection: {_id: 1}}, + [{_id: 0}, {_id: 1}, {_id: 2}], + false); + runTest({query: {$expr: {$lte: ["$a", 3]}, a: {$type: "number"}}, projection: {_id: 1}}, + [{_id: 0}, {_id: 1}, {_id: 2}], + {query: {$expr: {$lte: ["$a", 4]}, a: {$type: "number"}}, projection: {_id: 1}}, + [{_id: 0}, {_id: 1}, {_id: 2}, {_id: 3}, {_id: 4}], + false); + runTest({query: {$expr: {$gt: ["$a", 2]}, a: {$type: "number"}}, projection: {_id: 1}}, + [{_id: 2}, {_id: 3}, {_id: 4}, {_id: 5}, {_id: 6}], + {query: {$expr: {$gt: ["$a", 3]}, a: {$type: "number"}}, projection: {_id: 1}}, + [{_id: 3}, {_id: 4}, {_id: 5}, {_id: 6}], + false); + runTest({query: {$expr: {$gte: ["$a", 2]}, a: {$type: "number"}}, projection: {_id: 1}}, + [{_id: 1}, {_id: 2}, {_id: 3}, {_id: 4}, {_id: 5}, {_id: 6}], + {query: {$expr: {$gte: ["$a", 3]}, a: {$type: "number"}}, projection: {_id: 1}}, + [{_id: 2}, {_id: 3}, {_id: 4}, {_id: 5}, {_id: 6}], + false); +} else { + jsTestLog("Skipping $expr test cases because SBE is not fully enabled"); +} // Test that the entire list of $in values is treated as a parameter. runTest({query: {a: {$in: [1, 2]}}, projection: {_id: 1}}, [{_id: 0}, {_id: 1}], diff --git a/jstests/cqf/analyze/scalar_histograms.js b/jstests/cqf/analyze/scalar_histograms.js index 7777880a1f8..83dfa7c0a42 100644 --- a/jstests/cqf/analyze/scalar_histograms.js +++ b/jstests/cqf/analyze/scalar_histograms.js @@ -2,22 +2,17 @@ "use strict"; load("jstests/libs/optimizer_utils.js"); // For checkCascadesOptimizerEnabled. -load("jstests/libs/sbe_util.js"); // For checkSBEEnabled. if (!checkCascadesOptimizerEnabled(db)) { jsTestLog("Skipping test because the optimizer is not enabled"); return; } -if (checkSBEEnabled(db, ["featureFlagSbeFull"], true)) { - jsTestLog("Skipping the test because it doesn't work in Full SBE"); - return; -} - assert.commandWorked( db.adminCommand({setParameter: 1, internalQueryFrameworkControl: "tryBonsai"})); const coll = db.cqf_analyze_scalar_hist; +coll.drop(); const stats_coll = db.system.statistics.cqf_analyze_scalar_hist; const testAnalyzeStats = (key, docs, count) => { diff --git a/jstests/libs/parallelTester.js b/jstests/libs/parallelTester.js index bc76e43d96b..ddd8190175b 100644 --- a/jstests/libs/parallelTester.js +++ b/jstests/libs/parallelTester.js @@ -253,6 +253,15 @@ if (typeof _threadInject != "undefined") { // inMemory storage engine. "timeseries/timeseries_compact.js", + // TODO (SERVER-63228): Remove this exclusion once the feature flag is enabled by + // default. + "timeseries/timeseries_index_ttl_partial.js", + + // These tests load 'sbe_assert_error_override.js' unconditionally, which causes + // failures in the parallel suite. + "computed_projections.js", + "query/project/projection_expr_mod.js", + // TODO (SERVER-66393): Remove this exclusion once the feature flag is enabled by // default. "timeseries/timeseries_update_multi.js", diff --git a/jstests/libs/sbe_explain_helpers.js b/jstests/libs/sbe_explain_helpers.js index 994394c9abb..a405efc1ae5 100644 --- a/jstests/libs/sbe_explain_helpers.js +++ b/jstests/libs/sbe_explain_helpers.js @@ -41,24 +41,6 @@ function getSbePlanStages(queryLayerOutput, stage) { } /** - * Helper to make an assertion depending on the engine being used. If we're in a mixed version - * cluster, then we assert that either 'classicAssert' or 'sbeAssert' is true because the outcome - * will depend on which node we're making assertions against. If we're not in a mixed version - * scenario, then we make an assertion depending on the return value of 'checkSBEEnabled'. - */ -function engineSpecificAssertion(classicAssert, sbeAssert, theDB, msg) { - if (checkBothEnginesAreRunOnCluster(theDB)) { - assert(classicAssert || sbeAssert, msg); - } else if (checkSBEEnabled(theDB, ["featureFlagSbeFull"])) { - // This function assumes that SBE is fully enabled, and will fall back to the classic - // assert if it is not. - assert(sbeAssert, msg); - } else { - assert(classicAssert, msg); - } -} - -/** * Gets the query info object at either the top level or the first stage from a v2 * explainOutput. If a query is a find query or some prefix stage(s) of a pipeline is pushed down to * SBE, then plan information will be in the 'queryPlanner' object. Currently, this supports find diff --git a/jstests/libs/sbe_util.js b/jstests/libs/sbe_util.js index 1508052cae0..90451a646f7 100644 --- a/jstests/libs/sbe_util.js +++ b/jstests/libs/sbe_util.js @@ -98,89 +98,3 @@ function checkSBEEnabled(theDB, featureFlags = [], checkAllNodes = false) { return checkResult; } - -/** - * If 'theDB' corresponds to a node in a cluster, then returns true if the cluster that it - * belongs to has at least one node that has SBE enabled and at least one node that has it - * disabled; false otherwise. - */ -function checkBothEnginesAreRunOnCluster(theDB) { - let result = false; - assert.soon(() => { - if (!FixtureHelpers.isMongos(theDB) && !FixtureHelpers.isReplSet(theDB)) { - return true; - } - - // Retry the check if we fail to discover the topology (this can happen if the test - // suite has killed the primary). - let nodes; - try { - nodes = DiscoverTopology.findNonConfigNodes(theDB.getMongo()); - } catch (e) { - return false; - } - - let engineMap = {sbe: 0, classic: 0}; - - for (const node of nodes) { - // If we cannot contact a node because it was killed or is otherwise unreachable, we - // skip it and check the other nodes in the cluster. For our purposes, this is ok - // because test suites which step down/kill certain nodes are configured to use - // exactly one engine, whereas the test suites which are configured use both engines - // (namely, the multiversion suites), do not step down/kill nodes. - try { - const conn = new Mongo(node); - if (FixtureHelpers.isMongos(conn.getDB("admin"))) { - continue; - } - - const getParam = conn.adminCommand({ - getParameter: 1, - internalQueryFrameworkControl: 1, - internalQueryForceClassicEngine: 1, - featureFlagSbeFull: 1, - }); - - if (getParam.hasOwnProperty("internalQueryFrameworkControl")) { - // We say SBE is fully enabled if the engine is on and either - // 'featureFlagSbeFull' doesn't exist on the targeted server, or it exists and - // is set to true. - if (getParam.internalQueryFrameworkControl !== "forceClassicEngine" && - getParam.featureFlagSbeFull.value) { - engineMap.sbe++; - } else { - engineMap.classic++; - } - } else { - // 'internalQueryForceClassicEngine' should be set on the previous versions - // before 'internalQueryFrameworkControl' is introduced. - assert(getParam.hasOwnProperty("internalQueryForceClassicEngine"), getParam); - if (!getParam.internalQueryForceClassicEngine.value && - getParam.featureFlagSbeFull.value) { - engineMap.sbe++; - } else { - engineMap.classic++; - } - } - - result = (engineMap.sbe > 0 && engineMap.classic > 0); - if (result) { - return true; - } - } catch (e) { - continue; - } - } - - return true; - }); - - return result; -} - -/** - * Returns 'true' if SBE is enabled on at least on one node for the given connection 'db'. - */ -function checkSBEEnabledOnSomeNode(db) { - return checkSBEEnabled(db) || checkBothEnginesAreRunOnCluster(db); -} diff --git a/jstests/noPassthrough/columnstore_index_rowstore_settings.js b/jstests/noPassthrough/columnstore_index_rowstore_settings.js index 54f405cf7b7..22a2475cdc0 100644 --- a/jstests/noPassthrough/columnstore_index_rowstore_settings.js +++ b/jstests/noPassthrough/columnstore_index_rowstore_settings.js @@ -3,9 +3,8 @@ * reconstruct the result of a query. * * @tags: [ - * # column store indexes are still under a feature flag and require full sbe - * featureFlagColumnstoreIndexes, - * featureFlagSbeFull, + * # column store indexes are still under a feature flag + * featureFlagColumnstoreIndexes * ] */ diff --git a/jstests/noPassthrough/currentop_query.js b/jstests/noPassthrough/currentop_query.js index 7b6be89d2d8..a3244f66343 100644 --- a/jstests/noPassthrough/currentop_query.js +++ b/jstests/noPassthrough/currentop_query.js @@ -79,7 +79,7 @@ function runTests({conn, currentOp, truncatedOps, localOps}) { const isLocalMongosCurOp = (FixtureHelpers.isMongos(testDB) && localOps); const isRemoteShardCurOp = (FixtureHelpers.isMongos(testDB) && !localOps); - const sbeEnabled = checkSBEEnabled(testDB, ["featureFlagSbeFull"]); + const sbeEnabled = checkSBEEnabled(testDB); // If 'truncatedOps' is true, run only the subset of tests designed to validate the // truncation behaviour. Otherwise, run the standard set of tests which assume that diff --git a/jstests/noPassthrough/external_sort_find.js b/jstests/noPassthrough/external_sort_find.js index befac93c5dc..a1505f129a3 100644 --- a/jstests/noPassthrough/external_sort_find.js +++ b/jstests/noPassthrough/external_sort_find.js @@ -21,7 +21,7 @@ assert.neq(null, conn, "mongod was unable to start up with options: " + tojson(o const testDb = conn.getDB("test"); const collection = testDb.external_sort_find; -const isSBEEnabled = checkSBEEnabled(testDb, ["featureFlagSbeFull"]); +const isSBEEnabled = checkSBEEnabled(testDb); // Construct a document that is just over 1 kB. const charToRepeat = "-"; diff --git a/jstests/noPassthrough/log_and_profile_query_hash.js b/jstests/noPassthrough/log_and_profile_query_hash.js index b31cfcfe0ad..65093194711 100644 --- a/jstests/noPassthrough/log_and_profile_query_hash.js +++ b/jstests/noPassthrough/log_and_profile_query_hash.js @@ -110,7 +110,7 @@ const testList = [ test: function(db, comment) { assert.eq(200, db.test.find().comment(comment).itcount()); }, - hasPlanCacheKey: checkSBEEnabled(testDB, ["featureFlagSbeFull"]) + hasPlanCacheKey: checkSBEEnabled(testDB) }, { comment: "Test1 find query", diff --git a/jstests/noPassthrough/lookup_metrics.js b/jstests/noPassthrough/lookup_metrics.js index 44082f99ac2..9f2aec0bfdb 100644 --- a/jstests/noPassthrough/lookup_metrics.js +++ b/jstests/noPassthrough/lookup_metrics.js @@ -8,8 +8,7 @@ load("jstests/libs/sbe_util.js"); // For 'checkSBEEnabled()'. load("jstests/libs/analyze_plan.js"); // For 'getAggPlanStages' and other explain helpers. -const conn = - MongoRunner.runMongod({setParameter: {featureFlagSbeFull: true, allowDiskUseByDefault: true}}); +const conn = MongoRunner.runMongod({setParameter: {allowDiskUseByDefault: true}}); assert.neq(null, conn, "mongod was unable to start up"); const db = conn.getDB(jsTestName()); diff --git a/jstests/noPassthrough/lookup_pushdown.js b/jstests/noPassthrough/lookup_pushdown.js index 8c6496d10f1..641c73d5ff2 100644 --- a/jstests/noPassthrough/lookup_pushdown.js +++ b/jstests/noPassthrough/lookup_pushdown.js @@ -18,7 +18,7 @@ const JoinAlgorithm = { }; // Standalone cases. -const conn = MongoRunner.runMongod({setParameter: {allowDiskUseByDefault: true}}); +const conn = MongoRunner.runMongod(); assert.neq(null, conn, "mongod was unable to start up"); const name = "lookup_pushdown"; const foreignCollName = "foreign_lookup_pushdown"; @@ -112,15 +112,13 @@ function runTest(coll, } let db = conn.getDB(name); -if (!checkSBEEnabled(db)) { - jsTestLog("Skipping test because either the sbe lookup pushdown feature flag is disabled or" + - " sbe itself is disabled"); +const sbeEnabled = checkSBEEnabled(db); +if (!sbeEnabled) { + jsTestLog("Skipping test because SBE is disabled"); MongoRunner.stopMongod(conn); return; } -const sbeFullEnabled = checkSBEEnabled(db, ["featureFlagSbeFull"]); - let coll = db[name]; const localDocs = [{_id: 1, a: 2}]; assert.commandWorked(coll.insert(localDocs)); @@ -300,48 +298,6 @@ function setLookupPushdownDisabled(value) { {allowDiskUse: false}); }()); -// Verify that SBE is only used when a $lookup or a $group is present. -(function testLookupGroupIsRequiredForPushdown() { - // Don't execute this test case if SBE is fully enabled. - if (sbeFullEnabled) { - jsTestLog("Skipping test case because we are supporting SBE beyond $group and $lookup" + - " pushdown"); - return; - } - - const assertEngineUsed = function(pipeline, isSBE) { - const explain = coll.explain().aggregate(pipeline); - assert(explain.hasOwnProperty("explainVersion"), explain); - if (isSBE) { - assert.eq(explain.explainVersion, "2", explain); - } else { - assert.eq(explain.explainVersion, "1", explain); - } - }; - - const lookup = {$lookup: {from: "coll", localField: "a", foreignField: "b", as: "out"}}; - const group = { - $group: { - _id: "$a", - out: {$min: "$b"}, - } - }; - const match = {$match: {a: 1}}; - - // $lookup and $group should each run in SBE. - assertEngineUsed([lookup], true /* isSBE */); - assertEngineUsed([group], true /* isSBE */); - assertEngineUsed([lookup, group], true /* isSBE */); - - // $match on its own won't use SBE, nor will an empty pipeline. - assertEngineUsed([match], false /* isSBE */); - assertEngineUsed([], false /* isSBE */); - - // $match will use SBE if followed by either a $group or a $lookup. - assertEngineUsed([match, lookup], true /* isSBE */); - assertEngineUsed([match, group], true /* isSBE */); -})(); - // Build an index on the foreign collection that matches the foreignField. This should cause us // to choose an indexed nested loop join. (function testIndexNestedLoopJoinRegularIndex() { @@ -707,61 +663,56 @@ function setLookupPushdownDisabled(value) { // Test which verifies that the right side of a classic $lookup is never lowered into SBE, even if // the queries for the right side are eligible on their own to run in SBE. (function verifyThatClassicLookupRightSideIsNeverLoweredIntoSBE() { - // If running with SBE fully enabled, verify that our $match is SBE compatible. Otherwise, - // verify that the same $match, when used as a $lookup sub-pipeline, will not be lowered - // into SBE. + // Confirm that our candidate subpipeline is SBE compatible on its own. const subPipeline = [{$match: {b: 2}}]; - if (sbeFullEnabled) { - const subPipelineExplain = foreignColl.explain().aggregate(subPipeline); - assert(subPipelineExplain.hasOwnProperty("explainVersion"), subPipelineExplain); - assert.eq(subPipelineExplain["explainVersion"], "2", subPipelineExplain); - } else { - const pipeline = [{$lookup: {from: foreignCollName, pipeline: subPipeline, as: "result"}}]; - runTest(coll, pipeline, JoinAlgorithm.Classic /* expectedJoinAlgorithm */); - - // Create multiple indexes that can be used to answer the subPipeline query. This will allow - // the winning plan to be cached. - assert.commandWorked(foreignColl.dropIndexes()); - assert.commandWorked(foreignColl.createIndexes([{b: 1, a: 1}, {b: 1, c: 1}])); - - // Run the pipeline enough times to generate a cache entry for the right side in the foreign - // collection. - coll.aggregate(pipeline).itcount(); - coll.aggregate(pipeline).itcount(); - - const cacheEntries = foreignColl.getPlanCache().list(); - assert.eq(cacheEntries.length, 1); - const cacheEntry = cacheEntries[0]; - - // The cached plan should be a classic plan. - assert(cacheEntry.hasOwnProperty("version"), cacheEntry); - assert.eq(cacheEntry.version, "1", cacheEntry); - assert(cacheEntry.hasOwnProperty("cachedPlan"), cacheEntry); - const cachedPlan = cacheEntry.cachedPlan; - - // The cached plan should not have slot based plan. Instead, it should be a FETCH + IXSCAN - // executed in the classic engine. - assert(!cachedPlan.hasOwnProperty("slots"), cacheEntry); - assert(cachedPlan.hasOwnProperty("stage"), cacheEntry); - - assert(planHasStage(db, cachedPlan, "FETCH"), cacheEntry); - assert(planHasStage(db, cachedPlan, "IXSCAN"), cacheEntry); - assert.commandWorked(coll.dropIndexes()); - } + const subPipelineExplain = foreignColl.explain().aggregate(subPipeline); + assert(subPipelineExplain.hasOwnProperty("explainVersion"), subPipelineExplain); + assert.eq(subPipelineExplain["explainVersion"], "2", subPipelineExplain); + + // Now, run a lookup and force it to run in the classic engine by prefixing it with + // '$_internalInhibitOptimization'. + const pipeline = [ + {$_internalInhibitOptimization: {}}, + {$lookup: {from: foreignCollName, pipeline: subPipeline, as: "result"}} + ]; + runTest(coll, pipeline, JoinAlgorithm.Classic /* expectedJoinAlgorithm */); + + // Create multiple indexes that can be used to answer the subPipeline query. This will allow + // the winning plan to be cached. + assert.commandWorked(foreignColl.dropIndexes()); + assert.commandWorked(foreignColl.createIndexes([{b: 1, a: 1}, {b: 1, c: 1}])); + + // Run the pipeline enough times to generate a cache entry for the right side in the foreign + // collection. + coll.aggregate(pipeline).itcount(); + coll.aggregate(pipeline).itcount(); + + const cacheEntries = foreignColl.getPlanCache().list(); + assert.eq(cacheEntries.length, 1); + const cacheEntry = cacheEntries[0]; + + // The cached plan should be a classic plan. + assert(cacheEntry.hasOwnProperty("version"), cacheEntry); + assert.eq(cacheEntry.version, "1", cacheEntry); + assert(cacheEntry.hasOwnProperty("cachedPlan"), cacheEntry); + const cachedPlan = cacheEntry.cachedPlan; + + // The cached plan should not have slot based plan. Instead, it should be a FETCH + IXSCAN + // executed in the classic engine. + assert(!cachedPlan.hasOwnProperty("slots"), cacheEntry); + assert(cachedPlan.hasOwnProperty("stage"), cacheEntry); + + assert(planHasStage(db, cachedPlan, "FETCH"), cacheEntry); + assert(planHasStage(db, cachedPlan, "IXSCAN"), cacheEntry); + assert.commandWorked(coll.dropIndexes()); }()); MongoRunner.stopMongod(conn); -// Verify that pipeline stages get pushed down according to the subset of SBE that is enabled. -(function verifyPushdownLogicSbePartiallyEnabled() { - const conn = MongoRunner.runMongod({setParameter: {allowDiskUseByDefault: true}}); +// Verify that $lookup and $group stages get pushed down as expected. +(function verifyLookupGroupStagesArePushedDown() { + const conn = MongoRunner.runMongod(); const db = conn.getDB(name); - if (sbeFullEnabled) { - jsTestLog("Skipping test case because SBE is fully enabled, but this test case assumes" + - " that it is not fully enabled"); - MongoRunner.stopMongod(conn); - return; - } const coll = db[name]; const foreignColl = db[foreignCollName]; @@ -838,7 +789,7 @@ MongoRunner.stopMongod(conn); (function testHashJoinQueryKnobs() { // Create a new scope and start a new mongod so that the mongod-wide global state changes do not // affect subsequent tests if any. - const conn = MongoRunner.runMongod({setParameter: {featureFlagSbeFull: true}}); + const conn = MongoRunner.runMongod(); const db = conn.getDB(name); const lcoll = db.query_knobs_local; const fcoll = db.query_knobs_foreign; @@ -851,8 +802,7 @@ MongoRunner.stopMongod(conn); runTest(lcoll, [{$lookup: {from: fcoll.getName(), localField: "a", foreignField: "a", as: "out"}}], JoinAlgorithm.HJ, - null /* indexKeyPattern */, - {allowDiskUse: true}); + null /* indexKeyPattern */); // The fcollStats.count means the number of documents in a collection, the fcollStats.size means // the collection's data size, and the fcollStats.storageSize means the allocated storage size. @@ -868,8 +818,7 @@ MongoRunner.stopMongod(conn); runTest(lcoll, [{$lookup: {from: fcoll.getName(), localField: "a", foreignField: "a", as: "out"}}], JoinAlgorithm.HJ, - null /* indexKeyPattern */, - {allowDiskUse: true}); + null /* indexKeyPattern */); // Setting the 'internalQueryDisableLookupExecutionUsingHashJoin' knob to true will disable // HJ plans from being chosen and since the pipeline is SBE compatible it will fallback to @@ -882,8 +831,7 @@ MongoRunner.stopMongod(conn); runTest(lcoll, [{$lookup: {from: fcoll.getName(), localField: "a", foreignField: "a", as: "out"}}], JoinAlgorithm.NLJ, - null /* indexKeyPattern */, - {allowDiskUse: true}); + null /* indexKeyPattern */); // Test that we can go back to generating HJ plans. assert.commandWorked(db.adminCommand({ @@ -894,8 +842,7 @@ MongoRunner.stopMongod(conn); runTest(lcoll, [{$lookup: {from: fcoll.getName(), localField: "a", foreignField: "a", as: "out"}}], JoinAlgorithm.HJ, - null /* indexKeyPattern */, - {allowDiskUse: true}); + null /* indexKeyPattern */); // Setting the 'internalQueryCollectionMaxNoOfDocumentsToChooseHashJoin' to count - 1 results in // choosing the NLJ algorithm. @@ -907,8 +854,7 @@ MongoRunner.stopMongod(conn); runTest(lcoll, [{$lookup: {from: fcoll.getName(), localField: "a", foreignField: "a", as: "out"}}], JoinAlgorithm.NLJ, - null /* indexKeyPattern */, - {allowDiskUse: true}); + null /* indexKeyPattern */); // Reverting back 'internalQueryCollectionMaxNoOfDocumentsToChooseHashJoin' to the previous // value. Setting the 'internalQueryCollectionMaxDataSizeBytesToChooseHashJoin' to size - 1 @@ -922,8 +868,7 @@ MongoRunner.stopMongod(conn); runTest(lcoll, [{$lookup: {from: fcoll.getName(), localField: "a", foreignField: "a", as: "out"}}], JoinAlgorithm.NLJ, - null /* indexKeyPattern */, - {allowDiskUse: true}); + null /* indexKeyPattern */); // Reverting back 'internalQueryCollectionMaxDataSizeBytesToChooseHashJoin' to the previous // value. Setting the 'internalQueryCollectionMaxStorageSizeBytesToChooseHashJoin' to @@ -937,8 +882,7 @@ MongoRunner.stopMongod(conn); runTest(lcoll, [{$lookup: {from: fcoll.getName(), localField: "a", foreignField: "a", as: "out"}}], JoinAlgorithm.NLJ, - null /* indexKeyPattern */, - {allowDiskUse: true}); + null /* indexKeyPattern */); MongoRunner.stopMongod(conn); }()); @@ -1010,11 +954,7 @@ MongoRunner.stopMongod(conn); }()); // Sharded cases. -const st = new ShardingTest({ - shards: 2, - mongos: 1, - other: {shardOptions: {setParameter: {featureFlagSbeFull: true, allowDiskUseByDefault: true}}} -}); +const st = new ShardingTest({shards: 2, mongos: 1}); db = st.s.getDB(name); // Setup. Here, 'coll' is sharded, 'foreignColl' is unsharded, 'viewName' is an unsharded view, diff --git a/jstests/noPassthrough/plan_cache_group_lookup.js b/jstests/noPassthrough/plan_cache_group_lookup.js index f18277689b5..dcef122bf80 100644 --- a/jstests/noPassthrough/plan_cache_group_lookup.js +++ b/jstests/noPassthrough/plan_cache_group_lookup.js @@ -22,8 +22,6 @@ if (!checkSBEEnabled(db)) { return; } -const sbeFullEnabled = checkSBEEnabled(db, ["featureFlagSbeFull"]); - assert.commandWorked(coll.insert({a: 1})); assert.commandWorked(coll.createIndex({a: 1, a1: 1})); assert.commandWorked(coll.createIndex({a: 1, a2: 1})); @@ -123,7 +121,7 @@ const groupStage = { (function testLoweredPipelineCombination() { setupForeignColl(); - const expectedVersion = sbeFullEnabled ? 2 : 1; + const expectedVersion = 2; coll.getPlanCache().clear(); testLoweredPipeline( @@ -147,16 +145,11 @@ const groupStage = { setupForeignColl(); testLoweredPipeline({ pipeline: [multiPlanningQueryStage, lookupStage, {$_internalInhibitOptimization: {}}], - version: sbeFullEnabled ? 2 : 1 + version: 2 }); })(); (function testNonExistentForeignCollectionCache() { - if (!sbeFullEnabled) { - jsTestLog("Skipping testNonExistentForeignCollectionCache when SBE is not fully enabled"); - return; - } - coll.getPlanCache().clear(); foreignColl.drop(); const entryWithoutForeignColl = @@ -176,12 +169,6 @@ const groupStage = { })(); (function testForeignCollectionDropCacheInvalidation() { - if (!sbeFullEnabled) { - jsTestLog( - "Skipping testForeignCollectionDropCacheInvalidation when SBE is not fully enabled"); - return; - } - coll.getPlanCache().clear(); setupForeignColl(); testLoweredPipeline({pipeline: [multiPlanningQueryStage, lookupStage], version: 2}); @@ -191,11 +178,6 @@ const groupStage = { })(); (function testForeignIndexDropCacheInvalidation() { - if (!sbeFullEnabled) { - jsTestLog("Skipping testForeignIndexDropCacheInvalidation when SBE is not fully enabled"); - return; - } - coll.getPlanCache().clear(); setupForeignColl({b: 1} /* index */); testLoweredPipeline({pipeline: [multiPlanningQueryStage, lookupStage], version: 2}); @@ -205,11 +187,6 @@ const groupStage = { })(); (function testForeignIndexBuildCacheInvalidation() { - if (!sbeFullEnabled) { - jsTestLog("Skipping testForeignIndexBuildCacheInvalidation when SBE is not fully enabled"); - return; - } - coll.getPlanCache().clear(); setupForeignColl({b: 1} /* index */); testLoweredPipeline({pipeline: [multiPlanningQueryStage, lookupStage], version: 2}); @@ -219,11 +196,6 @@ const groupStage = { })(); (function testLookupSbeAndClassicPlanCacheKey() { - if (!sbeFullEnabled) { - jsTestLog("Skipping testLookupWithClassicPlanCache when SBE is not fully enabled"); - return; - } - setupForeignColl({b: 1} /* index */); // When using SBE engine, the plan cache key of $match vs. $match + $lookup should be different. diff --git a/jstests/noPassthrough/plan_cache_index_create.js b/jstests/noPassthrough/plan_cache_index_create.js index fed5fa3c18e..7a37e49bfc4 100644 --- a/jstests/noPassthrough/plan_cache_index_create.js +++ b/jstests/noPassthrough/plan_cache_index_create.js @@ -180,8 +180,8 @@ rst.initiate(); const primaryDB = rst.getPrimary().getDB(dbName); const secondaryDB = rst.getSecondary().getDB(dbName); -if (checkSBEEnabled(primaryDB, ["featureFlagSbeFull"])) { - jsTest.log("Skipping test because SBE is fully enabled"); +if (checkSBEEnabled(primaryDB)) { + jsTest.log("Skipping test because SBE is enabled"); rst.stopSet(); return; } diff --git a/jstests/noPassthrough/plan_cache_list_failed_plans.js b/jstests/noPassthrough/plan_cache_list_failed_plans.js index 9fd79e8308e..3e778a53e3a 100644 --- a/jstests/noPassthrough/plan_cache_list_failed_plans.js +++ b/jstests/noPassthrough/plan_cache_list_failed_plans.js @@ -9,8 +9,8 @@ assert.neq(null, conn, "mongod was unable to start up"); const testDB = conn.getDB("jstests_plan_cache_list_failed_plans"); const coll = testDB.test; -if (checkSBEEnabled(testDB, ["featureFlagSbeFull"])) { - jsTest.log("Skipping test because SBE is fully enabled"); +if (checkSBEEnabled(testDB)) { + jsTest.log("Skipping test because SBE is enabled"); MongoRunner.stopMongod(conn); return; } diff --git a/jstests/noPassthrough/plan_cache_memory_debug_info.js b/jstests/noPassthrough/plan_cache_memory_debug_info.js index 331077bebfa..a52d1f5aebe 100644 --- a/jstests/noPassthrough/plan_cache_memory_debug_info.js +++ b/jstests/noPassthrough/plan_cache_memory_debug_info.js @@ -83,8 +83,8 @@ assert.neq(conn, null, "mongod failed to start"); const db = conn.getDB("test"); const coll = db.plan_cache_memory_debug_info; -if (checkSBEEnabled(db, ["featureFlagSbeFull"])) { - jsTest.log("Skipping test because SBE is fully enabled"); +if (checkSBEEnabled(db)) { + jsTest.log("Skipping test because SBE is enabled"); MongoRunner.stopMongod(conn); return; } diff --git a/jstests/noPassthrough/plan_cache_replan_group_lookup.js b/jstests/noPassthrough/plan_cache_replan_group_lookup.js index 1fa8be2ab10..941b9ba7d8d 100644 --- a/jstests/noPassthrough/plan_cache_replan_group_lookup.js +++ b/jstests/noPassthrough/plan_cache_replan_group_lookup.js @@ -19,7 +19,7 @@ const coll = db.plan_cache_replan_group_lookup; const foreignCollName = "foreign"; coll.drop(); -const sbeFullEnabled = checkSBEEnabled(db, ["featureFlagSbeFull"]); +const sbeEnabled = checkSBEEnabled(db); function getPlansForCacheEntry(match) { const matchingCacheEntries = coll.getPlanCache().list([{$match: match}]); @@ -165,7 +165,7 @@ const aIndexPredicate = [{$match: {a: 1042, b: 1}}]; // {a: 1} index is used. const bIndexPredicate = [{$match: {a: 1, b: 1042}}]; -const expectedVersion = sbeFullEnabled ? 2 : 1; +const expectedVersion = sbeEnabled ? 2 : 1; // $group tests. const groupSuffix = [{$group: {_id: "$c"}}, {$count: "n"}]; testFn(aIndexPredicate.concat(groupSuffix), @@ -249,9 +249,9 @@ assert.eq(2, coll.aggregate(aLookup).toArray()[0].n); // If SBE plan cache is enabled, a new cache entry will be created in the SBE plan cache after // invalidation. The corresponding cache entry in SBE plan cache should be inactive because the SBE // plan cache is invalidated on index drop. -assertCacheUsage(sbeFullEnabled /*multiPlanning*/, +assertCacheUsage(sbeEnabled /*multiPlanning*/, expectedVersion /* cacheEntryVersion */, - !sbeFullEnabled /*cacheEntryIsActive*/, + !sbeEnabled /*cacheEntryIsActive*/, "a_1" /*cachedIndexName*/, aLookup); @@ -260,7 +260,7 @@ verifyCorrectLookupAlgorithmUsed("NestedLoopJoin", aLookup, {allowDiskUse: false assert.eq(2, coll.aggregate(aLookup).toArray()[0].n); // Note that multi-planning is expected here when the SBE plan cache is enabled because the // 'allowDiskUse' value is part of the SBE plan cache key encoding. -assertCacheUsage(sbeFullEnabled /*multiPlanning*/, +assertCacheUsage(sbeEnabled /*multiPlanning*/, expectedVersion /* cacheEntryVersion */, true /*cacheEntryIsActive*/, "a_1" /*cachedIndexName*/, @@ -270,9 +270,9 @@ assertCacheUsage(sbeFullEnabled /*multiPlanning*/, dropLookupForeignColl(); verifyCorrectLookupAlgorithmUsed("NonExistentForeignCollection", aLookup, {allowDiskUse: true}); assert.eq(2, coll.aggregate(aLookup).toArray()[0].n); -assertCacheUsage(sbeFullEnabled /*multiPlanning*/, +assertCacheUsage(sbeEnabled /*multiPlanning*/, expectedVersion /* cacheEntryVersion */, - !sbeFullEnabled /*cacheEntryIsActive*/, + !sbeEnabled /*cacheEntryIsActive*/, "a_1" /*cachedIndexName*/, aLookup); @@ -335,7 +335,7 @@ verifyCorrectLookupAlgorithmUsed( // If SBE plan cache is enabled, after dropping index, the $lookup plan cache will be invalidated. // We will need to rerun the multi-planner. -if (sbeFullEnabled) { +if (sbeEnabled) { runLookupQuery({allowDiskUse: false}); assertCacheUsage(true /*multiPlanning*/, 2 /* cacheEntryVersion */, @@ -355,7 +355,7 @@ if (sbeFullEnabled) { runLookupQuery({allowDiskUse: false}); assertCacheUsage(false /*multiPlanning*/, - sbeFullEnabled ? 2 : 1 /* cacheEntryVersion */, + sbeEnabled ? 2 : 1 /* cacheEntryVersion */, true /*activeCacheEntry*/, "b_1" /*cachedIndexName*/, avoidReplanLookupPipeline, @@ -363,7 +363,7 @@ assertCacheUsage(false /*multiPlanning*/, runLookupQuery({allowDiskUse: false}); assertCacheUsage(false /*multiPlanning*/, - sbeFullEnabled ? 2 : 1 /* cacheEntryVersion */, + sbeEnabled ? 2 : 1 /* cacheEntryVersion */, true /*activeCacheEntry*/, "b_1" /*cachedIndexName*/, avoidReplanLookupPipeline, @@ -375,7 +375,7 @@ verifyCorrectLookupAlgorithmUsed("HashJoin", avoidReplanLookupPipeline, {allowDi // If SBE plan cache is enabled, using different 'allowDiskUse' option will result in // different plan cache key. -if (sbeFullEnabled) { +if (sbeEnabled) { runLookupQuery({allowDiskUse: true}); assertCacheUsage(true /*multiPlanning*/, 2 /* cacheEntryVersion */, @@ -395,14 +395,14 @@ if (sbeFullEnabled) { runLookupQuery({allowDiskUse: true}); assertCacheUsage(false /*multiPlanning*/, - sbeFullEnabled ? 2 : 1 /* cacheEntryVersion */, + sbeEnabled ? 2 : 1 /* cacheEntryVersion */, true /*activeCacheEntry*/, "b_1" /*cachedIndexName*/, avoidReplanLookupPipeline, {allowDiskUse: true}); runLookupQuery({allowDiskUse: true}); assertCacheUsage(false /*multiPlanning*/, - sbeFullEnabled ? 2 : 1 /* cacheEntryVersion */, + sbeEnabled ? 2 : 1 /* cacheEntryVersion */, true /*activeCacheEntry*/, "b_1" /*cachedIndexName*/, avoidReplanLookupPipeline, @@ -428,25 +428,25 @@ verifyCorrectLookupAlgorithmUsed("IndexedLoopJoin", avoidReplanLookupPipeline); // Set up an active cache entry. runLookupQuery(); assertCacheUsage(true /*multiPlanning*/, - sbeFullEnabled ? 2 : 1 /* cacheEntryVersion */, + sbeEnabled ? 2 : 1 /* cacheEntryVersion */, false /*activeCacheEntry*/, "b_1" /*cachedIndexName*/, avoidReplanLookupPipeline); runLookupQuery(); assertCacheUsage(true /*multiPlanning*/, - sbeFullEnabled ? 2 : 1 /* cacheEntryVersion */, + sbeEnabled ? 2 : 1 /* cacheEntryVersion */, true /*activeCacheEntry*/, "b_1" /*cachedIndexName*/, avoidReplanLookupPipeline); runLookupQuery(); assertCacheUsage(false /*multiPlanning*/, - sbeFullEnabled ? 2 : 1 /* cacheEntryVersion */, + sbeEnabled ? 2 : 1 /* cacheEntryVersion */, true /*activeCacheEntry*/, "b_1" /*cachedIndexName*/, avoidReplanLookupPipeline); runLookupQuery(); assertCacheUsage(false /*multiPlanning*/, - sbeFullEnabled ? 2 : 1 /* cacheEntryVersion */, + sbeEnabled ? 2 : 1 /* cacheEntryVersion */, true /*activeCacheEntry*/, "b_1" /*cachedIndexName*/, avoidReplanLookupPipeline); @@ -459,7 +459,7 @@ assertCacheUsage(false /*multiPlanning*/, * solution. */ function testReplanningAndCacheInvalidationOnForeignCollSizeIncrease(singleSolution) { - if (!sbeFullEnabled) { + if (!sbeEnabled) { return; } @@ -552,7 +552,7 @@ let explain = coll.explain().aggregate(avoidReplanLookupPipeline); const eqLookupNodes = getAggPlanStages(explain, "EQ_LOOKUP"); assert.eq(eqLookupNodes.length, 0, "expected no EQ_LOOKUP nodes; got " + tojson(explain)); -if (sbeFullEnabled) { +if (sbeEnabled) { runLookupQuery(); const profileObj = getLatestProfilerEntry(db, {op: "command", ns: coll.getFullName()}); const matchingCacheEntries = @@ -621,7 +621,7 @@ explain = coll.explain().aggregate(avoidReplanLookupPipeline); groupNodes = getAggPlanStages(explain, "GROUP"); assert.eq(groupNodes.length, 0); -if (sbeFullEnabled) { +if (sbeEnabled) { runGroupQuery(); const profileObj = getLatestProfilerEntry(db, {op: "command", ns: coll.getFullName()}); const matchingCacheEntries = diff --git a/jstests/noPassthrough/plan_cache_replan_sort.js b/jstests/noPassthrough/plan_cache_replan_sort.js index 711a2676a15..16c80ea346b 100644 --- a/jstests/noPassthrough/plan_cache_replan_sort.js +++ b/jstests/noPassthrough/plan_cache_replan_sort.js @@ -44,7 +44,7 @@ assert.eq(1, cachedPlans.length, cachedPlans); assert.eq(true, cachedPlans[0].isActive, cachedPlans); const cachedPlan = getCachedPlan(cachedPlans[0].cachedPlan); const cachedPlanVersion = cachedPlans[0].version; -if (checkSBEEnabled(db, ["featureFlagSbeFull"])) { +if (checkSBEEnabled(db)) { // If the SBE plan cache is on, then the cached plan has a different format. assert.eq(cachedPlanVersion, "2", cachedPlans); assert(cachedPlan.stages.includes("sort"), cachedPlans); diff --git a/jstests/noPassthrough/plan_cache_stats_agg_source.js b/jstests/noPassthrough/plan_cache_stats_agg_source.js index 01bbf6a75a0..9c2777e1f04 100644 --- a/jstests/noPassthrough/plan_cache_stats_agg_source.js +++ b/jstests/noPassthrough/plan_cache_stats_agg_source.js @@ -16,11 +16,7 @@ assert.neq(null, conn, "mongod failed to start up"); const testDb = conn.getDB("test"); const coll = testDb.plan_cache_stats_agg_source; - -// Note that the "getParameter" command is expected to fail in versions of mongod that do not yet -// include the slot-based execution engine. When that happens, however, 'isSBEEnabled' still -// correctly evaluates to false. -const isSBEEnabled = checkSBEEnabled(testDb, ["featureFlagSbeFull"]); +const isSBEEnabled = checkSBEEnabled(testDb); function makeMatchForFilteringByShape(query) { const keyHash = getPlanCacheKeyFromShape({query: query, collection: coll, db: testDb}); diff --git a/jstests/noPassthrough/query_engine_stats.js b/jstests/noPassthrough/query_engine_stats.js index bf0cef1f043..a505b7512a0 100644 --- a/jstests/noPassthrough/query_engine_stats.js +++ b/jstests/noPassthrough/query_engine_stats.js @@ -15,8 +15,8 @@ assert.neq(null, conn, "mongod was unable to start up"); let db = conn.getDB(jsTestName()); // This test assumes that SBE is being used for most queries. -if (!checkSBEEnabled(db, ["featureFlagSbeFull"])) { - jsTestLog("Skipping test because SBE is not fully enabled"); +if (!checkSBEEnabled(db)) { + jsTestLog("Skipping test because SBE is not enabled"); MongoRunner.stopMongod(conn); return; } diff --git a/jstests/noPassthrough/restart_index_build_if_resume_fails.js b/jstests/noPassthrough/restart_index_build_if_resume_fails.js index 0336894febf..bcd1e3a50ce 100644 --- a/jstests/noPassthrough/restart_index_build_if_resume_fails.js +++ b/jstests/noPassthrough/restart_index_build_if_resume_fails.js @@ -24,9 +24,9 @@ rst.initiate(); let primary = rst.getPrimary(); let coll = primary.getDB(dbName).getCollection(collName); -const columnstoreEnabled = checkSBEEnabled(primary.getDB(dbName), - ["featureFlagColumnstoreIndexes", "featureFlagSbeFull"], - true /* checkAllNodes */) && +const columnstoreEnabled = + checkSBEEnabled( + primary.getDB(dbName), ["featureFlagColumnstoreIndexes"], true /* checkAllNodes */) && setUpServerForColumnStoreIndexTest(primary.getDB(dbName)); assert.commandWorked(coll.insert({a: 1})); diff --git a/jstests/noPassthrough/restart_index_build_if_resume_interrupted_by_shutdown.js b/jstests/noPassthrough/restart_index_build_if_resume_interrupted_by_shutdown.js index 0d9d4b1ff9b..46f5fd8d80a 100644 --- a/jstests/noPassthrough/restart_index_build_if_resume_interrupted_by_shutdown.js +++ b/jstests/noPassthrough/restart_index_build_if_resume_interrupted_by_shutdown.js @@ -25,8 +25,7 @@ rst.initiate(); let primary = rst.getPrimary(); const columnstoreEnabled = - checkSBEEnabled( - primary.getDB(dbName), ["featureFlagColumnstoreIndexes", "featureFlagSbeFull"], true) && + checkSBEEnabled(primary.getDB(dbName), ["featureFlagColumnstoreIndexes"], true) && setUpServerForColumnStoreIndexTest(primary.getDB(dbName)); ResumableIndexBuildTest.runResumeInterruptedByShutdown( diff --git a/jstests/noPassthrough/resumable_index_build_bulk_load_phase.js b/jstests/noPassthrough/resumable_index_build_bulk_load_phase.js index 6e24516c726..147c4e4281e 100644 --- a/jstests/noPassthrough/resumable_index_build_bulk_load_phase.js +++ b/jstests/noPassthrough/resumable_index_build_bulk_load_phase.js @@ -21,9 +21,8 @@ const rst = new ReplSetTest({nodes: 1}); rst.startSet(); rst.initiate(); -const columnstoreEnabled = checkSBEEnabled(rst.getPrimary().getDB(dbName), - ["featureFlagColumnstoreIndexes", "featureFlagSbeFull"], - true) && +const columnstoreEnabled = + checkSBEEnabled(rst.getPrimary().getDB(dbName), ["featureFlagColumnstoreIndexes"], true) && setUpServerForColumnStoreIndexTest(rst.getPrimary().getDB(dbName)); const runTests = function(docs, indexSpecsFlat, collNameSuffix) { diff --git a/jstests/noPassthrough/resumable_index_build_bulk_load_phase_large.js b/jstests/noPassthrough/resumable_index_build_bulk_load_phase_large.js index 3c217cc272f..8cbdcb18268 100644 --- a/jstests/noPassthrough/resumable_index_build_bulk_load_phase_large.js +++ b/jstests/noPassthrough/resumable_index_build_bulk_load_phase_large.js @@ -23,9 +23,8 @@ const rst = new ReplSetTest( rst.startSet(); rst.initiate(); -const columnstoreEnabled = checkSBEEnabled(rst.getPrimary().getDB(dbName), - ["featureFlagColumnstoreIndexes", "featureFlagSbeFull"], - true) && +const columnstoreEnabled = + checkSBEEnabled(rst.getPrimary().getDB(dbName), ["featureFlagColumnstoreIndexes"], true) && setUpServerForColumnStoreIndexTest(rst.getPrimary().getDB(dbName)); // Insert enough data so that the collection scan spills to disk. diff --git a/jstests/noPassthrough/resumable_index_build_clearing_tmp_directory_on_restart.js b/jstests/noPassthrough/resumable_index_build_clearing_tmp_directory_on_restart.js index fb563c40cca..c94db0b2ee7 100644 --- a/jstests/noPassthrough/resumable_index_build_clearing_tmp_directory_on_restart.js +++ b/jstests/noPassthrough/resumable_index_build_clearing_tmp_directory_on_restart.js @@ -30,8 +30,7 @@ rst.initiate(); // Insert enough data so that the collection scan spills to disk. const primary = rst.getPrimary(); const columnstoreEnabled = - checkSBEEnabled( - primary.getDB(dbName), ["featureFlagColumnstoreIndexes", "featureFlagSbeFull"], true) && + checkSBEEnabled(primary.getDB(dbName), ["featureFlagColumnstoreIndexes"], true) && setUpServerForColumnStoreIndexTest(primary.getDB(dbName)); const coll = primary.getDB(dbName).getCollection(jsTestName()); const bulk = coll.initializeUnorderedBulkOp(); diff --git a/jstests/noPassthrough/resumable_index_build_collection_scan_phase.js b/jstests/noPassthrough/resumable_index_build_collection_scan_phase.js index 5186ecfe278..49ec48f5ced 100644 --- a/jstests/noPassthrough/resumable_index_build_collection_scan_phase.js +++ b/jstests/noPassthrough/resumable_index_build_collection_scan_phase.js @@ -22,9 +22,8 @@ const rst = new ReplSetTest({nodes: 1}); rst.startSet(); rst.initiate(); -const columnstoreEnabled = checkSBEEnabled(rst.getPrimary().getDB(dbName), - ["featureFlagColumnstoreIndexes", "featureFlagSbeFull"], - true) && +const columnstoreEnabled = + checkSBEEnabled(rst.getPrimary().getDB(dbName), ["featureFlagColumnstoreIndexes"], true) && setUpServerForColumnStoreIndexTest(rst.getPrimary().getDB(dbName)); const runTests = function(docs, indexSpecsFlat, collNameSuffix) { diff --git a/jstests/noPassthrough/resumable_index_build_collection_scan_phase_large.js b/jstests/noPassthrough/resumable_index_build_collection_scan_phase_large.js index d1c498eb3eb..d1dd867cb3e 100644 --- a/jstests/noPassthrough/resumable_index_build_collection_scan_phase_large.js +++ b/jstests/noPassthrough/resumable_index_build_collection_scan_phase_large.js @@ -33,8 +33,7 @@ const primary = rst.getPrimary(); const coll = primary.getDB(dbName).getCollection(jsTestName()); const columnstoreEnabled = - checkSBEEnabled( - primary.getDB(dbName), ["featureFlagColumnstoreIndexes", "featureFlagSbeFull"], true) && + checkSBEEnabled(primary.getDB(dbName), ["featureFlagColumnstoreIndexes"], true) && setUpServerForColumnStoreIndexTest(primary.getDB(dbName)); const bulk = coll.initializeUnorderedBulkOp(); diff --git a/jstests/noPassthrough/resumable_index_build_drain_writes_phase_primary.js b/jstests/noPassthrough/resumable_index_build_drain_writes_phase_primary.js index 8e6f529c8c4..52def8c8bde 100644 --- a/jstests/noPassthrough/resumable_index_build_drain_writes_phase_primary.js +++ b/jstests/noPassthrough/resumable_index_build_drain_writes_phase_primary.js @@ -25,8 +25,8 @@ rst.initiate(); const primary = rst.getPrimary(); const coll = primary.getDB(dbName).getCollection(collName); -const columnstoreEnabled = checkSBEEnabled( - primary.getDB(dbName), ["featureFlagColumnstoreIndexes", "featureFlagSbeFull"], true); +const columnstoreEnabled = + checkSBEEnabled(primary.getDB(dbName), ["featureFlagColumnstoreIndexes"], true); assert.commandWorked(coll.insert({a: 1})); diff --git a/jstests/noPassthrough/resumable_index_build_drain_writes_phase_secondary.js b/jstests/noPassthrough/resumable_index_build_drain_writes_phase_secondary.js index f70971967c1..cb859855d34 100644 --- a/jstests/noPassthrough/resumable_index_build_drain_writes_phase_secondary.js +++ b/jstests/noPassthrough/resumable_index_build_drain_writes_phase_secondary.js @@ -33,8 +33,8 @@ rst.initiateWithHighElectionTimeout(); let primary = rst.getPrimary(); let coll = primary.getDB(dbName).getCollection(collName); -const columnstoreEnabled = checkSBEEnabled( - primary.getDB(dbName), ["featureFlagColumnstoreIndexes", "featureFlagSbeFull"], true); +const columnstoreEnabled = + checkSBEEnabled(primary.getDB(dbName), ["featureFlagColumnstoreIndexes"], true); assert.commandWorked(coll.insert({a: 1})); diff --git a/jstests/noPassthrough/resumable_index_build_initialized.js b/jstests/noPassthrough/resumable_index_build_initialized.js index f89c0fed9a3..aa672b3260d 100644 --- a/jstests/noPassthrough/resumable_index_build_initialized.js +++ b/jstests/noPassthrough/resumable_index_build_initialized.js @@ -22,9 +22,8 @@ const rst = new ReplSetTest({nodes: 1}); rst.startSet(); rst.initiate(); -const columnstoreEnabled = checkSBEEnabled(rst.getPrimary().getDB(dbName), - ["featureFlagColumnstoreIndexes", "featureFlagSbeFull"], - true) && +const columnstoreEnabled = + checkSBEEnabled(rst.getPrimary().getDB(dbName), ["featureFlagColumnstoreIndexes"], true) && setUpServerForColumnStoreIndexTest(rst.getPrimary().getDB(dbName)); const runTests = function(docs, indexSpecsFlat, collNameSuffix) { diff --git a/jstests/noPassthrough/resumable_index_build_mixed_phases.js b/jstests/noPassthrough/resumable_index_build_mixed_phases.js index d372e51360b..463d481d5e2 100644 --- a/jstests/noPassthrough/resumable_index_build_mixed_phases.js +++ b/jstests/noPassthrough/resumable_index_build_mixed_phases.js @@ -21,9 +21,8 @@ const rst = new ReplSetTest({nodes: 1}); rst.startSet(); rst.initiate(); -const columnstoreEnabled = checkSBEEnabled(rst.getPrimary().getDB(dbName), - ["featureFlagColumnstoreIndexes", "featureFlagSbeFull"], - true) && +const columnstoreEnabled = + checkSBEEnabled(rst.getPrimary().getDB(dbName), ["featureFlagColumnstoreIndexes"], true) && setUpServerForColumnStoreIndexTest(rst.getPrimary().getDB(dbName)); const runTest = function(docs, indexSpecs, failPoints, resumePhases, resumeChecks, collNameSuffix) { diff --git a/jstests/noPassthrough/sbe_multiplanner_trial_termination.js b/jstests/noPassthrough/sbe_multiplanner_trial_termination.js index 0fdd65ef851..a3178cd2858 100644 --- a/jstests/noPassthrough/sbe_multiplanner_trial_termination.js +++ b/jstests/noPassthrough/sbe_multiplanner_trial_termination.js @@ -25,8 +25,8 @@ assert.neq(conn, null, "mongod failed to start"); const db = conn.getDB(dbName); // This test assumes that SBE is being used for most queries. -if (!checkSBEEnabled(db, ["featureFlagSbeFull"])) { - jsTestLog("Skipping test because SBE is not fully enabled"); +if (!checkSBEEnabled(db)) { + jsTestLog("Skipping test because SBE is not enabled"); MongoRunner.stopMongod(conn); return; } diff --git a/jstests/noPassthrough/sbe_plan_cache_clear_on_param_change.js b/jstests/noPassthrough/sbe_plan_cache_clear_on_param_change.js index 546d94f7e2f..09b94049c97 100644 --- a/jstests/noPassthrough/sbe_plan_cache_clear_on_param_change.js +++ b/jstests/noPassthrough/sbe_plan_cache_clear_on_param_change.js @@ -56,10 +56,9 @@ assert.neq(conn, null, "mongod failed to start up"); const dbName = jsTestName(); const db = conn.getDB(dbName); -// This test is specifically verifying the behavior of the SBE plan cache which is enabled by -// 'featureFlagSbeFull'. -if (!checkSBEEnabled(db, ["featureFlagSbeFull"])) { - jsTestLog("Skipping test because SBE is not fully enabled"); +// This test is specifically verifying the behavior of the SBE plan cache. +if (!checkSBEEnabled(db)) { + jsTestLog("Skipping test because SBE is not enabled"); MongoRunner.stopMongod(conn); return; } diff --git a/jstests/noPassthrough/sbe_plan_cache_key_reporting.js b/jstests/noPassthrough/sbe_plan_cache_key_reporting.js index e603c495d0e..0cf0546a6bd 100644 --- a/jstests/noPassthrough/sbe_plan_cache_key_reporting.js +++ b/jstests/noPassthrough/sbe_plan_cache_key_reporting.js @@ -20,8 +20,8 @@ assert.neq(conn, null, "mongod failed to start"); const db = conn.getDB("plan_cache_key_reporting"); const coll = db.coll; -if (!checkSBEEnabled(db, ["featureFlagSbeFull"])) { - jsTest.log("Skipping test because SBE is not fully enabled"); +if (!checkSBEEnabled(db)) { + jsTest.log("Skipping test because SBE is not enabled"); MongoRunner.stopMongod(conn); return; } diff --git a/jstests/noPassthrough/sbe_plan_cache_memory_debug_info.js b/jstests/noPassthrough/sbe_plan_cache_memory_debug_info.js index 7bcdba91a34..d07a4456002 100644 --- a/jstests/noPassthrough/sbe_plan_cache_memory_debug_info.js +++ b/jstests/noPassthrough/sbe_plan_cache_memory_debug_info.js @@ -19,8 +19,8 @@ const conn = MongoRunner.runMongod({}); assert.neq(conn, null, "mongod failed to start"); const db = conn.getDB("sbe_plan_cache_memory_debug_info"); -if (!checkSBEEnabled(db, ["featureFlagSbeFull"])) { - jsTest.log("Skipping test because SBE is not fully enabled"); +if (!checkSBEEnabled(db)) { + jsTest.log("Skipping test because SBE is not enabled"); MongoRunner.stopMongod(conn); return; } diff --git a/jstests/noPassthrough/sbe_plan_cache_size_metric.js b/jstests/noPassthrough/sbe_plan_cache_size_metric.js index a0b820d10f2..1eb667754e0 100644 --- a/jstests/noPassthrough/sbe_plan_cache_size_metric.js +++ b/jstests/noPassthrough/sbe_plan_cache_size_metric.js @@ -23,8 +23,8 @@ const conn = MongoRunner.runMongod(); assert.neq(conn, null, "mongod failed to start"); const db = conn.getDB("sbe_plan_cache_size_metric"); -if (!checkSBEEnabled(db, ["featureFlagSbeFull"])) { - jsTest.log("Skipping test because SBE is not fully enabled"); +if (!checkSBEEnabled(db)) { + jsTest.log("Skipping test because SBE is not enabled"); MongoRunner.stopMongod(conn); return; } diff --git a/jstests/noPassthrough/server_status_multiplanner.js b/jstests/noPassthrough/server_status_multiplanner.js index 580bc736daa..db4c528f031 100644 --- a/jstests/noPassthrough/server_status_multiplanner.js +++ b/jstests/noPassthrough/server_status_multiplanner.js @@ -24,8 +24,8 @@ assert.neq(conn, null, "mongod failed to start"); const db = conn.getDB(dbName); // This test assumes that SBE is being used for most queries. -if (!checkSBEEnabled(db, ["featureFlagSbeFull"])) { - jsTestLog("Skipping test because SBE is not fully enabled"); +if (!checkSBEEnabled(db)) { + jsTestLog("Skipping test because SBE is not enabled"); MongoRunner.stopMongod(conn); return; } diff --git a/jstests/noPassthroughWithMongod/columnstore_planning_heuristics.js b/jstests/noPassthroughWithMongod/columnstore_planning_heuristics.js index 8bf80294e61..386ae3d57ad 100644 --- a/jstests/noPassthroughWithMongod/columnstore_planning_heuristics.js +++ b/jstests/noPassthroughWithMongod/columnstore_planning_heuristics.js @@ -2,9 +2,8 @@ * Testing of the query planner heuristics for determining whether a collection is eligible for * column scan. * @tags: [ - * # column store indexes are still under a feature flag and require full sbe - * featureFlagColumnstoreIndexes, - * featureFlagSbeFull + * # column store indexes are still under a feature flag + * featureFlagColumnstoreIndexes * ] */ (function() { diff --git a/jstests/noPassthroughWithMongod/group_pushdown.js b/jstests/noPassthroughWithMongod/group_pushdown.js index fe11f9f8def..63bbc29de15 100644 --- a/jstests/noPassthroughWithMongod/group_pushdown.js +++ b/jstests/noPassthroughWithMongod/group_pushdown.js @@ -8,7 +8,7 @@ load("jstests/libs/analyze_plan.js"); load("jstests/libs/sbe_util.js"); // For checkSBEEnabled. if (!checkSBEEnabled(db)) { - jsTestLog("Skipping test because the sbe group pushdown feature flag is disabled"); + jsTestLog("Skipping test because SBE is not enabled"); return; } @@ -185,28 +185,38 @@ assertResultsMatchWithAndWithoutPushdown( ], 1); -// The $group stage refers to two existing sub-fields. -assertResultsMatchWithAndWithoutPushdown( - coll, - [ - {$project: {item: 1, price: 1, quantity: 1, dateParts: {$dateToParts: {date: "$date"}}}}, - { - $group: { - _id: "$item", - hs: {$sum: {$add: ["$dateParts.hour", "$dateParts.hour", "$dateParts.minute"]}} - } - }, - ], - [{"_id": "a", "hs": 39}, {"_id": "b", "hs": 34}, {"_id": "c", "hs": 23}], - 1); - -// The $group stage refers to a non-existing sub-field twice. -assertResultsMatchWithAndWithoutPushdown( - coll, - [{$group: {_id: "$item", hs: {$sum: {$add: ["$date.hour", "$date.hour"]}}}}], - [{"_id": "a", "hs": 0}, {"_id": "b", "hs": 0}, {"_id": "c", "hs": 0}], - 1); - +// Computed projections are only eligible for pushdown into SBE when SBE is fully enabled. +// Additionally, $group stages with dotted fields may only be eligible for pushdown when SBE is +// fully enabled as dependancy analysis may produce a dotted projection, which are not currently +// supported in mainline SBE. +const sbeFull = checkSBEEnabled(db, ["featureFlagSbeFull"]); +if (sbeFull) { + // The $group stage refers to two existing sub-fields. + assertResultsMatchWithAndWithoutPushdown( + coll, + [ + { + $project: + {item: 1, price: 1, quantity: 1, dateParts: {$dateToParts: {date: "$date"}}} + }, + { + $group: { + _id: "$item", + hs: {$sum: + {$add: ["$dateParts.hour", "$dateParts.hour", "$dateParts.minute"]}} + } + }, + ], + [{"_id": "a", "hs": 39}, {"_id": "b", "hs": 34}, {"_id": "c", "hs": 23}], + 1); + + // The $group stage refers to a non-existing sub-field twice. + assertResultsMatchWithAndWithoutPushdown( + coll, + [{$group: {_id: "$item", hs: {$sum: {$add: ["$date.hour", "$date.hour"]}}}}], + [{"_id": "a", "hs": 0}, {"_id": "b", "hs": 0}, {"_id": "c", "hs": 0}], + 1); +} // Two group stages both get pushed down and the second $group stage refers to only existing // top-level fields of the first $group. The field name may be one of "result" / "recordId" / // "returnKey" / "snapshotId" / "indexId" / "indexKey" / "indexKeyPattern" which are reserved names diff --git a/jstests/noPassthroughWithMongod/index_bounds_static_limit.js b/jstests/noPassthroughWithMongod/index_bounds_static_limit.js index dc183a27346..616ddcf2a93 100644 --- a/jstests/noPassthroughWithMongod/index_bounds_static_limit.js +++ b/jstests/noPassthroughWithMongod/index_bounds_static_limit.js @@ -9,8 +9,8 @@ load("jstests/libs/analyze_plan.js"); // For explain helpers. load("jstests/libs/sbe_util.js"); // For checkSBEEnabled. -if (!checkSBEEnabled(db, ["featureFlagSbeFull"])) { - jsTest.log("Skipping test because SBE is not fully enabled"); +if (!checkSBEEnabled(db)) { + jsTest.log("Skipping test because SBE is not enabled"); return; } diff --git a/jstests/noPassthroughWithMongod/ne_array_indexability.js b/jstests/noPassthroughWithMongod/ne_array_indexability.js index f2ecb27151f..e632e5fc1b6 100644 --- a/jstests/noPassthroughWithMongod/ne_array_indexability.js +++ b/jstests/noPassthroughWithMongod/ne_array_indexability.js @@ -31,7 +31,7 @@ function runTest(queryToCache, queryToRunAfterCaching) { // a different planCacheKey. The SBE plan cache, on the other hand, does not auto-parameterize // $in or $eq involving a constant of type array, and therefore will consider the two queries to // have different shapes. - if (checkSBEEnabled(db, ["featureFlagSbeFull"])) { + if (checkSBEEnabled(db)) { assert.neq(explain.queryPlanner.queryHash, cacheEntries[0].queryHash); } else { assert.eq(explain.queryPlanner.queryHash, cacheEntries[0].queryHash); diff --git a/jstests/noPassthroughWithMongod/plan_cache_replanning.js b/jstests/noPassthroughWithMongod/plan_cache_replanning.js index e17a81cb660..d293413f0fc 100644 --- a/jstests/noPassthroughWithMongod/plan_cache_replanning.js +++ b/jstests/noPassthroughWithMongod/plan_cache_replanning.js @@ -10,7 +10,7 @@ load('jstests/libs/analyze_plan.js'); // For getPlanStage(). load("jstests/libs/collection_drop_recreate.js"); // For assert[Drop|Create]Collection. load("jstests/libs/sbe_util.js"); // For checkSBEEnabled. -const isSbeEnabled = checkSBEEnabled(db, ["featureFlagSbeFull"]); +const isSbeEnabled = checkSBEEnabled(db); let coll = assertDropAndRecreateCollection(db, "plan_cache_replanning"); diff --git a/jstests/noPassthroughWithMongod/sbe_query_eligibility.js b/jstests/noPassthroughWithMongod/sbe_query_eligibility.js new file mode 100644 index 00000000000..f9bc9fcb181 --- /dev/null +++ b/jstests/noPassthroughWithMongod/sbe_query_eligibility.js @@ -0,0 +1,192 @@ +/** + * Test that verifies which query shapes which are eligible for SBE. + */ +(function() { +"use strict"; + +load("jstests/libs/analyze_plan.js"); +load("jstests/libs/sbe_util.js"); // For 'checkSBEEnabled'. + +/** + * Utility which asserts whether, when aggregating over 'collection' with 'pipeline', whether + * explain reports that SBE or classic was used, based on the value of 'isSBE'. + */ +function assertEngineUsed(collection, pipeline, isSBE) { + const explain = collection.explain().aggregate(pipeline); + const expectedExplainVersion = isSBE ? "2" : "1"; + assert(explain.hasOwnProperty("explainVersion"), explain); + assert.eq(explain.explainVersion, expectedExplainVersion, explain); +} + +if (!checkSBEEnabled(db)) { + jsTestLog("Skipping test because SBE is disabled"); + return; +} + +const collName = "sbe_eligiblity"; +const coll = db[collName]; +coll.drop(); +assert.commandWorked(coll.insert({})); +assert.eq(coll.find().itcount(), 1); + +// Simple eligible cases. +const expectedSbeCases = [ + // Non-$expr match filters. + [{$match: {a: 1}}], + [{$match: {"a.b.c": 1}}], + + // Top level projections. + [{$project: {a: 1, b: 1}}], + [{$project: {a: 0, b: 0}}], + + // Sorts with no common prefixes. + [{$sort: {a: 1}}], + [{$sort: {"a.b.c": 1}}], + + // Test a combination of the above categories. + [{$match: {a: 1}}, {$sort: {b: 1}}], + [{$match: {a: 1}}, {$sort: {b: 1, c: 1}}], + [{$match: {a: 1}}, {$project: {b: 1, c: 1}}, {$sort: {b: 1, c: 1}}], + [ + {$match: {a: 1, b: 1, "c.d.e": {$mod: [2, 0]}}}, + {$project: {b: 1, c: 1}}, + {$sort: {b: 1, c: 1}} + ], + + // $lookup and $group should work as expected. + [ + {$match: {a: 1}}, + {$project: {a: 1}}, + {$lookup: {from: collName, localField: "a", foreignField: "a", as: "out"}} + ], + [{$match: {a: 1}}, {$project: {a: 1}}, {$group: {_id: "$a", out: {$sum: 1}}}], + + // If we have a non-SBE compatible expression after the pushdown boundary, this should not + // inhibit the pushdown of the pipeline prefix into SBE. + [ + {$match: {a: 1}}, + {$project: {a: 1}}, + {$lookup: {from: collName, localField: "a", foreignField: "a", as: "out"}}, + {$addFields: {foo: {$sum: "$a"}}}, + {$match: {$expr: {$eq: ["$a", "$b"]}}} + ], + [ + {$match: {a: 1}}, + {$project: {a: 1}}, + {$group: {_id: "$a", out: {$sum: 1}}}, + {$match: {$expr: {$eq: ["$a", "$b"]}}} + ], +]; + +for (const pipeline of expectedSbeCases) { + assertEngineUsed(coll, pipeline, true /* isSBE */); +} + +// The cases below are expected to use SBE only if 'featureFlagSbeFull' is on. +const isSbeFullyEnabled = checkSBEEnabled(db, ["featureFlagSbeFull"]); +const sbeFullCases = [ + // Match filters with $expr. + [{$match: {$expr: {$eq: ["$a", "$b"]}}}], + [{$match: {$and: [{$expr: {$eq: ["$a", "$b"]}}, {c: 1}]}}], + + // Dotted projections. + [{$project: {"a.b": 1}}], + [{$project: {"a.b": 0}}], + [{$project: {"a.b": 1, "a.c": 1}}], + [{$project: {"a.b.c.d.e.f.g": 0, "h.i.j.k": 0}}], + + // Computed projections. + [{$project: {a: {$add: ["$foo", "$bar"]}}}], + [{$project: {a: {$divide: ["$foo", "$bar"]}}}], + + // Sorts with common prefixes. + [{$sort: {"a.b": 1, "a.c": 1}}], + [{$sort: {"a.b.f.g": 1, "a.d.e.f": 1}}], + [{$sort: {"a": 1, "b": 1, "c.d": 1, "c.f": 1}}], + + // Mix SBE-eligible and non-SBE eligible filters, projections and sorts. + + // Match filters with $expr should inhibit pushdown. + [{$project: {a: 1, b: 1}}, {$match: {$expr: {$eq: ["$a", "$b"]}}}], + [{$match: {$and: [{$expr: {$eq: ["$a", "$b"]}}, {c: 1}]}}, {$sort: {a: 1, d: 1}}], + [ + {$match: {$and: [{$expr: {$eq: ["$a", "$b"]}}, {c: 1}]}}, + { + $lookup: + {from: collName, localField: "c_custkey", foreignField: "o_custkey", as: "custsale"} + } + ], + + // Dotted projections should inhibit pushdown. + [{$match: {d: 1}}, {$project: {"a.b": 1}}], + [{$sort: {d: 1, e: 1}}, {$project: {"a.b": 0}}], + [{$match: {$or: [{a: {$gt: 0}}, {b: {$gt: 0}}]}}, {$project: {"d.a": 1}}], + + [ + {$project: {"a.b": 1, "a.d": 1}}, + {$lookup: {from: collName, localField: "a", foreignField: "a", as: "out"}}, + ], + + // Computed projections should inhibit pushdown. + [{$match: {foo: {$gt: 0}}}, {$project: {a: {$add: ["$foo", "$bar"]}}}], + [{$project: {a: {$add: ["$foo", "$bar"]}}}, {$sort: {a: 1}}], + [ + {$project: {a: {$add: ["$foo", "$bar"]}}}, + {$group: {_id: "$a", "ct": {$sum: 1}}}, + ], + [ + {$project: {a: {$add: ["$out", 1]}}}, + {$lookup: {from: collName, localField: "a", foreignField: "a", as: "out"}}, + ], + + // Sorts with common prefixes should inhibit pushdown. + [{$match: {foo: {$gt: 0}}}, {$sort: {"a.b": 1, "a.c": 1}}], + [{$sort: {"a.b.f.g": 1, "a.d.e.f": 1}}, {$project: {a: 1}}], + [{$match: {$or: [{a: {$gt: 0}}, {b: {$gt: 0}}]}}, {$sort: {"d.a": 1, "d.b": 1}}], + [ + {$sort: {"a.b": 1, "a.c": 1}}, + {$group: {_id: {a: "$foo", b: "$bar"}, "a": {$sum: 1}}}, + ], + [ + {$sort: {"b.c": 1, "b.d": 1}}, + {$lookup: {from: collName, localField: "a", foreignField: "a", as: "out"}}, + ], + + // TPC-H query whose $lookup is SBE compatible, but which features a $match which uses $expr. + // Note that $match will be pushed to the front of the pipeline. + [ + { + $lookup: + {from: collName, localField: "c_custkey", foreignField: "o_custkey", as: "custsale"} + }, + {$addFields: {cntrycode: {$substr: ["$c_phone", 0, 2]}, custsale: {$size: "$custsale"}}}, + { + $match: { + $and: [ + { + $expr: { + $in: [ + "$cntrycode", + [ + {$toString: "13"}, + {$toString: "31"}, + {$toString: "23"}, + {$toString: "29"}, + {$toString: "30"}, + {$toString: "18"}, + {$toString: "17"} + ] + ] + } + }, + {$expr: {$gt: ["$c_acctbal", 0.00]}} + ] + } + } + ], +]; + +for (const pipeline of sbeFullCases) { + assertEngineUsed(coll, pipeline, isSbeFullyEnabled /* isSBE */); +} +})(); diff --git a/jstests/sharding/invalidate_plan_cache_entries_when_collection_generation_changes.js b/jstests/sharding/invalidate_plan_cache_entries_when_collection_generation_changes.js index 6aafb4c44ae..ffc349fa76b 100644 --- a/jstests/sharding/invalidate_plan_cache_entries_when_collection_generation_changes.js +++ b/jstests/sharding/invalidate_plan_cache_entries_when_collection_generation_changes.js @@ -1,6 +1,11 @@ /** * Tests that plan cache entries are deleted after shard key refining, resharding and renaming * operations. + * + * @tags: [ + * # The SBE plan cache was enabled by default in 6.3. + * requires_fcv_63, + * ] */ // Cannot run the filtering metadata check on tests that run refineCollectionShardKey. @@ -28,7 +33,7 @@ const db = st.getDB(dbName); const collA = db["collA"]; const collB = db["collB"]; -if (!checkSBEEnabled(db, ["featureFlagSbeFull"])) { +if (!checkSBEEnabled(db)) { jsTestLog("********** Skip the test because SBE is disabled **********"); st.stop(); return; diff --git a/jstests/sharding/sbe_plan_cache_does_not_block_range_deletion.js b/jstests/sharding/sbe_plan_cache_does_not_block_range_deletion.js index e48b23ccf44..b117f7b3e69 100644 --- a/jstests/sharding/sbe_plan_cache_does_not_block_range_deletion.js +++ b/jstests/sharding/sbe_plan_cache_does_not_block_range_deletion.js @@ -24,7 +24,7 @@ const st = new ShardingTest({mongos: 1, config: 1, shards: 2}); assert.commandWorked(st.s.adminCommand({enableSharding: dbName})); st.ensurePrimaryShard(dbName, st.shard0.shardName); -const isSbeFullyEnabled = checkSBEEnabled(st.s.getDB(dbName), ["featureFlagSbeFull"]); +const isSBEEnabled = checkSBEEnabled(st.s.getDB(dbName)); const coll = st.s.getDB(dbName)[collName]; @@ -67,9 +67,9 @@ function runTest({indexes, document, filter}) { }); } -// Scenario with just one available indexed plan. If SBE is fully enabled, then the SBE plan cache -// is in use and we expect a pinned plan cache entry. -if (isSbeFullyEnabled) { +// Scenario with just one available indexed plan. If SBE is enabled, then the SBE plan cache is in +// use and we expect a pinned plan cache entry. +if (isSBEEnabled) { runTest({indexes: [{a: 1}], document: {_id: 0, a: "abc"}, filter: {a: "abc"}}); } @@ -83,8 +83,8 @@ runTest({ // Test a rooted $or query. This should use the subplanner. The way that the subplanner interacts // with the plan cache differs between the classic engine and SBE. In the classic engine, the plan // for each branch is cached independently, whereas in SBE we cache the entire "composite" plan. -// This test is written to expect the SBE behavior, so it only runs when SBE is fully enabled. -if (isSbeFullyEnabled) { +// This test is written to expect the SBE behavior, so it only runs when SBE is enabled. +if (isSBEEnabled) { runTest({ indexes: [{a: 1}, {b: 1}, {c: 1}, {d: 1}], document: {_id: 0, a: "abc", b: "123", c: 4, d: 5}, |