diff options
Diffstat (limited to 'src/mongo/db/exec/multi_plan.cpp')
| -rw-r--r-- | src/mongo/db/exec/multi_plan.cpp | 57 |
1 files changed, 54 insertions, 3 deletions
diff --git a/src/mongo/db/exec/multi_plan.cpp b/src/mongo/db/exec/multi_plan.cpp index def29719b63..00254cef133 100644 --- a/src/mongo/db/exec/multi_plan.cpp +++ b/src/mongo/db/exec/multi_plan.cpp @@ -190,14 +190,13 @@ PlanStage::StageState MultiPlanStage::doWork(WorkingSetID* out) { .getPlanCache() ->remove(plan_cache_key_factory::make<PlanCacheKey>(*_query, collection())); - _bestPlanIdx = _backupPlanIdx; - _backupPlanIdx = kNoSuchPlan; + switchToBackupPlan(); return _candidates[_bestPlanIdx].root->work(out); } if (hasBackupPlan() && PlanStage::ADVANCED == state) { LOGV2_DEBUG(20589, 5, "Best plan had a blocking stage, became unblocked"); - _backupPlanIdx = kNoSuchPlan; + removeBackupPlan(); } return state; @@ -294,6 +293,7 @@ Status MultiPlanStage::pickBestPlan(PlanYieldPolicy* yieldPolicy) { plan_cache_util::updatePlanCache( expCtx()->opCtx, collection(), _cachingMode, *_query, std::move(ranking), _candidates); + removeRejectedPlans(); return Status::OK(); } @@ -364,6 +364,54 @@ bool MultiPlanStage::workAllPlans(size_t numResults, PlanYieldPolicy* yieldPolic return !doneWorking; } +void MultiPlanStage::removeRejectedPlans() { + // Move the best plan and the backup plan to the front of 'children'. + if (_bestPlanIdx != 0) { + std::swap(_children[_bestPlanIdx], _children[0]); + std::swap(_candidates[_bestPlanIdx], _candidates[0]); + if (_backupPlanIdx == 0) { + _backupPlanIdx = _bestPlanIdx; + } + _bestPlanIdx = 0; + } + size_t startIndex = 1; + if (_backupPlanIdx != kNoSuchPlan) { + if (_backupPlanIdx != 1) { + std::swap(_children[_backupPlanIdx], _children[1]); + std::swap(_candidates[_backupPlanIdx], _candidates[1]); + _backupPlanIdx = 1; + } + startIndex = 2; + } + + _rejected.reserve(_children.size() - startIndex); + for (size_t i = startIndex; i < _children.size(); ++i) { + rejectPlan(i); + } + _children.resize(startIndex); +} + +void MultiPlanStage::switchToBackupPlan() { + std::swap(_children[_backupPlanIdx], _children[_bestPlanIdx]); + std::swap(_candidates[_backupPlanIdx], _candidates[_bestPlanIdx]); + removeBackupPlan(); +} + +void MultiPlanStage::rejectPlan(size_t planIdx) { + auto rejectedPlan = std::move(_children[planIdx]); + if (opCtx() != nullptr) { + rejectedPlan->saveState(); + rejectedPlan->detachFromOperationContext(); + } + _rejected.emplace_back(std::move(rejectedPlan)); +} + +void MultiPlanStage::removeBackupPlan() { + rejectPlan(_backupPlanIdx); + _children.resize(1); + _backupPlanIdx = kNoSuchPlan; +} + bool MultiPlanStage::hasBackupPlan() const { return kNoSuchPlan != _backupPlanIdx; } @@ -398,6 +446,9 @@ unique_ptr<PlanStageStats> MultiPlanStage::getStats() { for (auto&& child : _children) { ret->children.emplace_back(child->getStats()); } + for (auto&& child : _rejected) { + ret->children.emplace_back(child->getStats()); + } return ret; } |
