Status FindCmd::explain(OperationContext* txn, const std::string& dbname, const BSONObj& cmdObj, ExplainCommon::Verbosity verbosity, BSONObjBuilder* out) const { const string fullns = parseNs(dbname, cmdObj); // Parse the command BSON to a LiteParsedQuery. LiteParsedQuery* rawLpq; bool isExplain = true; Status lpqStatus = LiteParsedQuery::make(fullns, cmdObj, isExplain, &rawLpq); if (!lpqStatus.isOK()) { return lpqStatus; } auto_ptr<LiteParsedQuery> lpq(rawLpq); const NamespaceString nss(fullns); // Finish the parsing step by using the LiteParsedQuery to create a CanonicalQuery. // This requires a lock on the collection in case we're parsing $where: where-specific // parsing code assumes we have a lock and creates execution machinery that requires it. CanonicalQuery* rawCq; WhereCallbackReal whereCallback(txn, nss.db()); Status canonStatus = CanonicalQuery::canonicalize(lpq.release(), &rawCq, whereCallback); if (!canonStatus.isOK()) { return canonStatus; } auto_ptr<CanonicalQuery> cq(rawCq); AutoGetCollectionForRead ctx(txn, nss); // The collection may be NULL. If so, getExecutor() should handle it by returning // an execution tree with an EOFStage. Collection* collection = ctx.getCollection(); // We have a parsed query. Time to get the execution plan for it. PlanExecutor* rawExec; Status execStatus = Status::OK(); if (cq->getParsed().getOptions().oplogReplay) { execStatus = getOplogStartHack(txn, collection, cq.release(), &rawExec); } else { size_t options = QueryPlannerParams::DEFAULT; if (shardingState.needCollectionMetadata(cq->getParsed().ns())) { options |= QueryPlannerParams::INCLUDE_SHARD_FILTER; } execStatus = getExecutor(txn, collection, cq.release(), &rawExec, options); } if (!execStatus.isOK()) { return execStatus; } scoped_ptr<PlanExecutor> exec(rawExec); exec->setYieldPolicy(PlanExecutor::YIELD_AUTO); // Got the execution tree. Explain it. return Explain::explainStages(exec.get(), verbosity, out); }
// static Status CanonicalQuery::canonicalize(const std::string& ns, const BSONObj& query, const BSONObj& sort, const BSONObj& proj, long long skip, long long limit, const BSONObj& hint, const BSONObj& minObj, const BSONObj& maxObj, bool snapshot, bool explain, CanonicalQuery** out, const MatchExpressionParser::WhereCallback& whereCallback) { LiteParsedQuery* lpqRaw; // Pass empty sort and projection. BSONObj emptyObj; Status parseStatus = LiteParsedQuery::make(ns, skip, limit, 0, query, proj, sort, hint, minObj, maxObj, snapshot, explain, &lpqRaw); if (!parseStatus.isOK()) { return parseStatus; } std::auto_ptr<LiteParsedQuery> lpq(lpqRaw); // Build a parse tree from the BSONObj in the parsed query. StatusWithMatchExpression swme = MatchExpressionParser::parse(lpq->getFilter(), whereCallback); if (!swme.isOK()) { return swme.getStatus(); } // Make the CQ we'll hopefully return. std::auto_ptr<CanonicalQuery> cq(new CanonicalQuery()); // Takes ownership of lpq and the MatchExpression* in swme. Status initStatus = cq->init(lpq.release(), whereCallback, swme.getValue()); if (!initStatus.isOK()) { return initStatus; } *out = cq.release(); return Status::OK(); }
Status ClusterFindCmd::explain(OperationContext* txn, const std::string& dbname, const BSONObj& cmdObj, ExplainCommon::Verbosity verbosity, BSONObjBuilder* out) const { const string fullns = parseNs(dbname, cmdObj); // Parse the command BSON to a LiteParsedQuery. LiteParsedQuery* rawLpq; bool isExplain = true; Status lpqStatus = LiteParsedQuery::make(fullns, cmdObj, isExplain, &rawLpq); if (!lpqStatus.isOK()) { return lpqStatus; } auto_ptr<LiteParsedQuery> lpq(rawLpq); BSONObjBuilder explainCmdBob; ClusterExplain::wrapAsExplain(cmdObj, verbosity, &explainCmdBob); // We will time how long it takes to run the commands on the shards. Timer timer; vector<Strategy::CommandResult> shardResults; STRATEGY->commandOp(dbname, explainCmdBob.obj(), lpq->getOptions().toInt(), fullns, lpq->getFilter(), &shardResults); long long millisElapsed = timer.millis(); const char* mongosStageName = ClusterExplain::getStageNameForReadOp(shardResults, cmdObj); return ClusterExplain::buildExplainResult(shardResults, mongosStageName, millisElapsed, out); }