bool PlanYieldPolicy::yield(RecordFetcher* fetcher) { invariant(_planYielding); invariant(allowedToYield()); _forceYield = false; OperationContext* opCtx = _planYielding->getOpCtx(); invariant(opCtx); invariant(!opCtx->lockState()->inAWriteUnitOfWork()); // Can't use MONGO_WRITE_CONFLICT_RETRY_LOOP_BEGIN/END since we need to call saveState // before reseting the transaction. for (int attempt = 1; true; attempt++) { try { // All YIELD_AUTO plans will get here eventually when the elapsed tracker triggers // that it's time to yield. Whether or not we will actually yield, we need to check // if this operation has been interrupted. Throws if the interrupt flag is set. if (_policy == PlanExecutor::YIELD_AUTO) { opCtx->checkForInterrupt(); } // No need to yield if the collection is NULL. if (NULL == _planYielding->collection()) { return true; } try { _planYielding->saveState(); } catch (const WriteConflictException& wce) { invariant(!"WriteConflictException not allowed in saveState"); } if (_policy == PlanExecutor::WRITE_CONFLICT_RETRY_ONLY) { // Just reset the snapshot. Leave all LockManager locks alone. opCtx->recoveryUnit()->commitAndRestart(); } else { // Release and reacquire locks. QueryYield::yieldAllLocks(opCtx, fetcher); } return _planYielding->restoreStateWithoutRetrying(opCtx); } catch (const WriteConflictException& wce) { opCtx->getCurOp()->debug().writeConflicts++; WriteConflictException::logAndBackoff(attempt, "plan execution restoreState", _planYielding->collection()->ns().ns()); // retry } } }
// static void Explain::explainStages(PlanExecutor* exec, ExplainCommon::Verbosity verbosity, BSONObjBuilder* out) { // // Step 1: run the stages as required by the verbosity level. // // Inspect the tree to see if there is a MultiPlanStage. MultiPlanStage* mps = getMultiPlanStage(exec->getRootStage()); // Get stats of the winning plan from the trial period, if the verbosity level // is high enough and there was a runoff between multiple plans. auto_ptr<PlanStageStats> winningStatsTrial; if (verbosity >= ExplainCommon::EXEC_ALL_PLANS && NULL != mps) { winningStatsTrial.reset(exec->getStats()); invariant(winningStatsTrial.get()); } // If we need execution stats, then run the plan in order to gather the stats. Status executePlanStatus = Status::OK(); if (verbosity >= ExplainCommon::EXEC_STATS) { executePlanStatus = exec->executePlan(); } // // Step 2: collect plan stats (which also give the structure of the plan tree). // // Get stats for the winning plan. scoped_ptr<PlanStageStats> winningStats(exec->getStats()); // Get stats for the rejected plans, if more than one plan was considered. OwnedPointerVector<PlanStageStats> allPlansStats; if (NULL != mps) { allPlansStats = mps->generateCandidateStats(); } // // Step 3: use the stats trees to produce explain BSON. // CanonicalQuery* query = exec->getCanonicalQuery(); if (verbosity >= ExplainCommon::QUERY_PLANNER) { generatePlannerInfo(query, winningStats.get(), allPlansStats.vector(), out); } if (verbosity >= ExplainCommon::EXEC_STATS) { BSONObjBuilder execBob(out->subobjStart("executionStats")); // If there is an execution error while running the query, the error is reported under // the "executionStats" section and the explain as a whole succeeds. execBob.append("executionSuccess", executePlanStatus.isOK()); if (!executePlanStatus.isOK()) { execBob.append("errorMessage", executePlanStatus.reason()); execBob.append("errorCode", executePlanStatus.code()); } // Generate exec stats BSON for the winning plan. OperationContext* opCtx = exec->getOpCtx(); long long totalTimeMillis = opCtx->getCurOp()->elapsedMillis(); generateExecStats(winningStats.get(), verbosity, &execBob, totalTimeMillis); // Also generate exec stats for all plans, if the verbosity level is high enough. // These stats reflect what happened during the trial period that ranked the plans. if (verbosity >= ExplainCommon::EXEC_ALL_PLANS) { // If we ranked multiple plans against each other, then add stats collected // from the trial period of the winning plan. The "allPlansExecution" section // will contain an apples-to-apples comparison of the winning plan's stats against // all rejected plans' stats collected during the trial period. if (NULL != mps) { invariant(winningStatsTrial.get()); allPlansStats.push_back(winningStatsTrial.release()); } BSONArrayBuilder allPlansBob(execBob.subarrayStart("allPlansExecution")); for (size_t i = 0; i < allPlansStats.size(); ++i) { BSONObjBuilder planBob(allPlansBob.subobjStart()); generateExecStats(allPlansStats[i], verbosity, &planBob); planBob.doneFast(); } allPlansBob.doneFast(); } execBob.doneFast(); } generateServerInfo(out); }