diff options
-rw-r--r-- | jstests/core/clustered_collection_collation.js | 16 | ||||
-rw-r--r-- | jstests/core/index_filter_commands.js | 4 | ||||
-rw-r--r-- | jstests/core/profile_findandmodify.js | 2 | ||||
-rw-r--r-- | jstests/core/timeseries/timeseries_bucket_index.js | 2 | ||||
-rw-r--r-- | jstests/core/timeseries/timeseries_id_range.js | 30 | ||||
-rw-r--r-- | jstests/libs/analyze_plan.js | 4 | ||||
-rw-r--r-- | jstests/libs/clustered_collections/clustered_collection_bounded_scan_common.js | 32 | ||||
-rw-r--r-- | jstests/libs/clustered_collections/clustered_collection_hint_common.js | 20 | ||||
-rw-r--r-- | src/mongo/db/exec/collection_scan.cpp | 12 | ||||
-rw-r--r-- | src/mongo/db/exec/collection_scan.h | 2 |
10 files changed, 68 insertions, 56 deletions
diff --git a/jstests/core/clustered_collection_collation.js b/jstests/core/clustered_collection_collation.js index 23fcb82277d..9b9c11f428c 100644 --- a/jstests/core/clustered_collection_collation.js +++ b/jstests/core/clustered_collection_collation.js @@ -195,7 +195,7 @@ validateClusteredCollectionHint(collated, { expectedNReturned: 2, cmd: {find: collatedName, hint: {_id: 1}, min: {_id: "a"}, max: {_id: "C"}}, expectedWinningPlanStats: { - stage: "COLLSCAN", + stage: "CLUSTERED_IXSCAN", direction: "forward", minRecord: collatedEncodings["a"], maxRecord: collatedEncodings["C"] @@ -209,7 +209,7 @@ validateClusteredCollectionHint(noncollated, { expectedNReturned: 3, // "a", "b" and "B" cmd: {find: noncollatedName, hint: {_id: 1}, min: {_id: "A"}, max: {_id: "c"}}, expectedWinningPlanStats: - {stage: "COLLSCAN", direction: "forward", minRecord: "A", maxRecord: "c"} + {stage: "CLUSTERED_IXSCAN", direction: "forward", minRecord: "A", maxRecord: "c"} }); // Strings with incompatible collation. @@ -241,12 +241,14 @@ assert.commandFailedWithCode( validateClusteredCollectionHint(collated, { expectedNReturned: 2, cmd: {find: collatedName, hint: {_id: 1}, min: {_id: 5}, max: {_id: 11}}, - expectedWinningPlanStats: {stage: "COLLSCAN", direction: "forward", minRecord: 5, maxRecord: 11} + expectedWinningPlanStats: + {stage: "CLUSTERED_IXSCAN", direction: "forward", minRecord: 5, maxRecord: 11} }); validateClusteredCollectionHint(noncollated, { expectedNReturned: 2, cmd: {find: noncollatedName, hint: {_id: 1}, min: {_id: 5}, max: {_id: 11}}, - expectedWinningPlanStats: {stage: "COLLSCAN", direction: "forward", minRecord: 5, maxRecord: 11} + expectedWinningPlanStats: + {stage: "CLUSTERED_IXSCAN", direction: "forward", minRecord: 5, maxRecord: 11} }); // Numeric with incompatible collation. @@ -259,7 +261,8 @@ validateClusteredCollectionHint(collated, { max: {_id: 11}, collation: incompatibleCollation }, - expectedWinningPlanStats: {stage: "COLLSCAN", direction: "forward", minRecord: 5, maxRecord: 11} + expectedWinningPlanStats: + {stage: "CLUSTERED_IXSCAN", direction: "forward", minRecord: 5, maxRecord: 11} }); validateClusteredCollectionHint(noncollated, { expectedNReturned: 2, @@ -270,6 +273,7 @@ validateClusteredCollectionHint(noncollated, { max: {_id: 11}, collation: incompatibleCollation }, - expectedWinningPlanStats: {stage: "COLLSCAN", direction: "forward", minRecord: 5, maxRecord: 11} + expectedWinningPlanStats: + {stage: "CLUSTERED_IXSCAN", direction: "forward", minRecord: 5, maxRecord: 11} }); })(); diff --git a/jstests/core/index_filter_commands.js b/jstests/core/index_filter_commands.js index ea97aefed48..fd48c095028 100644 --- a/jstests/core/index_filter_commands.js +++ b/jstests/core/index_filter_commands.js @@ -163,8 +163,8 @@ assert.commandWorked(explain); const winningPlan = getWinningPlan(explain.queryPlanner); const collectionIsClustered = ClusteredCollectionUtil.areAllCollectionsClustered(db.getMongo()); if (collectionIsClustered) { - assert(isCollscan(db, getWinningPlan(explain.queryPlanner)), - "Expected collscan: " + tojson(explain)); + assert(isClusteredIxscan(db, getWinningPlan(explain.queryPlanner)), + "Expected clustered ixscan: " + tojson(explain)); } else { engineSpecificAssertion( isIdhack(db, winningPlan), isIdIndexScan(db, winningPlan, "FETCH"), db, winningPlan); diff --git a/jstests/core/profile_findandmodify.js b/jstests/core/profile_findandmodify.js index 11aa91f21dc..db8a615571b 100644 --- a/jstests/core/profile_findandmodify.js +++ b/jstests/core/profile_findandmodify.js @@ -115,7 +115,7 @@ for (var i = 0; i < 3; i++) { } const expectedKeysExamined = collectionIsClustered ? 0 : 1; -const expectedPlan = collectionIsClustered ? "COLLSCAN" : "IDHACK"; +const expectedPlan = collectionIsClustered ? "CLUSTERED_IXSCAN" : "IDHACK"; assert.eq({_id: 2, a: 2}, coll.findAndModify({query: {_id: 2}, update: {$inc: {b: 1}}})); profileObj = getLatestProfilerEntry(testDB); diff --git a/jstests/core/timeseries/timeseries_bucket_index.js b/jstests/core/timeseries/timeseries_bucket_index.js index e2bb2f78fea..3f864c35850 100644 --- a/jstests/core/timeseries/timeseries_bucket_index.js +++ b/jstests/core/timeseries/timeseries_bucket_index.js @@ -40,7 +40,7 @@ TimeseriesTest.run((insert) => { assert.docEq(buckets, bucketsColl.find({_id: bucketId}).toArray()); let explain = bucketsColl.find({_id: bucketId}).explain(); - assert(planHasStage(db, explain, "COLLSCAN"), explain); + assert(planHasStage(db, explain, "CLUSTERED_IXSCAN"), explain); assert.docEq(buckets, bucketsColl.find({"control.max.time": maxTime}).toArray()); explain = bucketsColl.find({"control.max.time": minTime}).explain(); diff --git a/jstests/core/timeseries/timeseries_id_range.js b/jstests/core/timeseries/timeseries_id_range.js index 91ab77f87f1..13ab73d62fc 100644 --- a/jstests/core/timeseries/timeseries_id_range.js +++ b/jstests/core/timeseries/timeseries_id_range.js @@ -54,8 +54,8 @@ TimeseriesTest.run((insert) => { } })); - assert(dates[5], getPlanStage(expl, "COLLSCAN").minRecord); - assert(dates[5], getPlanStage(expl, "COLLSCAN").maxRecord); + assert(dates[5], getPlanStage(expl, "CLUSTERED_IXSCAN").minRecord); + assert(dates[5], getPlanStage(expl, "CLUSTERED_IXSCAN").maxRecord); })(); (function testLTE() { @@ -66,8 +66,8 @@ TimeseriesTest.run((insert) => { assert.eq(0, res.length); let expl = coll.explain("executionStats").aggregate(pipeline); - assert(getAggPlanStage(expl, "COLLSCAN"), expl); - assert(getAggPlanStage(expl, "COLLSCAN").hasOwnProperty("maxRecord"), expl); + assert(getAggPlanStage(expl, "CLUSTERED_IXSCAN"), expl); + assert(getAggPlanStage(expl, "CLUSTERED_IXSCAN").hasOwnProperty("maxRecord"), expl); assert.eq(0, expl.stages[0].$cursor.executionStats.executionStages.nReturned); for (let i = 0; i < dates.length; i++) { @@ -88,7 +88,7 @@ TimeseriesTest.run((insert) => { assert.eq(0, res.length); let expl = coll.explain("executionStats").aggregate(pipeline); - assert(getAggPlanStage(expl, "COLLSCAN").hasOwnProperty("maxRecord")); + assert(getAggPlanStage(expl, "CLUSTERED_IXSCAN").hasOwnProperty("maxRecord")); assert.eq(0, expl.stages[0].$cursor.executionStats.executionStages.nReturned); for (let i = 0; i < dates.length; i++) { @@ -109,7 +109,7 @@ TimeseriesTest.run((insert) => { assert.eq(0, res.length); let expl = coll.explain("executionStats").aggregate(pipeline); - assert(getAggPlanStage(expl, "COLLSCAN").hasOwnProperty("minRecord")); + assert(getAggPlanStage(expl, "CLUSTERED_IXSCAN").hasOwnProperty("minRecord")); assert.eq(0, expl.stages[0].$cursor.executionStats.executionStages.nReturned); for (let i = 0; i < dates.length; i++) { @@ -130,7 +130,7 @@ TimeseriesTest.run((insert) => { assert.eq(0, res.length); let expl = coll.explain("executionStats").aggregate(pipeline); - assert(getAggPlanStage(expl, "COLLSCAN").hasOwnProperty("minRecord")); + assert(getAggPlanStage(expl, "CLUSTERED_IXSCAN").hasOwnProperty("minRecord")); assert.eq(0, expl.stages[0].$cursor.executionStats.executionStages.nReturned); for (let i = 0; i < dates.length; i++) { @@ -152,8 +152,8 @@ TimeseriesTest.run((insert) => { assert.eq(0, res.length); let expl = coll.explain("executionStats").aggregate(pipeline); - assert(getAggPlanStage(expl, "COLLSCAN").hasOwnProperty("minRecord")); - assert(getAggPlanStage(expl, "COLLSCAN").hasOwnProperty("maxRecord")); + assert(getAggPlanStage(expl, "CLUSTERED_IXSCAN").hasOwnProperty("minRecord")); + assert(getAggPlanStage(expl, "CLUSTERED_IXSCAN").hasOwnProperty("maxRecord")); assert.eq(0, expl.stages[0].$cursor.executionStats.executionStages.nReturned); for (let i = 0; i < dates.length; i++) { @@ -175,8 +175,8 @@ TimeseriesTest.run((insert) => { assert.eq(0, res.length); let expl = coll.explain("executionStats").aggregate(pipeline); - assert(getAggPlanStage(expl, "COLLSCAN").hasOwnProperty("minRecord")); - assert(getAggPlanStage(expl, "COLLSCAN").hasOwnProperty("maxRecord")); + assert(getAggPlanStage(expl, "CLUSTERED_IXSCAN").hasOwnProperty("minRecord")); + assert(getAggPlanStage(expl, "CLUSTERED_IXSCAN").hasOwnProperty("maxRecord")); assert.eq(0, expl.stages[0].$cursor.executionStats.executionStages.nReturned); for (let i = 0; i < dates.length; i++) { @@ -198,8 +198,8 @@ TimeseriesTest.run((insert) => { assert.eq(0, res.length); let expl = coll.explain("executionStats").aggregate(pipeline); - assert(getAggPlanStage(expl, "COLLSCAN").hasOwnProperty("minRecord")); - assert(getAggPlanStage(expl, "COLLSCAN").hasOwnProperty("maxRecord")); + assert(getAggPlanStage(expl, "CLUSTERED_IXSCAN").hasOwnProperty("minRecord")); + assert(getAggPlanStage(expl, "CLUSTERED_IXSCAN").hasOwnProperty("maxRecord")); assert.eq(0, expl.stages[0].$cursor.executionStats.executionStages.nReturned); for (let i = 0; i < dates.length; i++) { @@ -221,8 +221,8 @@ TimeseriesTest.run((insert) => { assert.eq(0, res.length); let expl = coll.explain("executionStats").aggregate(pipeline); - assert(getAggPlanStage(expl, "COLLSCAN").hasOwnProperty("minRecord")); - assert(getAggPlanStage(expl, "COLLSCAN").hasOwnProperty("maxRecord")); + assert(getAggPlanStage(expl, "CLUSTERED_IXSCAN").hasOwnProperty("minRecord")); + assert(getAggPlanStage(expl, "CLUSTERED_IXSCAN").hasOwnProperty("maxRecord")); assert.eq(0, expl.stages[0].$cursor.executionStats.executionStages.nReturned); for (let i = 0; i < dates.length; i++) { diff --git a/jstests/libs/analyze_plan.js b/jstests/libs/analyze_plan.js index e03cfab5cae..24624c5ad59 100644 --- a/jstests/libs/analyze_plan.js +++ b/jstests/libs/analyze_plan.js @@ -367,6 +367,10 @@ function isCollscan(db, root) { return planHasStage(db, root, "COLLSCAN"); } +function isClusteredIxscan(db, root) { + return planHasStage(db, root, "CLUSTERED_IXSCAN"); +} + /** * Returns true if the BSON representation of a plan rooted at 'root' is using the aggregation * framework, and false otherwise. diff --git a/jstests/libs/clustered_collections/clustered_collection_bounded_scan_common.js b/jstests/libs/clustered_collections/clustered_collection_bounded_scan_common.js index 6a47a8d2f3c..3d8f46e0319 100644 --- a/jstests/libs/clustered_collections/clustered_collection_bounded_scan_common.js +++ b/jstests/libs/clustered_collections/clustered_collection_bounded_scan_common.js @@ -31,9 +31,9 @@ const testClusteredCollectionBoundedScan = function(coll, clusterKey) { verbosity: "executionStats" })); - assert(getPlanStage(expl, "COLLSCAN")); - assert.eq(5, getPlanStage(expl, "COLLSCAN").minRecord); - assert.eq(5, getPlanStage(expl, "COLLSCAN").maxRecord); + assert(getPlanStage(expl, "CLUSTERED_IXSCAN")); + assert.eq(5, getPlanStage(expl, "CLUSTERED_IXSCAN").minRecord); + assert.eq(5, getPlanStage(expl, "CLUSTERED_IXSCAN").maxRecord); assert.eq(1, expl.executionStats.executionStages.nReturned); // Expect nReturned + 1 documents examined by design - additional cursor 'next' beyond @@ -48,10 +48,10 @@ const testClusteredCollectionBoundedScan = function(coll, clusterKey) { verbosity: "executionStats" })); - assert(getPlanStage(expl, "COLLSCAN")); - assert(getPlanStage(expl, "COLLSCAN").hasOwnProperty("maxRecord")); - assert(!getPlanStage(expl, "COLLSCAN").hasOwnProperty("minRecord")); - assert.eq(10, getPlanStage(expl, "COLLSCAN").maxRecord); + assert(getPlanStage(expl, "CLUSTERED_IXSCAN")); + assert(getPlanStage(expl, "CLUSTERED_IXSCAN").hasOwnProperty("maxRecord")); + assert(!getPlanStage(expl, "CLUSTERED_IXSCAN").hasOwnProperty("minRecord")); + assert.eq(10, getPlanStage(expl, "CLUSTERED_IXSCAN").maxRecord); assert.eq(expectedNReturned, expl.executionStats.executionStages.nReturned); assert.eq(expectedDocsExamined, expl.executionStats.executionStages.docsExamined); @@ -64,10 +64,10 @@ const testClusteredCollectionBoundedScan = function(coll, clusterKey) { verbosity: "executionStats" })); - assert(getPlanStage(expl, "COLLSCAN")); - assert(!getPlanStage(expl, "COLLSCAN").hasOwnProperty("maxRecord")); - assert(getPlanStage(expl, "COLLSCAN").hasOwnProperty("minRecord")); - assert.eq(89, getPlanStage(expl, "COLLSCAN").minRecord); + assert(getPlanStage(expl, "CLUSTERED_IXSCAN")); + assert(!getPlanStage(expl, "CLUSTERED_IXSCAN").hasOwnProperty("maxRecord")); + assert(getPlanStage(expl, "CLUSTERED_IXSCAN").hasOwnProperty("minRecord")); + assert.eq(89, getPlanStage(expl, "CLUSTERED_IXSCAN").minRecord); assert.eq(expectedNReturned, expl.executionStats.executionStages.nReturned); assert.eq(expectedDocsExamined, expl.executionStats.executionStages.docsExamined); @@ -83,11 +83,11 @@ const testClusteredCollectionBoundedScan = function(coll, clusterKey) { verbosity: "executionStats" })); - assert(getPlanStage(expl, "COLLSCAN")); - assert(getPlanStage(expl, "COLLSCAN").hasOwnProperty("maxRecord")); - assert(getPlanStage(expl, "COLLSCAN").hasOwnProperty("minRecord")); - assert.eq(minVal, getPlanStage(expl, "COLLSCAN").minRecord); - assert.eq(maxVal, getPlanStage(expl, "COLLSCAN").maxRecord); + assert(getPlanStage(expl, "CLUSTERED_IXSCAN")); + assert(getPlanStage(expl, "CLUSTERED_IXSCAN").hasOwnProperty("maxRecord")); + assert(getPlanStage(expl, "CLUSTERED_IXSCAN").hasOwnProperty("minRecord")); + assert.eq(minVal, getPlanStage(expl, "CLUSTERED_IXSCAN").minRecord); + assert.eq(maxVal, getPlanStage(expl, "CLUSTERED_IXSCAN").maxRecord); assert.eq(expectedNReturned, expl.executionStats.executionStages.nReturned); assert.eq(expectedDocsExamined, expl.executionStats.executionStages.docsExamined); diff --git a/jstests/libs/clustered_collections/clustered_collection_hint_common.js b/jstests/libs/clustered_collections/clustered_collection_hint_common.js index 6be6a4f4314..16123c75816 100644 --- a/jstests/libs/clustered_collections/clustered_collection_hint_common.js +++ b/jstests/libs/clustered_collections/clustered_collection_hint_common.js @@ -89,7 +89,7 @@ function testClusteredCollectionHint(coll, clusterKey, clusterKeyName) { hint: clusterKey, }, expectedWinningPlanStats: { - stage: "COLLSCAN", + stage: "CLUSTERED_IXSCAN", direction: "forward", minRecord: arbitraryDocId, maxRecord: arbitraryDocId @@ -104,7 +104,7 @@ function testClusteredCollectionHint(coll, clusterKey, clusterKeyName) { max: {[clusterKeyFieldName]: MaxKey} }, expectedWinningPlanStats: - {stage: "COLLSCAN", direction: "forward", minRecord: 101, maxRecord: MaxKey} + {stage: "CLUSTERED_IXSCAN", direction: "forward", minRecord: 101, maxRecord: MaxKey} }); validateClusteredCollectionHint(coll, { expectedNReturned: 0, @@ -115,7 +115,7 @@ function testClusteredCollectionHint(coll, clusterKey, clusterKeyName) { max: {[clusterKeyFieldName]: -2} }, expectedWinningPlanStats: - {stage: "COLLSCAN", direction: "forward", minRecord: MinKey, maxRecord: -2} + {stage: "CLUSTERED_IXSCAN", direction: "forward", minRecord: MinKey, maxRecord: -2} }); validateClusteredCollectionHint(coll, { expectedNReturned: 1, @@ -125,7 +125,7 @@ function testClusteredCollectionHint(coll, clusterKey, clusterKeyName) { hint: clusterKeyName, }, expectedWinningPlanStats: { - stage: "COLLSCAN", + stage: "CLUSTERED_IXSCAN", direction: "forward", minRecord: arbitraryDocId, maxRecord: arbitraryDocId @@ -139,7 +139,7 @@ function testClusteredCollectionHint(coll, clusterKey, clusterKeyName) { hint: clusterKey, }, expectedWinningPlanStats: - {stage: "COLLSCAN", direction: "forward", maxRecord: arbitraryDocId} + {stage: "CLUSTERED_IXSCAN", direction: "forward", maxRecord: arbitraryDocId} }); validateClusteredCollectionHint(coll, { expectedNReturned: batchSize - arbitraryDocId, @@ -149,7 +149,7 @@ function testClusteredCollectionHint(coll, clusterKey, clusterKeyName) { hint: clusterKey, }, expectedWinningPlanStats: - {stage: "COLLSCAN", direction: "forward", minRecord: arbitraryDocId} + {stage: "CLUSTERED_IXSCAN", direction: "forward", minRecord: arbitraryDocId} }); // Find with $natural hints. @@ -206,7 +206,7 @@ function testClusteredCollectionHint(coll, clusterKey, clusterKeyName) { updates: [{q: {[clusterKeyFieldName]: 3}, u: {$inc: {a: -2}}, hint: clusterKey}] }, expectedWinningPlanStats: - {stage: "COLLSCAN", direction: "forward", minRecord: 3, maxRecord: 3} + {stage: "CLUSTERED_IXSCAN", direction: "forward", minRecord: 3, maxRecord: 3} }); // Update with reverse $natural hint. @@ -218,7 +218,7 @@ function testClusteredCollectionHint(coll, clusterKey, clusterKeyName) { [{q: {[clusterKeyFieldName]: 80}, u: {$inc: {a: 80}}, hint: {$natural: -1}}] }, expectedWinningPlanStats: - {stage: "COLLSCAN", direction: "backward", minRecord: 80, maxRecord: 80} + {stage: "CLUSTERED_IXSCAN", direction: "backward", minRecord: 80, maxRecord: 80} }); // Update with hint on secondary index. @@ -239,7 +239,7 @@ function testClusteredCollectionHint(coll, clusterKey, clusterKeyName) { deletes: [{q: {[clusterKeyFieldName]: 2}, limit: 0, hint: clusterKey}] }, expectedWinningPlanStats: - {stage: "COLLSCAN", direction: "forward", minRecord: 2, maxRecord: 2} + {stage: "CLUSTERED_IXSCAN", direction: "forward", minRecord: 2, maxRecord: 2} }); // Delete reverse $natural hint. @@ -250,7 +250,7 @@ function testClusteredCollectionHint(coll, clusterKey, clusterKeyName) { deletes: [{q: {[clusterKeyFieldName]: 30}, limit: 0, hint: {$natural: -1}}] }, expectedWinningPlanStats: - {stage: "COLLSCAN", direction: "backward", minRecord: 30, maxRecord: 30} + {stage: "CLUSTERED_IXSCAN", direction: "backward", minRecord: 30, maxRecord: 30} }); // Delete with hint on standard index. diff --git a/src/mongo/db/exec/collection_scan.cpp b/src/mongo/db/exec/collection_scan.cpp index c6a4690080f..cb8e776eaec 100644 --- a/src/mongo/db/exec/collection_scan.cpp +++ b/src/mongo/db/exec/collection_scan.cpp @@ -51,8 +51,13 @@ namespace mongo { using std::unique_ptr; using std::vector; -// static -const char* CollectionScan::kStageType = "COLLSCAN"; +namespace { +const char* getStageName(const CollectionPtr& coll, const CollectionScanParams& params) { + return (!coll->ns().isOplog() && (params.minRecord || params.maxRecord)) ? "CLUSTERED_IXSCAN" + : "COLLSCAN"; +} +} // namespace + CollectionScan::CollectionScan(ExpressionContext* expCtx, const CollectionPtr& collection, @@ -60,7 +65,8 @@ CollectionScan::CollectionScan(ExpressionContext* expCtx, WorkingSet* workingSet, const MatchExpression* filter, bool relaxCappedConstraints) - : RequiresCollectionStage(kStageType, expCtx, collection, relaxCappedConstraints), + : RequiresCollectionStage( + getStageName(collection, params), expCtx, collection, relaxCappedConstraints), _workingSet(workingSet), _filter((filter && !filter->isTriviallyTrue()) ? filter : nullptr), _params(params) { diff --git a/src/mongo/db/exec/collection_scan.h b/src/mongo/db/exec/collection_scan.h index 69d71cc70b1..0ddb2f9e348 100644 --- a/src/mongo/db/exec/collection_scan.h +++ b/src/mongo/db/exec/collection_scan.h @@ -52,8 +52,6 @@ class OperationContext; */ class CollectionScan final : public RequiresCollectionStage { public: - static const char* kStageType; - CollectionScan(ExpressionContext* expCtx, const CollectionPtr& collection, const CollectionScanParams& params, |