diff options
author | Anton Korshunov <anton.korshunov@mongodb.com> | 2019-11-05 22:41:50 +0000 |
---|---|---|
committer | evergreen <evergreen@mongodb.com> | 2019-11-05 22:41:50 +0000 |
commit | 7c7bf229e2e1a911ad636e8d7827b2918215b357 (patch) | |
tree | 42f4a0a9b22c82ae8f73ca74462c0a0cd621a95e /src | |
parent | a22581e85b43b826535b180afaddac2b6146b44f (diff) | |
download | mongo-7c7bf229e2e1a911ad636e8d7827b2918215b357.tar.gz |
SERVER-43877 Remove raw projection BSON from projection stages
Diffstat (limited to 'src')
-rw-r--r-- | src/mongo/db/commands/find_and_modify.cpp | 16 | ||||
-rw-r--r-- | src/mongo/db/commands/find_cmd.cpp | 16 | ||||
-rw-r--r-- | src/mongo/db/commands/write_commands/write_commands.cpp | 14 | ||||
-rw-r--r-- | src/mongo/db/exec/projection.cpp | 67 | ||||
-rw-r--r-- | src/mongo/db/exec/projection.h | 29 | ||||
-rw-r--r-- | src/mongo/db/ops/delete.cpp | 7 | ||||
-rw-r--r-- | src/mongo/db/ops/update.cpp | 3 | ||||
-rw-r--r-- | src/mongo/db/ops/write_ops_exec.cpp | 14 | ||||
-rw-r--r-- | src/mongo/db/query/find.cpp | 16 | ||||
-rw-r--r-- | src/mongo/db/query/get_executor.cpp | 24 | ||||
-rw-r--r-- | src/mongo/db/query/get_executor.h | 18 | ||||
-rw-r--r-- | src/mongo/db/query/stage_builder.cpp | 10 | ||||
-rw-r--r-- | src/mongo/db/repl/storage_interface_impl.cpp | 8 |
13 files changed, 130 insertions, 112 deletions
diff --git a/src/mongo/db/commands/find_and_modify.cpp b/src/mongo/db/commands/find_and_modify.cpp index fbe9235c19e..7a0c7f038e1 100644 --- a/src/mongo/db/commands/find_and_modify.cpp +++ b/src/mongo/db/commands/find_and_modify.cpp @@ -267,8 +267,8 @@ public: css->checkShardVersionOrThrow(opCtx, autoColl.getCollection()); Collection* const collection = autoColl.getCollection(); - const auto exec = - uassertStatusOK(getExecutorDelete(opCtx, opDebug, collection, &parsedDelete)); + const auto exec = uassertStatusOK( + getExecutorDelete(opCtx, opDebug, collection, &parsedDelete, verbosity)); auto bodyBuilder = result->getBodyBuilder(); Explain::explainStages(exec.get(), collection, verbosity, BSONObj(), &bodyBuilder); @@ -292,8 +292,8 @@ public: css->checkShardVersionOrThrow(opCtx, autoColl.getCollection()); Collection* const collection = autoColl.getCollection(); - const auto exec = - uassertStatusOK(getExecutorUpdate(opCtx, opDebug, collection, &parsedUpdate)); + const auto exec = uassertStatusOK( + getExecutorUpdate(opCtx, opDebug, collection, &parsedUpdate, verbosity)); auto bodyBuilder = result->getBodyBuilder(); Explain::explainStages(exec.get(), collection, verbosity, BSONObj(), &bodyBuilder); @@ -381,8 +381,8 @@ public: Collection* const collection = autoColl.getCollection(); checkIfTransactionOnCappedColl(collection, inTransaction); - const auto exec = - uassertStatusOK(getExecutorDelete(opCtx, opDebug, collection, &parsedDelete)); + const auto exec = uassertStatusOK(getExecutorDelete( + opCtx, opDebug, collection, &parsedDelete, boost::none /* verbosity */)); { stdx::lock_guard<Client> lk(*opCtx->getClient()); @@ -487,8 +487,8 @@ public: checkIfTransactionOnCappedColl(collection, inTransaction); - const auto exec = - uassertStatusOK(getExecutorUpdate(opCtx, opDebug, collection, &parsedUpdate)); + const auto exec = uassertStatusOK(getExecutorUpdate( + opCtx, opDebug, collection, &parsedUpdate, boost::none /* verbosity */)); { stdx::lock_guard<Client> lk(*opCtx->getClient()); diff --git a/src/mongo/db/commands/find_cmd.cpp b/src/mongo/db/commands/find_cmd.cpp index 82f9dd07c96..56e65aad432 100644 --- a/src/mongo/db/commands/find_cmd.cpp +++ b/src/mongo/db/commands/find_cmd.cpp @@ -76,8 +76,10 @@ std::unique_ptr<QueryRequest> parseCmdObjectToQueryRequest(OperationContext* opC return qr; } -boost::intrusive_ptr<ExpressionContext> makeExpressionContext(OperationContext* opCtx, - const QueryRequest& queryRequest) { +boost::intrusive_ptr<ExpressionContext> makeExpressionContext( + OperationContext* opCtx, + const QueryRequest& queryRequest, + boost::optional<ExplainOptions::Verbosity> verbosity) { std::unique_ptr<CollatorInterface> collator; if (!queryRequest.getCollation().isEmpty()) { collator = uassertStatusOK(CollatorFactoryInterface::get(opCtx->getServiceContext()) @@ -100,9 +102,9 @@ boost::intrusive_ptr<ExpressionContext> makeExpressionContext(OperationContext* // sense to start initializing these fields for find operations as well. auto expCtx = make_intrusive<ExpressionContext>(opCtx, - boost::none, // explain - false, // fromMongos - false, // needsMerge + verbosity, + false, // fromMongos + false, // needsMerge queryRequest.allowDiskUse(), false, // bypassDocumentValidation queryRequest.nss(), @@ -227,7 +229,7 @@ public: // Finish the parsing step by using the QueryRequest to create a CanonicalQuery. const ExtensionsCallbackReal extensionsCallback(opCtx, &nss); - auto expCtx = makeExpressionContext(opCtx, *qr); + auto expCtx = makeExpressionContext(opCtx, *qr, verbosity); auto cq = uassertStatusOK( CanonicalQuery::canonicalize(opCtx, std::move(qr), @@ -425,7 +427,7 @@ public: // Finish the parsing step by using the QueryRequest to create a CanonicalQuery. const ExtensionsCallbackReal extensionsCallback(opCtx, &nss); - auto expCtx = makeExpressionContext(opCtx, *qr); + auto expCtx = makeExpressionContext(opCtx, *qr, boost::none /* verbosity */); auto cq = uassertStatusOK( CanonicalQuery::canonicalize(opCtx, std::move(qr), diff --git a/src/mongo/db/commands/write_commands/write_commands.cpp b/src/mongo/db/commands/write_commands/write_commands.cpp index 8d7339d1d80..4c9671b9e34 100644 --- a/src/mongo/db/commands/write_commands/write_commands.cpp +++ b/src/mongo/db/commands/write_commands/write_commands.cpp @@ -377,8 +377,11 @@ private: // info is more accurate. AutoGetCollection collection(opCtx, _batch.getNamespace(), MODE_IX); - auto exec = uassertStatusOK(getExecutorUpdate( - opCtx, &CurOp::get(opCtx)->debug(), collection.getCollection(), &parsedUpdate)); + auto exec = uassertStatusOK(getExecutorUpdate(opCtx, + &CurOp::get(opCtx)->debug(), + collection.getCollection(), + &parsedUpdate, + verbosity)); auto bodyBuilder = result->getBodyBuilder(); Explain::explainStages( exec.get(), collection.getCollection(), verbosity, BSONObj(), &bodyBuilder); @@ -451,8 +454,11 @@ private: AutoGetCollection collection(opCtx, _batch.getNamespace(), MODE_IX); // Explain the plan tree. - auto exec = uassertStatusOK(getExecutorDelete( - opCtx, &CurOp::get(opCtx)->debug(), collection.getCollection(), &parsedDelete)); + auto exec = uassertStatusOK(getExecutorDelete(opCtx, + &CurOp::get(opCtx)->debug(), + collection.getCollection(), + &parsedDelete, + verbosity)); auto bodyBuilder = result->getBodyBuilder(); Explain::explainStages( exec.get(), collection.getCollection(), verbosity, BSONObj(), &bodyBuilder); diff --git a/src/mongo/db/exec/projection.cpp b/src/mongo/db/exec/projection.cpp index d824df21a6c..514b90a78a4 100644 --- a/src/mongo/db/exec/projection.cpp +++ b/src/mongo/db/exec/projection.cpp @@ -45,9 +45,6 @@ #include "mongo/util/str.h" namespace mongo { - -static const char* kIdField = "_id"; - namespace { void transitionMemberToOwnedObj(Document&& doc, WorkingSetMember* member) { @@ -115,36 +112,14 @@ auto rehydrateIndexKey(const BSONObj& keyPattern, const BSONObj& dehydratedKey) } } // namespace -ProjectionStage::ProjectionStage(OperationContext* opCtx, +ProjectionStage::ProjectionStage(boost::intrusive_ptr<ExpressionContext> expCtx, const BSONObj& projObj, WorkingSet* ws, std::unique_ptr<PlanStage> child, const char* stageType) - : PlanStage(opCtx, std::move(child), stageType), _projObj(projObj), _ws(*ws) {} - -// static -void ProjectionStage::getSimpleInclusionFields(const BSONObj& projObj, FieldSet* includedFields) { - // The _id is included by default. - bool includeId = true; - - // Figure out what fields are in the projection. We could eventually do this using the - // Projection AST. - BSONObjIterator projObjIt(projObj); - while (projObjIt.more()) { - BSONElement elt = projObjIt.next(); - // Must deal with the _id case separately as there is an implicit _id: 1 in the - // projection. - if ((elt.fieldNameStringData() == kIdField) && !elt.trueValue()) { - includeId = false; - continue; - } - (*includedFields)[elt.fieldNameStringData()] = true; - } - - if (includeId) { - (*includedFields)[kIdField] = true; - } -} + : PlanStage{expCtx->opCtx, std::move(child), stageType}, + _projObj{expCtx->explain ? boost::make_optional(projObj.getOwned()) : boost::none}, + _ws{*ws} {} bool ProjectionStage::isEOF() { return child()->isEOF(); @@ -184,7 +159,7 @@ std::unique_ptr<PlanStageStats> ProjectionStage::getStats() { auto ret = std::make_unique<PlanStageStats>(_commonStats, stageType()); auto projStats = std::make_unique<ProjectionStats>(_specificStats); - projStats->projObj = _projObj; + projStats->projObj = _projObj.value_or(BSONObj{}); ret->specific = std::move(projStats); ret->children.emplace_back(child()->getStats()); @@ -196,7 +171,7 @@ ProjectionStageDefault::ProjectionStageDefault(boost::intrusive_ptr<ExpressionCo const projection_ast::Projection* projection, WorkingSet* ws, std::unique_ptr<PlanStage> child) - : ProjectionStage{expCtx->opCtx, projObj, ws, std::move(child), "PROJECTION_DEFAULT"}, + : ProjectionStage{expCtx, projObj, ws, std::move(child), "PROJECTION_DEFAULT"}, _wantRecordId{projection->metadataDeps()[DocumentMetadataFields::kRecordId]}, _projectType{projection->type()}, _executor{projection_executor::buildProjectionExecutor(expCtx, projection, {})} {} @@ -241,16 +216,15 @@ Status ProjectionStageDefault::transform(WorkingSetMember* member) const { return Status::OK(); } -ProjectionStageCovered::ProjectionStageCovered(OperationContext* opCtx, +ProjectionStageCovered::ProjectionStageCovered(boost::intrusive_ptr<ExpressionContext> expCtx, const BSONObj& projObj, + const projection_ast::Projection* projection, WorkingSet* ws, std::unique_ptr<PlanStage> child, const BSONObj& coveredKeyObj) - : ProjectionStage(opCtx, projObj, ws, std::move(child), "PROJECTION_COVERED"), - _coveredKeyObj(coveredKeyObj) { - invariant(projObjHasOwnedData()); - // Figure out what fields are in the projection. - getSimpleInclusionFields(_projObj, &_includedFields); + : ProjectionStage{expCtx, projObj, ws, std::move(child), "PROJECTION_COVERED"}, + _coveredKeyObj{coveredKeyObj} { + invariant(projection->isSimple()); // If we're pulling data out of one index we can pre-compute the indices of the fields // in the key that we pull data from and avoid looking up the field name each time. @@ -258,6 +232,8 @@ ProjectionStageCovered::ProjectionStageCovered(OperationContext* opCtx, // Sanity-check. invariant(_coveredKeyObj.isOwned()); + _includedFields = {projection->getRequiredFields().begin(), + projection->getRequiredFields().end()}; BSONObjIterator kpIt(_coveredKeyObj); while (kpIt.more()) { BSONElement elt = kpIt.next(); @@ -269,7 +245,7 @@ ProjectionStageCovered::ProjectionStageCovered(OperationContext* opCtx, _includeKey.push_back(false); } else { // If we are including this key field store its field name. - _keyFieldNames.push_back(fieldIt->first); + _keyFieldNames.push_back(*fieldIt); _includeKey.push_back(true); } } @@ -297,14 +273,15 @@ Status ProjectionStageCovered::transform(WorkingSetMember* member) const { return Status::OK(); } -ProjectionStageSimple::ProjectionStageSimple(OperationContext* opCtx, +ProjectionStageSimple::ProjectionStageSimple(boost::intrusive_ptr<ExpressionContext> expCtx, const BSONObj& projObj, + const projection_ast::Projection* projection, WorkingSet* ws, std::unique_ptr<PlanStage> child) - : ProjectionStage(opCtx, projObj, ws, std::move(child), "PROJECTION_SIMPLE") { - invariant(projObjHasOwnedData()); - // Figure out what fields are in the projection. - getSimpleInclusionFields(_projObj, &_includedFields); + : ProjectionStage{expCtx, projObj, ws, std::move(child), "PROJECTION_SIMPLE"} { + invariant(projection->isSimple()); + _includedFields = {projection->getRequiredFields().begin(), + projection->getRequiredFields().end()}; } Status ProjectionStageSimple::transform(WorkingSetMember* member) const { @@ -317,8 +294,8 @@ Status ProjectionStageSimple::transform(WorkingSetMember* member) const { // Look at every field in the source document and see if we're including it. auto objToProject = member->doc.value().toBson(); for (auto&& elt : objToProject) { - auto fieldIt = _includedFields.find(elt.fieldNameStringData()); - if (_includedFields.end() != fieldIt) { + if (auto fieldIt = _includedFields.find(elt.fieldNameStringData()); + _includedFields.end() != fieldIt) { bob.append(elt); } } diff --git a/src/mongo/db/exec/projection.h b/src/mongo/db/exec/projection.h index 5b368750cad..0866dbdd150 100644 --- a/src/mongo/db/exec/projection.h +++ b/src/mongo/db/exec/projection.h @@ -43,7 +43,7 @@ namespace mongo { */ class ProjectionStage : public PlanStage { protected: - ProjectionStage(OperationContext* opCtx, + ProjectionStage(boost::intrusive_ptr<ExpressionContext> expCtx, const BSONObj& projObj, WorkingSet* ws, std::unique_ptr<PlanStage> child, @@ -60,22 +60,11 @@ public: } protected: - using FieldSet = StringMap<bool>; // Value is unused. + using FieldSet = StringSet; - /** - * Given the projection spec for a simple inclusion projection, - * 'projObj', populates 'includedFields' with the set of field - * names to be included. - */ - static void getSimpleInclusionFields(const BSONObj& projObj, FieldSet* includedFields); - - bool projObjHasOwnedData() { - return _projObj.isOwned() && !_projObj.isEmpty(); - } - - // The projection object used by all projection implementations. We lack a ProjectionExpression - // or similar so we use a BSONObj. - BSONObj _projObj; + // The raw BSON projection used to populate projection stats. Optional, since it is required + // only in explain mode. + boost::optional<BSONObj> _projObj; private: /** @@ -128,8 +117,9 @@ public: /** * ProjectionNodeCovered should obtain a fast-path object through this constructor. */ - ProjectionStageCovered(OperationContext* opCtx, + ProjectionStageCovered(boost::intrusive_ptr<ExpressionContext> expCtx, const BSONObj& projObj, + const projection_ast::Projection* projection, WorkingSet* ws, std::unique_ptr<PlanStage> child, const BSONObj& coveredKeyObj); @@ -141,7 +131,7 @@ public: private: Status transform(WorkingSetMember* member) const final; - // Has the field names present in the simple projection. + // Field names present in the simple projection. FieldSet _includedFields; // This is the key pattern we're extracting covered data from. It is maintained here since @@ -166,8 +156,9 @@ public: /** * ProjectionNodeSimple should obtain a fast-path object through this constructor. */ - ProjectionStageSimple(OperationContext* opCtx, + ProjectionStageSimple(boost::intrusive_ptr<ExpressionContext> expCtx, const BSONObj& projObj, + const projection_ast::Projection* projection, WorkingSet* ws, std::unique_ptr<PlanStage> child); diff --git a/src/mongo/db/ops/delete.cpp b/src/mongo/db/ops/delete.cpp index 3a95b360a47..85b06c4e7db 100644 --- a/src/mongo/db/ops/delete.cpp +++ b/src/mongo/db/ops/delete.cpp @@ -56,8 +56,11 @@ long long deleteObjects(OperationContext* opCtx, ParsedDelete parsedDelete(opCtx, &request); uassertStatusOK(parsedDelete.parseRequest()); - auto exec = uassertStatusOK( - getExecutorDelete(opCtx, &CurOp::get(opCtx)->debug(), collection, &parsedDelete)); + auto exec = uassertStatusOK(getExecutorDelete(opCtx, + &CurOp::get(opCtx)->debug(), + collection, + &parsedDelete, + boost::none /* verbosity */)); uassertStatusOK(exec->executePlan()); diff --git a/src/mongo/db/ops/update.cpp b/src/mongo/db/ops/update.cpp index f6e0fcd3eaa..6f12b861cc4 100644 --- a/src/mongo/db/ops/update.cpp +++ b/src/mongo/db/ops/update.cpp @@ -97,7 +97,8 @@ UpdateResult update(OperationContext* opCtx, Database* db, const UpdateRequest& uassertStatusOK(parsedUpdate.parseRequest()); OpDebug* const nullOpDebug = nullptr; - auto exec = uassertStatusOK(getExecutorUpdate(opCtx, nullOpDebug, collection, &parsedUpdate)); + auto exec = uassertStatusOK(getExecutorUpdate( + opCtx, nullOpDebug, collection, &parsedUpdate, boost::none /* verbosity */)); uassertStatusOK(exec->executePlan()); diff --git a/src/mongo/db/ops/write_ops_exec.cpp b/src/mongo/db/ops/write_ops_exec.cpp index d640bbf8113..3f22f0fd379 100644 --- a/src/mongo/db/ops/write_ops_exec.cpp +++ b/src/mongo/db/ops/write_ops_exec.cpp @@ -636,8 +636,11 @@ static SingleWriteResult performSingleUpdateOp(OperationContext* opCtx, assertCanWrite_inlock(opCtx, ns, collection->getCollection()); - auto exec = uassertStatusOK( - getExecutorUpdate(opCtx, &curOp.debug(), collection->getCollection(), &parsedUpdate)); + auto exec = uassertStatusOK(getExecutorUpdate(opCtx, + &curOp.debug(), + collection->getCollection(), + &parsedUpdate, + boost::none /* verbosity */)); { stdx::lock_guard<Client> lk(*opCtx->getClient()); @@ -865,8 +868,11 @@ static SingleWriteResult performSingleDeleteOp(OperationContext* opCtx, CurOpFailpointHelpers::waitWhileFailPointEnabled( &hangWithLockDuringBatchRemove, opCtx, "hangWithLockDuringBatchRemove"); - auto exec = uassertStatusOK( - getExecutorDelete(opCtx, &curOp.debug(), collection.getCollection(), &parsedDelete)); + auto exec = uassertStatusOK(getExecutorDelete(opCtx, + &curOp.debug(), + collection.getCollection(), + &parsedDelete, + boost::none /* verbosity */)); { stdx::lock_guard<Client> lk(*opCtx->getClient()); diff --git a/src/mongo/db/query/find.cpp b/src/mongo/db/query/find.cpp index 12b5f4073ee..0d903bd3086 100644 --- a/src/mongo/db/query/find.cpp +++ b/src/mongo/db/query/find.cpp @@ -591,7 +591,8 @@ std::string runQuery(OperationContext* opCtx, beginQueryOp(opCtx, nss, upconvertedQuery, q.ntoreturn, q.ntoskip); // Parse the qm into a CanonicalQuery. - const boost::intrusive_ptr<ExpressionContext> expCtx; + const boost::intrusive_ptr<ExpressionContext> expCtx = + make_intrusive<ExpressionContext>(opCtx, nullptr /* collator */); auto cq = uassertStatusOKWithContext( CanonicalQuery::canonicalize(opCtx, q, @@ -607,10 +608,9 @@ std::string runQuery(OperationContext* opCtx, // Parse, canonicalize, plan, transcribe, and get a plan executor. AutoGetCollectionForReadCommand ctx(opCtx, nss, AutoGetCollection::ViewMode::kViewsForbidden); Collection* const collection = ctx.getCollection(); + const QueryRequest& qr = cq->getQueryRequest(); { - const QueryRequest& qr = cq->getQueryRequest(); - // Allow the query to run on secondaries if the read preference permits it. If no read // preference was specified, allow the query to run iff slaveOk has been set. const bool slaveOK = qr.hasReadPref() @@ -622,10 +622,10 @@ std::string runQuery(OperationContext* opCtx, } // Get the execution plan for the query. + constexpr auto verbosity = ExplainOptions::Verbosity::kExecAllPlans; + expCtx->explain = qr.isExplain() ? boost::make_optional(verbosity) : boost::none; auto exec = uassertStatusOK(getExecutorLegacyFind(opCtx, collection, std::move(cq))); - const QueryRequest& qr = exec->getCanonicalQuery()->getQueryRequest(); - // If it's actually an explain, do the explain and return rather than falling through // to the normal query execution loop. if (qr.isExplain()) { @@ -633,11 +633,7 @@ std::string runQuery(OperationContext* opCtx, bb.skip(sizeof(QueryResult::Value)); BSONObjBuilder explainBob; - Explain::explainStages(exec.get(), - collection, - ExplainOptions::Verbosity::kExecAllPlans, - BSONObj(), - &explainBob); + Explain::explainStages(exec.get(), collection, verbosity, BSONObj(), &explainBob); // Add the resulting object to the return buffer. BSONObj explainObj = explainBob.obj(); diff --git a/src/mongo/db/query/get_executor.cpp b/src/mongo/db/query/get_executor.cpp index 8f0623def21..b236de9e8ea 100644 --- a/src/mongo/db/query/get_executor.cpp +++ b/src/mongo/db/query/get_executor.cpp @@ -427,7 +427,11 @@ StatusWith<PrepareExecutionResult> prepareExecution(OperationContext* opCtx, std::move(root)); } else { root = std::make_unique<ProjectionStageSimple>( - opCtx, canonicalQuery->getQueryRequest().getProj(), ws, std::move(root)); + canonicalQuery->getExpCtx(), + canonicalQuery->getQueryRequest().getProj(), + canonicalQuery->getProj(), + ws, + std::move(root)); } } @@ -686,7 +690,11 @@ StatusWith<unique_ptr<PlanStage>> applyProjection(OperationContext* opCtx, // StatusWith<unique_ptr<PlanExecutor, PlanExecutor::Deleter>> getExecutorDelete( - OperationContext* opCtx, OpDebug* opDebug, Collection* collection, ParsedDelete* parsedDelete) { + OperationContext* opCtx, + OpDebug* opDebug, + Collection* collection, + ParsedDelete* parsedDelete, + boost::optional<ExplainOptions::Verbosity> verbosity) { const DeleteRequest* request = parsedDelete->getRequest(); const NamespaceString& nss(request->getNamespaceString()); @@ -772,6 +780,9 @@ StatusWith<unique_ptr<PlanExecutor, PlanExecutor::Deleter>> getExecutorDelete( // This is the regular path for when we have a CanonicalQuery. unique_ptr<CanonicalQuery> cq(parsedDelete->releaseParsedQuery()); + // Transfer the explain verbosity level into the expression context. + cq->getExpCtx()->explain = verbosity; + const size_t defaultPlannerOptions = 0; StatusWith<PrepareExecutionResult> executionResult = prepareExecution(opCtx, collection, ws.get(), std::move(cq), defaultPlannerOptions); @@ -816,7 +827,11 @@ StatusWith<unique_ptr<PlanExecutor, PlanExecutor::Deleter>> getExecutorDelete( // StatusWith<unique_ptr<PlanExecutor, PlanExecutor::Deleter>> getExecutorUpdate( - OperationContext* opCtx, OpDebug* opDebug, Collection* collection, ParsedUpdate* parsedUpdate) { + OperationContext* opCtx, + OpDebug* opDebug, + Collection* collection, + ParsedUpdate* parsedUpdate, + boost::optional<ExplainOptions::Verbosity> verbosity) { const UpdateRequest* request = parsedUpdate->getRequest(); UpdateDriver* driver = parsedUpdate->getDriver(); @@ -913,6 +928,9 @@ StatusWith<unique_ptr<PlanExecutor, PlanExecutor::Deleter>> getExecutorUpdate( // This is the regular path for when we have a CanonicalQuery. unique_ptr<CanonicalQuery> cq(parsedUpdate->releaseParsedQuery()); + // Transfer the explain verbosity level into the expression context. + cq->getExpCtx()->explain = verbosity; + const size_t defaultPlannerOptions = 0; StatusWith<PrepareExecutionResult> executionResult = prepareExecution(opCtx, collection, ws.get(), std::move(cq), defaultPlannerOptions); diff --git a/src/mongo/db/query/get_executor.h b/src/mongo/db/query/get_executor.h index 51fd3b008af..99e1657c6a7 100644 --- a/src/mongo/db/query/get_executor.h +++ b/src/mongo/db/query/get_executor.h @@ -218,6 +218,9 @@ StatusWith<std::unique_ptr<PlanExecutor, PlanExecutor::Deleter>> getExecutorCoun * * 'opDebug' Optional argument. When not null, will be used to record operation statistics. * + * If the delete operation is executed in explain mode, the 'verbosity' parameter should be + * set to the requested verbosity level, or boost::none otherwise. + * * The returned PlanExecutor will used the YieldPolicy returned by parsedDelete->yieldPolicy(). * * Does not take ownership of its arguments. @@ -228,7 +231,11 @@ StatusWith<std::unique_ptr<PlanExecutor, PlanExecutor::Deleter>> getExecutorCoun * If the query cannot be executed, returns a Status indicating why. */ StatusWith<std::unique_ptr<PlanExecutor, PlanExecutor::Deleter>> getExecutorDelete( - OperationContext* opCtx, OpDebug* opDebug, Collection* collection, ParsedDelete* parsedDelete); + OperationContext* opCtx, + OpDebug* opDebug, + Collection* collection, + ParsedDelete* parsedDelete, + boost::optional<ExplainOptions::Verbosity> verbosity); /** * Get a PlanExecutor for an update operation. 'parsedUpdate' describes the query predicate @@ -238,6 +245,9 @@ StatusWith<std::unique_ptr<PlanExecutor, PlanExecutor::Deleter>> getExecutorDele * * 'opDebug' Optional argument. When not null, will be used to record operation statistics. * + * If the delete operation is executed in explain mode, the 'verbosity' parameter should be + * set to the requested verbosity level, or boost::none otherwise. + * * The returned PlanExecutor will used the YieldPolicy returned by parsedUpdate->yieldPolicy(). * * Does not take ownership of its arguments. @@ -248,5 +258,9 @@ StatusWith<std::unique_ptr<PlanExecutor, PlanExecutor::Deleter>> getExecutorDele * If the query cannot be executed, returns a Status indicating why. */ StatusWith<std::unique_ptr<PlanExecutor, PlanExecutor::Deleter>> getExecutorUpdate( - OperationContext* opCtx, OpDebug* opDebug, Collection* collection, ParsedUpdate* parsedUpdate); + OperationContext* opCtx, + OpDebug* opDebug, + Collection* collection, + ParsedUpdate* parsedUpdate, + boost::optional<ExplainOptions::Verbosity> verbosity); } // namespace mongo diff --git a/src/mongo/db/query/stage_builder.cpp b/src/mongo/db/query/stage_builder.cpp index d7afdebefbb..76b00bfd6b1 100644 --- a/src/mongo/db/query/stage_builder.cpp +++ b/src/mongo/db/query/stage_builder.cpp @@ -154,8 +154,9 @@ std::unique_ptr<PlanStage> buildStages(OperationContext* opCtx, case STAGE_PROJECTION_COVERED: { auto pn = static_cast<const ProjectionNodeCovered*>(root); auto childStage = buildStages(opCtx, collection, cq, qsol, pn->children[0], ws); - return std::make_unique<ProjectionStageCovered>(opCtx, + return std::make_unique<ProjectionStageCovered>(cq.getExpCtx(), cq.getQueryRequest().getProj(), + cq.getProj(), ws, std::move(childStage), pn->coveredKeyObj); @@ -163,8 +164,11 @@ std::unique_ptr<PlanStage> buildStages(OperationContext* opCtx, case STAGE_PROJECTION_SIMPLE: { auto pn = static_cast<const ProjectionNodeSimple*>(root); auto childStage = buildStages(opCtx, collection, cq, qsol, pn->children[0], ws); - return std::make_unique<ProjectionStageSimple>( - opCtx, cq.getQueryRequest().getProj(), ws, std::move(childStage)); + return std::make_unique<ProjectionStageSimple>(cq.getExpCtx(), + cq.getQueryRequest().getProj(), + cq.getProj(), + ws, + std::move(childStage)); } case STAGE_LIMIT: { const LimitNode* ln = static_cast<const LimitNode*>(root); diff --git a/src/mongo/db/repl/storage_interface_impl.cpp b/src/mongo/db/repl/storage_interface_impl.cpp index 79a05656b9d..0770b586e37 100644 --- a/src/mongo/db/repl/storage_interface_impl.cpp +++ b/src/mongo/db/repl/storage_interface_impl.cpp @@ -863,8 +863,8 @@ Status _updateWithQuery(OperationContext* opCtx, uassertStatusOK(opCtx->recoveryUnit()->setTimestamp(ts)); } - auto planExecutorResult = - mongo::getExecutorUpdate(opCtx, nullptr, collection, &parsedUpdate); + auto planExecutorResult = mongo::getExecutorUpdate( + opCtx, nullptr, collection, &parsedUpdate, boost::none /* verbosity */); if (!planExecutorResult.isOK()) { return planExecutorResult.getStatus(); } @@ -992,8 +992,8 @@ Status StorageInterfaceImpl::deleteByFilter(OperationContext* opCtx, } auto collection = collectionResult.getValue(); - auto planExecutorResult = - mongo::getExecutorDelete(opCtx, nullptr, collection, &parsedDelete); + auto planExecutorResult = mongo::getExecutorDelete( + opCtx, nullptr, collection, &parsedDelete, boost::none /* verbosity */); if (!planExecutorResult.isOK()) { return planExecutorResult.getStatus(); } |