From bae712c9891ad30c4fa9e1413efa4b3f3aa5c828 Mon Sep 17 00:00:00 2001 From: Ben Shteinfeld Date: Tue, 8 Nov 2022 21:40:31 +0000 Subject: SERVER-68847 Include query framework information in GetMore profiler entries --- jstests/noPassthrough/query_engine_stats.js | 72 +++++++++++++++---- src/mongo/db/commands/getmore_cmd.cpp | 2 + src/mongo/db/commands/run_aggregate.cpp | 7 +- src/mongo/db/curop.cpp | 54 ++++++++++---- src/mongo/db/curop.h | 13 +--- src/mongo/db/pipeline/document_source_cursor.cpp | 3 +- src/mongo/db/pipeline/document_source_cursor.h | 6 ++ src/mongo/db/pipeline/plan_executor_pipeline.cpp | 18 +++++ src/mongo/db/pipeline/plan_executor_pipeline.h | 2 + src/mongo/db/query/cqf_get_executor.cpp | 6 +- src/mongo/db/query/get_executor.cpp | 90 ++++++++++++------------ src/mongo/db/query/plan_executor.h | 24 +++++++ src/mongo/db/query/plan_executor_factory.cpp | 9 ++- src/mongo/db/query/plan_executor_factory.h | 3 +- src/mongo/db/query/plan_executor_impl.h | 4 ++ src/mongo/db/query/plan_executor_sbe.cpp | 6 +- src/mongo/db/query/plan_executor_sbe.h | 11 ++- src/mongo/db/stats/counters.h | 53 ++++++++------ 18 files changed, 264 insertions(+), 119 deletions(-) diff --git a/jstests/noPassthrough/query_engine_stats.js b/jstests/noPassthrough/query_engine_stats.js index 0913e2f8596..aa5b9f4af22 100644 --- a/jstests/noPassthrough/query_engine_stats.js +++ b/jstests/noPassthrough/query_engine_stats.js @@ -63,18 +63,12 @@ function verifySlowQueryLog(db, expectedComment, queryFramework) { // Ensure the profile filter contains the correct information about the queryFramework used. function verifyProfiler(expectedComment, queryFramework) { - const profileEntryFilter = {ns: "query_engine_stats.collection"}; + const profileEntryFilter = { + ns: "query_engine_stats.collection", + "command.comment": expectedComment + }; const profileObj = getLatestProfilerEntry(db, profileEntryFilter); - try { - assert.eq(profileObj.command.comment, expectedComment); - if (queryFramework) { - assert.eq(profileObj.queryFramework, queryFramework); - } - } catch (e) { - print('failed to find [{ "queryFramework" : "' + queryFramework + '", { "comment" : "' + - expectedComment + '"} }] in the latest profiler entry.'); - throw (e); - } + assert.eq(profileObj.queryFramework, queryFramework); } // Create an object with the correct queryFramework counter values after the specified type of @@ -155,9 +149,25 @@ verifySlowQueryLog(db, queryComment, framework.find.classic); compareQueryEngineCounters(expectedCounters); verifyProfiler(queryComment, framework.find.classic); +// Find with getMore. +queryComment = "findClassicGetMore"; +let cursor = coll.find({a: {$gt: 2}}).comment(queryComment).batchSize(1); +cursor.next(); // initial query +verifyProfiler(queryComment, framework.find.classic); +cursor.next(); // getMore performed +verifyProfiler(queryComment, framework.find.classic); + +// Aggregation with getMore. +queryComment = "aggClassicGetMore"; +cursor = coll.aggregate([{$match: {a: {$gt: 2}}}], {comment: queryComment, batchSize: 1}); +cursor.next(); // initial query +verifyProfiler(queryComment, framework.find.classic); +cursor.next(); // getMore performed +verifyProfiler(queryComment, framework.find.classic); + // Turn SBE on. assert.commandWorked( - db.adminCommand({setParameter: 1, internalQueryFrameworkControl: "tryBonsai"})); + db.adminCommand({setParameter: 1, internalQueryFrameworkControl: "trySbeEngine"})); // Run a find command. expectedCounters = generateExpectedCounters(framework.find.sbe); @@ -191,6 +201,28 @@ verifySlowQueryLog(db, queryComment, framework.find.sbe); compareQueryEngineCounters(expectedCounters); verifyProfiler(queryComment, framework.find.sbe); +// SBE find with getMore. +queryComment = "findSBEGetMore"; +cursor = coll.find({a: {$gt: 2}}).comment(queryComment).batchSize(1); +cursor.next(); // initial query +verifyProfiler(queryComment, framework.find.sbe); +cursor.next(); // getMore performed +verifyProfiler(queryComment, framework.find.sbe); + +// SBE aggregation with getMore. +queryComment = "aggSBEGetMore"; +cursor = coll.aggregate( + [ + {$_internalInhibitOptimization: {}}, + {$group: {_id: "$a", acc: {$sum: "$b"}}}, + {$match: {acc: {$gt: 0}}} + ], + {comment: queryComment, batchSize: 1}); +cursor.next(); // initial query +verifyProfiler(queryComment, framework.find.sbe); +cursor.next(); // getMore performed +verifyProfiler(queryComment, framework.find.sbe); + MongoRunner.stopMongod(conn); conn = MongoRunner.runMongod({restart: conn, setParameter: 'featureFlagCommonQueryFramework=1'}); @@ -228,5 +260,21 @@ verifySlowQueryLog(db, queryComment, framework.find.sbe); compareQueryEngineCounters(expectedCounters); verifyProfiler(queryComment, framework.find.sbe); +// CQF find with getMore. +queryComment = "findCQFGetMore"; +cursor = coll.find({a: {$gt: 2}}).comment(queryComment).batchSize(1); +cursor.next(); // initial query +verifyProfiler(queryComment, "cqf"); +cursor.next(); // getMore performed +verifyProfiler(queryComment, "cqf"); + +// CQF aggregation with getMore. +queryComment = "aggCQFGetMore"; +cursor = coll.aggregate([{$match: {a: {$gt: 2}}}], {comment: queryComment, batchSize: 1}); +cursor.next(); // initial query +verifyProfiler(queryComment, "cqf"); +cursor.next(); // getMore performed +verifyProfiler(queryComment, "cqf"); + MongoRunner.stopMongod(conn); })(); diff --git a/src/mongo/db/commands/getmore_cmd.cpp b/src/mongo/db/commands/getmore_cmd.cpp index 09aa73cc315..02b5739397c 100644 --- a/src/mongo/db/commands/getmore_cmd.cpp +++ b/src/mongo/db/commands/getmore_cmd.cpp @@ -572,6 +572,8 @@ public: curOp->setOriginatingCommand_inlock(originatingCommand); } + curOp->debug().queryFramework = exec->getQueryFramework(); + // Update the genericCursor stored in curOp with the new cursor stats. curOp->setGenericCursor_inlock(cursorPin->toGenericCursor()); } diff --git a/src/mongo/db/commands/run_aggregate.cpp b/src/mongo/db/commands/run_aggregate.cpp index efca157417f..5a4b171d0b9 100644 --- a/src/mongo/db/commands/run_aggregate.cpp +++ b/src/mongo/db/commands/run_aggregate.cpp @@ -608,9 +608,6 @@ std::vector> createLegacyEx request, hasGeoNearStage, liteParsedPipeline.hasChangeStream())) { - // Mark that this query does not use DocumentSource. - curOp->debug().documentSourceUsed = false; - // This pipeline is currently empty, but once completed it will have only one source, // which is a DocumentSourceCursor. Instead of creating a whole pipeline to do nothing // more than forward the results of its cursor document source, we can use the @@ -618,9 +615,6 @@ std::vector> createLegacyEx // have gotten from find command. execs.emplace_back(std::move(attachExecutorCallback.second)); } else { - // Mark that this query uses DocumentSource. - curOp->debug().documentSourceUsed = true; - getSearchHelpers(expCtx->opCtx->getServiceContext()) ->injectSearchShardFiltererIfNeeded(pipeline.get()); @@ -1017,6 +1011,7 @@ Status runAggregate(OperationContext* opCtx, auto planSummary = execs[0]->getPlanExplainer().getPlanSummary(); stdx::lock_guard lk(*opCtx->getClient()); curOp->setPlanSummary_inlock(std::move(planSummary)); + curOp->debug().queryFramework = execs[0]->getQueryFramework(); } } diff --git a/src/mongo/db/curop.cpp b/src/mongo/db/curop.cpp index 9e6b89c1af4..ea2e0456911 100644 --- a/src/mongo/db/curop.cpp +++ b/src/mongo/db/curop.cpp @@ -894,10 +894,20 @@ void OpDebug::report(OperationContext* opCtx, pAttrs->addDeepCopy("planCacheKey", zeroPaddedHex(*planCacheKey)); } - if (classicEngineUsed) { - pAttrs->add("queryFramework", classicEngineUsed.value() ? "classic" : "sbe"); - } else if (cqfUsed) { - pAttrs->add("queryFramework", "cqf"); + switch (queryFramework) { + case PlanExecutor::QueryFramework::kClassicOnly: + case PlanExecutor::QueryFramework::kClassicHybrid: + pAttrs->add("queryFramework", "classic"); + break; + case PlanExecutor::QueryFramework::kSBEOnly: + case PlanExecutor::QueryFramework::kSBEHybrid: + pAttrs->add("queryFramework", "sbe"); + break; + case PlanExecutor::QueryFramework::kCQF: + pAttrs->add("queryFramework", "cqf"); + break; + case PlanExecutor::QueryFramework::kUnknown: + break; } if (!errInfo.isOK()) { @@ -1070,10 +1080,20 @@ void OpDebug::append(OperationContext* opCtx, b.append("planCacheKey", zeroPaddedHex(*planCacheKey)); } - if (classicEngineUsed) { - b.append("queryFramework", classicEngineUsed.value() ? "classic" : "sbe"); - } else if (cqfUsed) { - b.append("queryFramework", "cqf"); + switch (queryFramework) { + case PlanExecutor::QueryFramework::kClassicOnly: + case PlanExecutor::QueryFramework::kClassicHybrid: + b.append("queryFramework", "classic"); + break; + case PlanExecutor::QueryFramework::kSBEOnly: + case PlanExecutor::QueryFramework::kSBEHybrid: + b.append("queryFramework", "sbe"); + break; + case PlanExecutor::QueryFramework::kCQF: + b.append("queryFramework", "cqf"); + break; + case PlanExecutor::QueryFramework::kUnknown: + break; } { @@ -1341,10 +1361,20 @@ std::function OpDebug::appendStaged(StringSet requ }); addIfNeeded("queryFramework", [](auto field, auto args, auto& b) { - if (args.op.classicEngineUsed) { - b.append("queryFramework", args.op.classicEngineUsed.value() ? "classic" : "sbe"); - } else if (args.op.cqfUsed) { - b.append("queryFramework", "cqf"); + switch (args.op.queryFramework) { + case PlanExecutor::QueryFramework::kClassicOnly: + case PlanExecutor::QueryFramework::kClassicHybrid: + b.append("queryFramework", "classic"); + break; + case PlanExecutor::QueryFramework::kSBEOnly: + case PlanExecutor::QueryFramework::kSBEHybrid: + b.append("queryFramework", "sbe"); + break; + case PlanExecutor::QueryFramework::kCQF: + b.append("queryFramework", "cqf"); + break; + case PlanExecutor::QueryFramework::kUnknown: + break; } }); diff --git a/src/mongo/db/curop.h b/src/mongo/db/curop.h index 9f83bd92cf1..c4cfcbcbb42 100644 --- a/src/mongo/db/curop.h +++ b/src/mongo/db/curop.h @@ -266,17 +266,8 @@ public: // The hash of the query's "stable" key. This represents the query's shape. boost::optional queryHash; - // Has a value if this operation is a query. True if the execution tree for the find part of the - // query was built exclusively using the classic query engine, false if any part was built using - // SBE. - boost::optional classicEngineUsed; - - // Has a value if this operation is an aggregation query. True if `DocumentSources` were - // involved in the execution tree for this query, false if they were not. - boost::optional documentSourceUsed; - - // Indicates whether this operation used the common query framework (CQF). - bool cqfUsed{false}; + // The query framework that this operation used. Will be unknown for non query operations. + PlanExecutor::QueryFramework queryFramework{PlanExecutor::QueryFramework::kUnknown}; // Tracks the amount of indexed loop joins in a pushed down lookup stage. int indexedLoopJoin{0}; diff --git a/src/mongo/db/pipeline/document_source_cursor.cpp b/src/mongo/db/pipeline/document_source_cursor.cpp index 81e023837b9..6c59043a7ed 100644 --- a/src/mongo/db/pipeline/document_source_cursor.cpp +++ b/src/mongo/db/pipeline/document_source_cursor.cpp @@ -315,7 +315,8 @@ DocumentSourceCursor::DocumentSourceCursor( : DocumentSource(kStageName, pCtx), _currentBatch(cursorType), _exec(std::move(exec)), - _trackOplogTS(trackOplogTimestamp) { + _trackOplogTS(trackOplogTimestamp), + _queryFramework(_exec->getQueryFramework()) { // It is illegal for both 'kEmptyDocuments' and 'trackOplogTimestamp' to be set. invariant(!(cursorType == CursorType::kEmptyDocuments && trackOplogTimestamp)); diff --git a/src/mongo/db/pipeline/document_source_cursor.h b/src/mongo/db/pipeline/document_source_cursor.h index d3f61cbee7d..0fd9428069a 100644 --- a/src/mongo/db/pipeline/document_source_cursor.h +++ b/src/mongo/db/pipeline/document_source_cursor.h @@ -126,6 +126,10 @@ public: return _exec->getPlanExplainer().getVersion(); } + PlanExecutor::QueryFramework getQueryFramework() const { + return _queryFramework; + } + BSONObj serializeToBSONForDebug() const final { // Feel free to add any useful information here. For now this has not been useful for // debugging so is left empty. @@ -271,6 +275,8 @@ private: // Specific stats for $cursor stage. DocumentSourceCursorStats _stats; + + PlanExecutor::QueryFramework _queryFramework; }; } // namespace mongo diff --git a/src/mongo/db/pipeline/plan_executor_pipeline.cpp b/src/mongo/db/pipeline/plan_executor_pipeline.cpp index 0b26a7db813..a41b1b1ab73 100644 --- a/src/mongo/db/pipeline/plan_executor_pipeline.cpp +++ b/src/mongo/db/pipeline/plan_executor_pipeline.cpp @@ -252,4 +252,22 @@ void PlanExecutorPipeline::markAsKilled(Status killStatus) { } } +PlanExecutor::QueryFramework PlanExecutorPipeline::getQueryFramework() const { + // If this executor has a $cursor source at the front, use the query framework of that executor + // backing the cursor stage in order to determine whether the current pipeline is a hybrid plan. + if (auto cursor = dynamic_cast(_pipeline->peekFront())) { + switch (cursor->getQueryFramework()) { + case PlanExecutor::QueryFramework::kClassicOnly: + return PlanExecutor::QueryFramework::kClassicHybrid; + case PlanExecutor::QueryFramework::kSBEOnly: + return PlanExecutor::QueryFramework::kSBEHybrid; + default: + MONGO_UNREACHABLE_TASSERT(6884701); + } + } + // If this executor doesn't have a $cursor source, then return classicOnly as it cannot be a + // hybrid plan. + return PlanExecutor::QueryFramework::kClassicOnly; +} + } // namespace mongo diff --git a/src/mongo/db/pipeline/plan_executor_pipeline.h b/src/mongo/db/pipeline/plan_executor_pipeline.h index ce0b840f3c9..cfc1a9052c3 100644 --- a/src/mongo/db/pipeline/plan_executor_pipeline.h +++ b/src/mongo/db/pipeline/plan_executor_pipeline.h @@ -171,6 +171,8 @@ public: return _pipeline->getTypeString(); } + PlanExecutor::QueryFramework getQueryFramework() const override final; + private: /** * Obtains the next document from the underlying Pipeline, and does change streams-related diff --git a/src/mongo/db/query/cqf_get_executor.cpp b/src/mongo/db/query/cqf_get_executor.cpp index cc1c42bc3af..0ca8ef9405a 100644 --- a/src/mongo/db/query/cqf_get_executor.cpp +++ b/src/mongo/db/query/cqf_get_executor.cpp @@ -364,7 +364,8 @@ static std::unique_ptr optimizeAndCreateExe QueryPlannerParams::Options::DEFAULT, nss, std::move(yieldPolicy), - false /*isFromPlanCache*/)); + false /*isFromPlanCache*/, + true /* generatedByBonsai */)); return planExec; } @@ -657,9 +658,6 @@ std::unique_ptr getSBEExecutorViaCascadesOp validateCommandOptions(canonicalQuery.get(), collection, indexHint, involvedCollections); - auto curOp = CurOp::get(opCtx); - curOp->debug().cqfUsed = true; - const bool requireRID = canonicalQuery ? canonicalQuery->getForceGenerateRecordId() : false; const bool collectionExists = collection != nullptr; const std::string uuidStr = collectionExists ? collection->uuid().toString() : ""; diff --git a/src/mongo/db/query/get_executor.cpp b/src/mongo/db/query/get_executor.cpp index 2325df018e2..d36bb993a33 100644 --- a/src/mongo/db/query/get_executor.cpp +++ b/src/mongo/db/query/get_executor.cpp @@ -1171,11 +1171,6 @@ StatusWith> getClassicExecu std::unique_ptr canonicalQuery, PlanYieldPolicy::YieldPolicy yieldPolicy, const QueryPlannerParams& plannerParams) { - // Mark that this query uses the classic engine, unless this has already been set. - OpDebug& opDebug = CurOp::get(opCtx)->debug(); - if (!opDebug.classicEngineUsed) { - opDebug.classicEngineUsed = true; - } auto ws = std::make_unique(); ClassicPrepareExecutionHelper helper{ opCtx, collection, ws.get(), canonicalQuery.get(), nullptr, plannerParams}; @@ -1283,9 +1278,6 @@ StatusWith> getSlotBasedExe // Now that we know what executor we are going to use, fill in some opDebug information, unless // it has already been filled by an outer pipeline. OpDebug& opDebug = CurOp::get(opCtx)->debug(); - if (!opDebug.classicEngineUsed) { - opDebug.classicEngineUsed = false; - } const auto& mainColl = collections.getMainCollection(); if (mainColl) { auto planCacheKey = plan_cache_key_factory::make(*cq, collections); @@ -1375,7 +1367,8 @@ StatusWith> getSlotBasedExe plannerParams.options, std::move(nss), std::move(yieldPolicy), - planningResult->isRecoveredFromPlanCache()); + planningResult->isRecoveredFromPlanCache(), + false /* generatedByBonsai */); } /** @@ -1472,43 +1465,52 @@ StatusWith> getExecutor( std::function extractAndAttachPipelineStages, PlanYieldPolicy::YieldPolicy yieldPolicy, const QueryPlannerParams& plannerParams) { - invariant(canonicalQuery); - const auto& mainColl = collections.getMainCollection(); - canonicalQuery->setSbeCompatible( - isQuerySbeCompatible(&mainColl, canonicalQuery.get(), plannerParams.options)); - - if (isEligibleForBonsai(*canonicalQuery, opCtx, mainColl)) { - return getSBEExecutorViaCascadesOptimizer(mainColl, std::move(canonicalQuery)); - } - - // Use SBE if 'canonicalQuery' is SBE compatible. - if (!canonicalQuery->getForceClassicEngine() && canonicalQuery->isSbeCompatible()) { - auto statusWithExecutor = attemptToGetSlotBasedExecutor(opCtx, - collections, - std::move(canonicalQuery), - extractAndAttachPipelineStages, - yieldPolicy, - plannerParams); - if (!statusWithExecutor.isOK()) { - return statusWithExecutor.getStatus(); - } - auto& maybeExecutor = statusWithExecutor.getValue(); - if (stdx::holds_alternative>( - maybeExecutor)) { - return std::move( - stdx::get>(maybeExecutor)); - } else { - // The query is not eligible for SBE execution - reclaim the canonical query and fall - // back to classic. - tassert(7087103, - "return value must contain canonical query if not executor", - stdx::holds_alternative>(maybeExecutor)); - canonicalQuery = std::move(stdx::get>(maybeExecutor)); + auto exec = [&]() { + invariant(canonicalQuery); + const auto& mainColl = collections.getMainCollection(); + canonicalQuery->setSbeCompatible( + isQuerySbeCompatible(&mainColl, canonicalQuery.get(), plannerParams.options)); + + if (isEligibleForBonsai(*canonicalQuery, opCtx, mainColl)) { + return StatusWith>( + getSBEExecutorViaCascadesOptimizer(mainColl, std::move(canonicalQuery))); + } + + // Use SBE if 'canonicalQuery' is SBE compatible. + if (!canonicalQuery->getForceClassicEngine() && canonicalQuery->isSbeCompatible()) { + auto statusWithExecutor = attemptToGetSlotBasedExecutor(opCtx, + collections, + std::move(canonicalQuery), + extractAndAttachPipelineStages, + yieldPolicy, + plannerParams); + if (!statusWithExecutor.isOK()) { + return StatusWith>( + statusWithExecutor.getStatus()); + } + auto& maybeExecutor = statusWithExecutor.getValue(); + if (stdx::holds_alternative>( + maybeExecutor)) { + return StatusWith>( + std::move(stdx::get>( + maybeExecutor))); + } else { + // The query is not eligible for SBE execution - reclaim the canonical query and + // fall back to classic. + tassert(7087103, + "return value must contain canonical query if not executor", + stdx::holds_alternative>(maybeExecutor)); + canonicalQuery = + std::move(stdx::get>(maybeExecutor)); + } } + return getClassicExecutor( + opCtx, mainColl, std::move(canonicalQuery), yieldPolicy, plannerParams); + }(); + if (exec.isOK()) { + CurOp::get(opCtx)->debug().queryFramework = exec.getValue()->getQueryFramework(); } - - return getClassicExecutor( - opCtx, mainColl, std::move(canonicalQuery), yieldPolicy, plannerParams); + return exec; } StatusWith> getExecutor( diff --git a/src/mongo/db/query/plan_executor.h b/src/mongo/db/query/plan_executor.h index a94e87648dd..f47f0e1a57b 100644 --- a/src/mongo/db/query/plan_executor.h +++ b/src/mongo/db/query/plan_executor.h @@ -384,6 +384,30 @@ public: virtual boost::optional getExecutorType() const { return boost::none; } + + /** + * Describes the query framework which an executor used. + */ + enum class QueryFramework { + // Null value. + kUnknown, + // The entirety of this plan was executed in the classic execution engine. + kClassicOnly, + // This plan was executed using classic document source and any find pushdown was executed + // in the classic execution engine. + kClassicHybrid, + // The entirety of this plan was exectued in SBE via stage builders. + kSBEOnly, + // A portion of this plan was executed in SBE via stage builders. + kSBEHybrid, + // The entirely of this plan was executed using CQF. Hybrid CQF plans are not possible. + kCQF + }; + + /** + * Returns the query framework that this executor used. + */ + virtual QueryFramework getQueryFramework() const = 0; }; } // namespace mongo diff --git a/src/mongo/db/query/plan_executor_factory.cpp b/src/mongo/db/query/plan_executor_factory.cpp index 1ff8d5660b8..fc2107e8164 100644 --- a/src/mongo/db/query/plan_executor_factory.cpp +++ b/src/mongo/db/query/plan_executor_factory.cpp @@ -130,7 +130,8 @@ StatusWith> make( size_t plannerOptions, NamespaceString nss, std::unique_ptr yieldPolicy, - bool planIsFromCache) { + bool planIsFromCache, + bool generatedByBonsai) { auto&& [rootStage, data] = root; LOGV2_DEBUG(4822860, @@ -153,7 +154,8 @@ StatusWith> make( plannerOptions & QueryPlannerParams::RETURN_OWNED_DATA, std::move(nss), false, - std::move(yieldPolicy)), + std::move(yieldPolicy), + generatedByBonsai), PlanExecutor::Deleter{opCtx}}}; } @@ -179,7 +181,8 @@ StatusWith> make( plannerOptions & QueryPlannerParams::RETURN_OWNED_DATA, std::move(nss), true, - std::move(yieldPolicy)), + std::move(yieldPolicy), + false), PlanExecutor::Deleter{opCtx}}}; } diff --git a/src/mongo/db/query/plan_executor_factory.h b/src/mongo/db/query/plan_executor_factory.h index be7ab263a88..da12d682392 100644 --- a/src/mongo/db/query/plan_executor_factory.h +++ b/src/mongo/db/query/plan_executor_factory.h @@ -119,7 +119,8 @@ StatusWith> make( size_t plannerOptions, NamespaceString nss, std::unique_ptr yieldPolicy, - bool isFromPlanCache); + bool isFromPlanCache, + bool generatedByBonsai); /** * Similar to the factory function above in that it also constructs an executor for the winning SBE diff --git a/src/mongo/db/query/plan_executor_impl.h b/src/mongo/db/query/plan_executor_impl.h index 5f6563bf7e4..6855e6b14e8 100644 --- a/src/mongo/db/query/plan_executor_impl.h +++ b/src/mongo/db/query/plan_executor_impl.h @@ -127,6 +127,10 @@ public: LockPolicy lockPolicy() const final; const PlanExplainer& getPlanExplainer() const final; + PlanExecutor::QueryFramework getQueryFramework() const override final { + return PlanExecutor::QueryFramework::kClassicOnly; + } + /** * Same as restoreState() but without the logic to retry if a WriteConflictException is thrown. * diff --git a/src/mongo/db/query/plan_executor_sbe.cpp b/src/mongo/db/query/plan_executor_sbe.cpp index bd62138da46..6327a6b8a10 100644 --- a/src/mongo/db/query/plan_executor_sbe.cpp +++ b/src/mongo/db/query/plan_executor_sbe.cpp @@ -54,7 +54,8 @@ PlanExecutorSBE::PlanExecutorSBE(OperationContext* opCtx, bool returnOwnedBson, NamespaceString nss, bool isOpen, - std::unique_ptr yieldPolicy) + std::unique_ptr yieldPolicy, + bool generatedByBonsai) : _state{isOpen ? State::kOpened : State::kClosed}, _opCtx(opCtx), _nss(std::move(nss)), @@ -64,7 +65,8 @@ PlanExecutorSBE::PlanExecutorSBE(OperationContext* opCtx, _solution{std::move(candidates.winner().solution)}, _stash{std::move(candidates.winner().results)}, _cq{std::move(cq)}, - _yieldPolicy(std::move(yieldPolicy)) { + _yieldPolicy(std::move(yieldPolicy)), + _generatedByBonsai(generatedByBonsai) { invariant(!_nss.isEmpty()); invariant(_root); diff --git a/src/mongo/db/query/plan_executor_sbe.h b/src/mongo/db/query/plan_executor_sbe.h index 71b894c9f60..1327dd2b455 100644 --- a/src/mongo/db/query/plan_executor_sbe.h +++ b/src/mongo/db/query/plan_executor_sbe.h @@ -50,7 +50,8 @@ public: bool returnOwnedBson, NamespaceString nss, bool isOpen, - std::unique_ptr yieldPolicy); + std::unique_ptr yieldPolicy, + bool generatedByBonsai); CanonicalQuery* getCanonicalQuery() const override { return _cq.get(); @@ -147,6 +148,11 @@ public: return _isSaveRecoveryUnitAcrossCommandsEnabled; } + PlanExecutor::QueryFramework getQueryFramework() const override final { + return _generatedByBonsai ? PlanExecutor::QueryFramework::kCQF + : PlanExecutor::QueryFramework::kSBEOnly; + } + private: template ExecState getNextImpl(ObjectType* out, RecordId* dlOut); @@ -205,6 +211,9 @@ private: bool _isDisposed{false}; bool _isSaveRecoveryUnitAcrossCommandsEnabled = false; + + // Indicates whether this executor was constructed via Bonsai/CQF. + bool _generatedByBonsai{false}; }; /** diff --git a/src/mongo/db/stats/counters.h b/src/mongo/db/stats/counters.h index 65b15958c59..d066202d375 100644 --- a/src/mongo/db/stats/counters.h +++ b/src/mongo/db/stats/counters.h @@ -323,31 +323,40 @@ public: auto& debug = curop->debug(); const BSONObj& cmdObj = curop->opDescription(); auto cmdName = cmdObj.firstElementFieldNameStringData(); - if (cmdName == "find" && debug.classicEngineUsed) { - if (debug.classicEngineUsed.get()) { - classicFindQueryCounter.increment(); - } else { - sbeFindQueryCounter.increment(); + + if (cmdName == "find") { + switch (debug.queryFramework) { + case PlanExecutor::QueryFramework::kClassicOnly: + classicFindQueryCounter.increment(); + break; + case PlanExecutor::QueryFramework::kSBEOnly: + sbeFindQueryCounter.increment(); + break; + case PlanExecutor::QueryFramework::kCQF: + cqfFindQueryCounter.increment(); + break; + default: + break; } - } else if (cmdName == "aggregate" && debug.classicEngineUsed && debug.documentSourceUsed) { - if (debug.classicEngineUsed.get()) { - if (debug.documentSourceUsed.get()) { - classicHybridAggregationCounter.increment(); - } else { + } else if (cmdName == "aggregate") { + switch (debug.queryFramework) { + case PlanExecutor::QueryFramework::kClassicOnly: classicOnlyAggregationCounter.increment(); - } - } else { - if (debug.documentSourceUsed.get()) { - sbeHybridAggregationCounter.increment(); - } else { + break; + case PlanExecutor::QueryFramework::kClassicHybrid: + classicHybridAggregationCounter.increment(); + break; + case PlanExecutor::QueryFramework::kSBEOnly: sbeOnlyAggregationCounter.increment(); - } - } - } else if (debug.cqfUsed) { - if (cmdName == "find") { - cqfFindQueryCounter.increment(); - } else { - cqfAggregationQueryCounter.increment(); + break; + case PlanExecutor::QueryFramework::kSBEHybrid: + sbeHybridAggregationCounter.increment(); + break; + case PlanExecutor::QueryFramework::kCQF: + cqfAggregationQueryCounter.increment(); + break; + case PlanExecutor::QueryFramework::kUnknown: + break; } } } -- cgit v1.2.1