long long runCount(OperationContext* txn, const string& ns, const BSONObj &cmd, string &err, int &errCode) { AutoGetCollectionForRead ctx(txn, ns); Collection* collection = ctx.getCollection(); if (NULL == collection) { err = "ns missing"; return -1; } const NamespaceString nss(ns); CountRequest request; CmdCount* countComm = static_cast<CmdCount*>(Command::findCommand("count")); Status parseStatus = countComm->parseRequest(nss.db().toString(), cmd, &request); if (!parseStatus.isOK()) { err = parseStatus.reason(); errCode = parseStatus.code(); return -1; } if (request.query.isEmpty()) { return applySkipLimit(collection->numRecords(txn), cmd); } PlanExecutor* rawExec; Status getExecStatus = getExecutorCount(txn, collection, request, PlanExecutor::YIELD_AUTO, &rawExec); if (!getExecStatus.isOK()) { err = getExecStatus.reason(); errCode = getExecStatus.code(); return -1; } scoped_ptr<PlanExecutor> exec(rawExec); // Store the plan summary string in CurOp. if (NULL != txn->getCurOp()) { txn->getCurOp()->debug().planSummary = Explain::getPlanSummary(exec.get()); } Status execPlanStatus = exec->executePlan(); if (!execPlanStatus.isOK()) { err = execPlanStatus.reason(); errCode = execPlanStatus.code(); return -2; } // Plan is done executing. We just need to pull the count out of the root stage. invariant(STAGE_COUNT == exec->getRootStage()->stageType()); CountStage* countStage = static_cast<CountStage*>(exec->getRootStage()); const CountStats* countStats = static_cast<const CountStats*>(countStage->getSpecificStats()); return countStats->nCounted; }
long long runCount( const char *ns, const BSONObj &cmd, string &err, int &errCode ) { // Lock 'ns'. Client::Context cx(ns); NamespaceDetails *d = nsdetails(ns); if (NULL == d) { err = "ns missing"; return -1; } BSONObj query = cmd.getObjectField("query"); long long count = 0; long long skip = cmd["skip"].numberLong(); long long limit = cmd["limit"].numberLong(); if (limit < 0) { limit = -limit; } // count of all objects if (query.isEmpty()) { return applySkipLimit(d->numRecords(), cmd); } CanonicalQuery* cq; // We pass -limit because a positive limit means 'batch size' but negative limit is a // hard limit. if (!CanonicalQuery::canonicalize(ns, query, skip, -limit, &cq).isOK()) { uasserted(17220, "could not canonicalize query " + query.toString()); return -2; } Runner* rawRunner; if (!getRunner(cq, &rawRunner).isOK()) { uasserted(17221, "could not get runner " + query.toString()); return -2; } auto_ptr<Runner> runner(rawRunner); try { const ScopedRunnerRegistration safety(runner.get()); runner->setYieldPolicy(Runner::YIELD_AUTO); Runner::RunnerState state; while (Runner::RUNNER_ADVANCED == (state = runner->getNext(NULL, NULL))) { ++count; } // Emulate old behavior and return the count even if the runner was killed. This // happens when the underlying collection is dropped. return count; } catch (const DBException &e) { err = e.toString(); errCode = e.getCode(); } catch (const std::exception &e) { err = e.what(); errCode = 0; } // Historically we have returned zero in many count assertion cases - see SERVER-2291. log() << "Count with ns: " << ns << " and query: " << query << " failed with exception: " << err << " code: " << errCode << endl; return -2; }
long long runCount( const string& ns, const BSONObj &cmd, string &err, int &errCode ) { // Lock 'ns'. Client::Context cx(ns); Collection* collection = cx.db()->getCollection(ns); if (NULL == collection) { err = "ns missing"; return -1; } BSONObj query = cmd.getObjectField("query"); const std::string hint = cmd.getStringField("hint"); const BSONObj hintObj = hint.empty() ? BSONObj() : BSON("$hint" << hint); // count of all objects if (query.isEmpty()) { return applySkipLimit(collection->numRecords(), cmd); } Runner* rawRunner; long long skip = cmd["skip"].numberLong(); long long limit = cmd["limit"].numberLong(); if (limit < 0) { limit = -limit; } uassertStatusOK(getRunnerCount(collection, query, hintObj, &rawRunner)); auto_ptr<Runner> runner(rawRunner); try { const ScopedRunnerRegistration safety(runner.get()); runner->setYieldPolicy(Runner::YIELD_AUTO); long long count = 0; Runner::RunnerState state; while (Runner::RUNNER_ADVANCED == (state = runner->getNext(NULL, NULL))) { if (skip > 0) { --skip; } else { ++count; // Fast-path. There's no point in iterating all over the runner if limit // is set. if (count >= limit && limit != 0) { break; } } } // Emulate old behavior and return the count even if the runner was killed. This // happens when the underlying collection is dropped. return count; } catch (const DBException &e) { err = e.toString(); errCode = e.getCode(); } catch (const std::exception &e) { err = e.what(); errCode = 0; } // Historically we have returned zero in many count assertion cases - see SERVER-2291. log() << "Count with ns: " << ns << " and query: " << query << " failed with exception: " << err << " code: " << errCode << endl; return -2; }
long long runCount( const string& ns, const BSONObj &cmd, string &err, int &errCode ) { // Lock 'ns'. Client::Context cx(ns); Collection* collection = cx.db()->getCollection(ns); if (NULL == collection) { err = "ns missing"; return -1; } BSONObj query = cmd.getObjectField("query"); BSONObj hintObj; if (Object == cmd["hint"].type()) { hintObj = cmd["hint"].Obj(); } else if (String == cmd["hint"].type()) { const std::string hint = cmd.getStringField("hint"); hintObj = BSON("$hint" << hint); } // count of all objects if (query.isEmpty()) { return applySkipLimit(collection->numRecords(), cmd); } Runner* rawRunner; long long skip = cmd["skip"].numberLong(); long long limit = cmd["limit"].numberLong(); if (limit < 0) { limit = -limit; } uassertStatusOK(getRunnerCount(collection, query, hintObj, &rawRunner)); auto_ptr<Runner> runner(rawRunner); // Get a pointer to the current operation. We will try to copy the planSummary // there so that it appears in db.currentOp() and the slow query log. Client& client = cc(); CurOp* currentOp = client.curop(); // Have we copied the planSummary to 'currentOp' yet? bool gotPlanSummary = false; // Try to copy the plan summary to the 'currentOp'. if (!gotPlanSummary) { gotPlanSummary = setPlanSummary(runner.get(), currentOp); } try { const ScopedRunnerRegistration safety(runner.get()); runner->setYieldPolicy(Runner::YIELD_AUTO); long long count = 0; Runner::RunnerState state; while (Runner::RUNNER_ADVANCED == (state = runner->getNext(NULL, NULL))) { // Try to copy the plan summary to the 'currentOp'. We need to try again // here because we might not have chosen a plan until after the first // call to getNext(...). if (!gotPlanSummary) { gotPlanSummary = setPlanSummary(runner.get(), currentOp); } if (skip > 0) { --skip; } else { ++count; // Fast-path. There's no point in iterating all over the runner if limit // is set. if (count >= limit && limit != 0) { break; } } } // Try to copy the plan summary to the 'currentOp', if we haven't already. This // could happen if, for example, the count is 0. if (!gotPlanSummary) { gotPlanSummary = setPlanSummary(runner.get(), currentOp); } // Emulate old behavior and return the count even if the runner was killed. This // happens when the underlying collection is dropped. return count; } catch (const DBException &e) { err = e.toString(); errCode = e.getCode(); } catch (const std::exception &e) { err = e.what(); errCode = 0; } // Historically we have returned zero in many count assertion cases - see SERVER-2291. log() << "Count with ns: " << ns << " and query: " << query << " failed with exception: " << err << " code: " << errCode << endl; return -2; }
long long runCount(OperationContext* txn, const string& ns, const BSONObj &cmd, string &err, int &errCode) { // Lock 'ns'. Client::Context cx(txn, ns); Collection* collection = cx.db()->getCollection(txn, ns); const string& dbname = cx.db()->name(); if (NULL == collection) { err = "ns missing"; return -1; } CountRequest request; CmdCount* countComm = static_cast<CmdCount*>(Command::findCommand("count")); Status parseStatus = countComm->parseRequest(dbname, cmd, &request); if (!parseStatus.isOK()) { err = parseStatus.reason(); errCode = parseStatus.code(); return -1; } if (request.query.isEmpty()) { return applySkipLimit(collection->numRecords(txn), cmd); } PlanExecutor* rawExec; Status getExecStatus = getExecutorCount(txn, collection, request, &rawExec); if (!getExecStatus.isOK()) { err = getExecStatus.reason(); errCode = parseStatus.code(); return -1; } scoped_ptr<PlanExecutor> exec(rawExec); // Store the plan summary string in CurOp. if (NULL != txn->getCurOp()) { PlanSummaryStats stats; Explain::getSummaryStats(exec.get(), &stats); txn->getCurOp()->debug().planSummary = stats.summaryStr.c_str(); } const ScopedExecutorRegistration safety(exec.get()); Status execPlanStatus = exec->executePlan(); if (!execPlanStatus.isOK()) { err = execPlanStatus.reason(); errCode = execPlanStatus.code(); return -2; } // Plan is done executing. We just need to pull the count out of the root stage. invariant(STAGE_COUNT == exec->getRootStage()->stageType()); CountStage* countStage = static_cast<CountStage*>(exec->getRootStage()); const CountStats* countStats = static_cast<const CountStats*>(countStage->getSpecificStats()); return countStats->nCounted; }