diff options
author | Mathias Stearn <mathias@10gen.com> | 2015-07-08 12:40:15 -0400 |
---|---|---|
committer | Mathias Stearn <mathias@10gen.com> | 2015-07-16 14:37:02 -0400 |
commit | c832bc753c29f91597b75fa02c0d9019c3c20b0f (patch) | |
tree | 5324f665212988a354ff6ba254b239dc594d2c7d | |
parent | f64b6c596f9dcd1bae7011a3230b517386baa255 (diff) | |
download | mongo-c832bc753c29f91597b75fa02c0d9019c3c20b0f.tar.gz |
SERVER-17364 Unify handling of child stages into PlanStage base class
This is prep for adding more methods that need to propagate to children.
75 files changed, 540 insertions, 1617 deletions
diff --git a/src/mongo/db/exec/SConscript b/src/mongo/db/exec/SConscript index 035817e61cc..282a49887d5 100644 --- a/src/mongo/db/exec/SConscript +++ b/src/mongo/db/exec/SConscript @@ -58,6 +58,7 @@ env.Library( "oplogstart.cpp", "or.cpp", "pipeline_proxy.cpp", + "plan_stage.cpp", "projection.cpp", "projection_exec.cpp", "queued_data_stage.cpp", diff --git a/src/mongo/db/exec/and_hash.cpp b/src/mongo/db/exec/and_hash.cpp index 9fe0111ebe8..1c21b4adf83 100644 --- a/src/mongo/db/exec/and_hash.cpp +++ b/src/mongo/db/exec/and_hash.cpp @@ -55,31 +55,25 @@ const size_t AndHashStage::kLookAheadWorks = 10; const char* AndHashStage::kStageType = "AND_HASH"; AndHashStage::AndHashStage(WorkingSet* ws, const Collection* collection) - : _collection(collection), + : PlanStage(kStageType), + _collection(collection), _ws(ws), _hashingChildren(true), _currentChild(0), - _commonStats(kStageType), _memUsage(0), _maxMemUsage(kDefaultMaxMemUsageBytes) {} AndHashStage::AndHashStage(WorkingSet* ws, const Collection* collection, size_t maxMemUsage) - : _collection(collection), + : PlanStage(kStageType), + _collection(collection), _ws(ws), _hashingChildren(true), _currentChild(0), - _commonStats(kStageType), _memUsage(0), _maxMemUsage(maxMemUsage) {} -AndHashStage::~AndHashStage() { - for (size_t i = 0; i < _children.size(); ++i) { - delete _children[i]; - } -} - void AndHashStage::addChild(PlanStage* child) { - _children.push_back(child); + _children.emplace_back(child); } size_t AndHashStage::getMemUsage() const { @@ -137,7 +131,7 @@ PlanStage::StageState AndHashStage::work(WorkingSetID* out) { // a result. If it's EOF this whole stage will be EOF. If it produces a // result we cache it for later. for (size_t i = 0; i < _children.size(); ++i) { - PlanStage* child = _children[i]; + auto& child = _children[i]; for (size_t j = 0; j < kLookAheadWorks; ++j) { StageState childStatus = child->work(&_lookAheadResults[i]); @@ -428,33 +422,12 @@ PlanStage::StageState AndHashStage::hashOtherChildren(WorkingSetID* out) { } } -void AndHashStage::saveState() { - ++_commonStats.yields; - - for (size_t i = 0; i < _children.size(); ++i) { - _children[i]->saveState(); - } -} - -void AndHashStage::restoreState(OperationContext* opCtx) { - ++_commonStats.unyields; - - for (size_t i = 0; i < _children.size(); ++i) { - _children[i]->restoreState(opCtx); - } -} - -void AndHashStage::invalidate(OperationContext* txn, const RecordId& dl, InvalidationType type) { - ++_commonStats.invalidates; - +void AndHashStage::doInvalidate(OperationContext* txn, const RecordId& dl, InvalidationType type) { + // TODO remove this since calling isEOF is illegal inside of doInvalidate(). if (isEOF()) { return; } - for (size_t i = 0; i < _children.size(); ++i) { - _children[i]->invalidate(txn, dl, type); - } - // Invalidation can happen to our warmup results. If that occurs just // flag it and forget about it. for (size_t i = 0; i < _lookAheadResults.size(); ++i) { @@ -500,10 +473,6 @@ void AndHashStage::invalidate(OperationContext* txn, const RecordId& dl, Invalid } } -vector<PlanStage*> AndHashStage::getChildren() const { - return _children; -} - unique_ptr<PlanStageStats> AndHashStage::getStats() { _commonStats.isEOF = isEOF(); @@ -519,10 +488,6 @@ unique_ptr<PlanStageStats> AndHashStage::getStats() { return ret; } -const CommonStats* AndHashStage::getCommonStats() const { - return &_commonStats; -} - const SpecificStats* AndHashStage::getSpecificStats() const { return &_specificStats; } diff --git a/src/mongo/db/exec/and_hash.h b/src/mongo/db/exec/and_hash.h index 974c940acda..b72a78fbeb8 100644 --- a/src/mongo/db/exec/and_hash.h +++ b/src/mongo/db/exec/and_hash.h @@ -58,8 +58,6 @@ public: */ AndHashStage(WorkingSet* ws, const Collection* collection, size_t maxMemUsage); - virtual ~AndHashStage(); - void addChild(PlanStage* child); /** @@ -71,11 +69,7 @@ public: virtual StageState work(WorkingSetID* out); virtual bool isEOF(); - virtual void saveState(); - virtual void restoreState(OperationContext* opCtx); - virtual void invalidate(OperationContext* txn, const RecordId& dl, InvalidationType type); - - virtual std::vector<PlanStage*> getChildren() const; + virtual void doInvalidate(OperationContext* txn, const RecordId& dl, InvalidationType type); virtual StageType stageType() const { return STAGE_AND_HASH; @@ -83,8 +77,6 @@ public: virtual std::unique_ptr<PlanStageStats> getStats(); - virtual const CommonStats* getCommonStats() const; - virtual const SpecificStats* getSpecificStats() const; static const char* kStageType; @@ -102,9 +94,6 @@ private: // Not owned by us. WorkingSet* _ws; - // The stages we read from. Owned by us. - std::vector<PlanStage*> _children; - // We want to see if any of our children are EOF immediately. This requires working them a // few times to see if they hit EOF or if they produce a result. If they produce a result, // we place that result here. @@ -127,7 +116,6 @@ private: size_t _currentChild; // Stats - CommonStats _commonStats; AndHashStats _specificStats; // The usage in bytes of all buffered data that we're holding. diff --git a/src/mongo/db/exec/and_sorted.cpp b/src/mongo/db/exec/and_sorted.cpp index 7186e694daa..873e545a2dd 100644 --- a/src/mongo/db/exec/and_sorted.cpp +++ b/src/mongo/db/exec/and_sorted.cpp @@ -45,21 +45,16 @@ using stdx::make_unique; const char* AndSortedStage::kStageType = "AND_SORTED"; AndSortedStage::AndSortedStage(WorkingSet* ws, const Collection* collection) - : _collection(collection), + : PlanStage(kStageType), + _collection(collection), _ws(ws), _targetNode(numeric_limits<size_t>::max()), _targetId(WorkingSet::INVALID_ID), - _isEOF(false), - _commonStats(kStageType) {} + _isEOF(false) {} -AndSortedStage::~AndSortedStage() { - for (size_t i = 0; i < _children.size(); ++i) { - delete _children[i]; - } -} void AndSortedStage::addChild(PlanStage* child) { - _children.push_back(child); + _children.emplace_back(child); } bool AndSortedStage::isEOF() { @@ -160,7 +155,7 @@ PlanStage::StageState AndSortedStage::moveTowardTargetLoc(WorkingSetID* out) { // We have nodes that haven't hit _targetLoc yet. size_t workingChildNumber = _workingTowardRep.front(); - PlanStage* next = _children[workingChildNumber]; + auto& next = _children[workingChildNumber]; WorkingSetID id = WorkingSet::INVALID_ID; StageState state = next->work(&id); @@ -253,33 +248,15 @@ PlanStage::StageState AndSortedStage::moveTowardTargetLoc(WorkingSetID* out) { } } -void AndSortedStage::saveState() { - ++_commonStats.yields; - - for (size_t i = 0; i < _children.size(); ++i) { - _children[i]->saveState(); - } -} - -void AndSortedStage::restoreState(OperationContext* opCtx) { - ++_commonStats.unyields; - - for (size_t i = 0; i < _children.size(); ++i) { - _children[i]->restoreState(opCtx); - } -} - -void AndSortedStage::invalidate(OperationContext* txn, const RecordId& dl, InvalidationType type) { - ++_commonStats.invalidates; +void AndSortedStage::doInvalidate(OperationContext* txn, + const RecordId& dl, + InvalidationType type) { + // TODO remove this since calling isEOF is illegal inside of doInvalidate(). if (isEOF()) { return; } - for (size_t i = 0; i < _children.size(); ++i) { - _children[i]->invalidate(txn, dl, type); - } - if (dl == _targetLoc) { // We're in the middle of moving children forward until they hit _targetLoc, which is no // longer a valid target. If it's a deletion we can't AND it with anything, if it's a @@ -298,10 +275,6 @@ void AndSortedStage::invalidate(OperationContext* txn, const RecordId& dl, Inval } } -vector<PlanStage*> AndSortedStage::getChildren() const { - return _children; -} - unique_ptr<PlanStageStats> AndSortedStage::getStats() { _commonStats.isEOF = isEOF(); @@ -314,10 +287,6 @@ unique_ptr<PlanStageStats> AndSortedStage::getStats() { return ret; } -const CommonStats* AndSortedStage::getCommonStats() const { - return &_commonStats; -} - const SpecificStats* AndSortedStage::getSpecificStats() const { return &_specificStats; } diff --git a/src/mongo/db/exec/and_sorted.h b/src/mongo/db/exec/and_sorted.h index cda1fa52a28..b742a1090e3 100644 --- a/src/mongo/db/exec/and_sorted.h +++ b/src/mongo/db/exec/and_sorted.h @@ -54,18 +54,13 @@ namespace mongo { class AndSortedStage : public PlanStage { public: AndSortedStage(WorkingSet* ws, const Collection* collection); - virtual ~AndSortedStage(); void addChild(PlanStage* child); virtual StageState work(WorkingSetID* out); virtual bool isEOF(); - virtual void saveState(); - virtual void restoreState(OperationContext* opCtx); - virtual void invalidate(OperationContext* txn, const RecordId& dl, InvalidationType type); - - virtual std::vector<PlanStage*> getChildren() const; + virtual void doInvalidate(OperationContext* txn, const RecordId& dl, InvalidationType type); virtual StageType stageType() const { return STAGE_AND_SORTED; @@ -73,8 +68,6 @@ public: virtual std::unique_ptr<PlanStageStats> getStats(); - virtual const CommonStats* getCommonStats() const; - virtual const SpecificStats* getSpecificStats() const; static const char* kStageType; @@ -93,9 +86,6 @@ private: // Not owned by us. WorkingSet* _ws; - // Owned by us. - std::vector<PlanStage*> _children; - // The current node we're AND-ing against. size_t _targetNode; RecordId _targetLoc; @@ -110,7 +100,6 @@ private: bool _isEOF; // Stats - CommonStats _commonStats; AndSortedStats _specificStats; }; diff --git a/src/mongo/db/exec/cached_plan.cpp b/src/mongo/db/exec/cached_plan.cpp index 6888b309039..7ad6ef16a6e 100644 --- a/src/mongo/db/exec/cached_plan.cpp +++ b/src/mongo/db/exec/cached_plan.cpp @@ -60,15 +60,15 @@ CachedPlanStage::CachedPlanStage(OperationContext* txn, const QueryPlannerParams& params, size_t decisionWorks, PlanStage* root) - : _txn(txn), + : PlanStage(kStageType), + _txn(txn), _collection(collection), _ws(ws), _canonicalQuery(cq), _plannerParams(params), - _decisionWorks(decisionWorks), - _root(root), - _commonStats(kStageType) { + _decisionWorks(decisionWorks) { invariant(_collection); + _children.emplace_back(root); } Status CachedPlanStage::pickBestPlan(PlanYieldPolicy* yieldPolicy) { @@ -93,7 +93,7 @@ Status CachedPlanStage::pickBestPlan(PlanYieldPolicy* yieldPolicy) { } WorkingSetID id = WorkingSet::INVALID_ID; - PlanStage::StageState state = _root->work(&id); + PlanStage::StageState state = child()->work(&id); if (PlanStage::ADVANCED == state) { // Save result for later. @@ -138,7 +138,7 @@ Status CachedPlanStage::pickBestPlan(PlanYieldPolicy* yieldPolicy) { LOG(1) << "Execution of cached plan failed, falling back to replan." << " query: " << _canonicalQuery->toStringShort() - << " planSummary: " << Explain::getPlanSummary(_root.get()) + << " planSummary: " << Explain::getPlanSummary(child().get()) << " status: " << statusObj; const bool shouldCache = false; @@ -149,7 +149,7 @@ Status CachedPlanStage::pickBestPlan(PlanYieldPolicy* yieldPolicy) { LOG(1) << "Execution of cached plan failed: PlanStage died" << ", query: " << _canonicalQuery->toStringShort() - << " planSummary: " << Explain::getPlanSummary(_root.get()) + << " planSummary: " << Explain::getPlanSummary(child().get()) << " status: " << statusObj; return WorkingSetCommon::getMemberObjectStatus(statusObj); @@ -164,7 +164,7 @@ Status CachedPlanStage::pickBestPlan(PlanYieldPolicy* yieldPolicy) { << " works, but was originally cached with only " << _decisionWorks << " works. Evicting cache entry and replanning query: " << _canonicalQuery->toStringShort() - << " plan summary before replan: " << Explain::getPlanSummary(_root.get()); + << " plan summary before replan: " << Explain::getPlanSummary(child().get()); const bool shouldCache = true; return replan(yieldPolicy, shouldCache); @@ -194,11 +194,10 @@ Status CachedPlanStage::tryYield(PlanYieldPolicy* yieldPolicy) { } Status CachedPlanStage::replan(PlanYieldPolicy* yieldPolicy, bool shouldCache) { - // We're going to start over with a new plan. No need for only old buffered results. + // We're going to start over with a new plan. Clear out info from our old plan. _results.clear(); - - // Clear out the working set. We'll start with a fresh working set. _ws->clear(); + _children.clear(); // Use the query planning module to plan the whole query. std::vector<QuerySolution*> rawSolutions; @@ -230,15 +229,15 @@ Status CachedPlanStage::replan(PlanYieldPolicy* yieldPolicy, bool shouldCache) { PlanStage* newRoot; // Only one possible plan. Build the stages from the solution. verify(StageBuilder::build(_txn, _collection, *solutions[0], _ws, &newRoot)); - _root.reset(newRoot); + _children.emplace_back(newRoot); _replannedQs.reset(solutions.popAndReleaseBack()); return Status::OK(); } // Many solutions. Create a MultiPlanStage to pick the best, update the cache, // and so on. The working set will be shared by all candidate plans. - _root.reset(new MultiPlanStage(_txn, _collection, _canonicalQuery, shouldCache)); - MultiPlanStage* multiPlanStage = static_cast<MultiPlanStage*>(_root.get()); + _children.emplace_back(new MultiPlanStage(_txn, _collection, _canonicalQuery, shouldCache)); + MultiPlanStage* multiPlanStage = static_cast<MultiPlanStage*>(child().get()); for (size_t ix = 0; ix < solutions.size(); ++ix) { if (solutions[ix]->cacheData.get()) { @@ -257,7 +256,7 @@ Status CachedPlanStage::replan(PlanYieldPolicy* yieldPolicy, bool shouldCache) { } bool CachedPlanStage::isEOF() { - return _results.empty() && _root->isEOF(); + return _results.empty() && child()->isEOF(); } PlanStage::StageState CachedPlanStage::work(WorkingSetID* out) { @@ -279,7 +278,7 @@ PlanStage::StageState CachedPlanStage::work(WorkingSetID* out) { } // Nothing left in trial period buffer. - StageState childStatus = _root->work(out); + StageState childStatus = child()->work(out); if (PlanStage::ADVANCED == childStatus) { _commonStats.advanced++; @@ -292,24 +291,14 @@ PlanStage::StageState CachedPlanStage::work(WorkingSetID* out) { return childStatus; } -void CachedPlanStage::saveState() { - _txn = NULL; - ++_commonStats.yields; - _root->saveState(); -} -void CachedPlanStage::restoreState(OperationContext* opCtx) { - invariant(_txn == NULL); +void CachedPlanStage::doRestoreState(OperationContext* opCtx) { _txn = opCtx; - - ++_commonStats.unyields; - _root->restoreState(opCtx); } -void CachedPlanStage::invalidate(OperationContext* txn, const RecordId& dl, InvalidationType type) { - _root->invalidate(txn, dl, type); - ++_commonStats.invalidates; - +void CachedPlanStage::doInvalidate(OperationContext* txn, + const RecordId& dl, + InvalidationType type) { for (std::list<WorkingSetID>::iterator it = _results.begin(); it != _results.end();) { WorkingSetMember* member = _ws->get(*it); if (member->hasLoc() && member->loc == dl) { @@ -324,25 +313,17 @@ void CachedPlanStage::invalidate(OperationContext* txn, const RecordId& dl, Inva } } -std::vector<PlanStage*> CachedPlanStage::getChildren() const { - return {_root.get()}; -} - std::unique_ptr<PlanStageStats> CachedPlanStage::getStats() { _commonStats.isEOF = isEOF(); std::unique_ptr<PlanStageStats> ret = stdx::make_unique<PlanStageStats>(_commonStats, STAGE_CACHED_PLAN); ret->specific = stdx::make_unique<CachedPlanStats>(_specificStats); - ret->children.push_back(_root->getStats().release()); + ret->children.push_back(child()->getStats().release()); return ret; } -const CommonStats* CachedPlanStage::getCommonStats() const { - return &_commonStats; -} - const SpecificStats* CachedPlanStage::getSpecificStats() const { return &_specificStats; } diff --git a/src/mongo/db/exec/cached_plan.h b/src/mongo/db/exec/cached_plan.h index 02f92350549..117e6aa5dfa 100644 --- a/src/mongo/db/exec/cached_plan.h +++ b/src/mongo/db/exec/cached_plan.h @@ -65,11 +65,8 @@ public: virtual StageState work(WorkingSetID* out); - virtual void saveState(); - virtual void restoreState(OperationContext* opCtx); - virtual void invalidate(OperationContext* txn, const RecordId& dl, InvalidationType type); - - virtual std::vector<PlanStage*> getChildren() const; + virtual void doRestoreState(OperationContext* opCtx); + virtual void doInvalidate(OperationContext* txn, const RecordId& dl, InvalidationType type); virtual StageType stageType() const { return STAGE_CACHED_PLAN; @@ -77,8 +74,6 @@ public: virtual std::unique_ptr<PlanStageStats> getStats(); - virtual const CommonStats* getCommonStats() const; - virtual const SpecificStats* getSpecificStats() const; static const char* kStageType; @@ -142,8 +137,6 @@ private: // that solution is owned here. std::unique_ptr<QuerySolution> _replannedQs; - std::unique_ptr<PlanStage> _root; - // Any results produced during trial period execution are kept here. std::list<WorkingSetID> _results; @@ -154,7 +147,6 @@ private: std::unique_ptr<RecordFetcher> _fetcher; // Stats - CommonStats _commonStats; CachedPlanStats _specificStats; }; diff --git a/src/mongo/db/exec/collection_scan.cpp b/src/mongo/db/exec/collection_scan.cpp index d5a5d550bea..9eee74c4451 100644 --- a/src/mongo/db/exec/collection_scan.cpp +++ b/src/mongo/db/exec/collection_scan.cpp @@ -58,13 +58,13 @@ CollectionScan::CollectionScan(OperationContext* txn, const CollectionScanParams& params, WorkingSet* workingSet, const MatchExpression* filter) - : _txn(txn), + : PlanStage(kStageType), + _txn(txn), _workingSet(workingSet), _filter(filter), _params(params), _isDead(false), - _wsidForFetch(_workingSet->allocate()), - _commonStats(kStageType) { + _wsidForFetch(_workingSet->allocate()) { // Explain reports the direction of the collection scan. _specificStats.direction = params.direction; } @@ -191,9 +191,9 @@ bool CollectionScan::isEOF() { return _commonStats.isEOF || _isDead; } -void CollectionScan::invalidate(OperationContext* txn, const RecordId& id, InvalidationType type) { - ++_commonStats.invalidates; - +void CollectionScan::doInvalidate(OperationContext* txn, + const RecordId& id, + InvalidationType type) { // We don't care about mutations since we apply any filters to the result when we (possibly) // return it. if (INVALIDATION_DELETION != type) { @@ -214,18 +214,16 @@ void CollectionScan::invalidate(OperationContext* txn, const RecordId& id, Inval } } -void CollectionScan::saveState() { +void CollectionScan::doSaveState() { _txn = NULL; - ++_commonStats.yields; if (_cursor) { _cursor->savePositioned(); } } -void CollectionScan::restoreState(OperationContext* opCtx) { +void CollectionScan::doRestoreState(OperationContext* opCtx) { invariant(_txn == NULL); _txn = opCtx; - ++_commonStats.unyields; if (_cursor) { if (!_cursor->restore(opCtx)) { warning() << "Could not restore RecordCursor for CollectionScan: " << opCtx->getNS(); @@ -234,11 +232,6 @@ void CollectionScan::restoreState(OperationContext* opCtx) { } } -vector<PlanStage*> CollectionScan::getChildren() const { - vector<PlanStage*> empty; - return empty; -} - unique_ptr<PlanStageStats> CollectionScan::getStats() { // Add a BSON representation of the filter to the stats tree, if there is one. if (NULL != _filter) { @@ -252,10 +245,6 @@ unique_ptr<PlanStageStats> CollectionScan::getStats() { return ret; } -const CommonStats* CollectionScan::getCommonStats() const { - return &_commonStats; -} - const SpecificStats* CollectionScan::getSpecificStats() const { return &_specificStats; } diff --git a/src/mongo/db/exec/collection_scan.h b/src/mongo/db/exec/collection_scan.h index 418a3b5b7e2..856af5e10ad 100644 --- a/src/mongo/db/exec/collection_scan.h +++ b/src/mongo/db/exec/collection_scan.h @@ -57,11 +57,9 @@ public: virtual StageState work(WorkingSetID* out); virtual bool isEOF(); - virtual void invalidate(OperationContext* txn, const RecordId& dl, InvalidationType type); - virtual void saveState(); - virtual void restoreState(OperationContext* opCtx); - - virtual std::vector<PlanStage*> getChildren() const; + virtual void doInvalidate(OperationContext* txn, const RecordId& dl, InvalidationType type); + virtual void doSaveState(); + virtual void doRestoreState(OperationContext* opCtx); virtual StageType stageType() const { return STAGE_COLLSCAN; @@ -69,8 +67,6 @@ public: virtual std::unique_ptr<PlanStageStats> getStats(); - virtual const CommonStats* getCommonStats() const; - virtual const SpecificStats* getSpecificStats() const; static const char* kStageType; @@ -105,7 +101,6 @@ private: const WorkingSetID _wsidForFetch; // Stats - CommonStats _commonStats; CollectionScanStats _specificStats; }; diff --git a/src/mongo/db/exec/count.cpp b/src/mongo/db/exec/count.cpp index 55e080d8c14..bcc389a488b 100644 --- a/src/mongo/db/exec/count.cpp +++ b/src/mongo/db/exec/count.cpp @@ -49,15 +49,15 @@ CountStage::CountStage(OperationContext* txn, const CountRequest& request, WorkingSet* ws, PlanStage* child) - : _txn(txn), + : PlanStage(kStageType), + _txn(txn), _collection(collection), _request(request), _leftToSkip(request.getSkip()), - _ws(ws), - _child(child), - _commonStats(kStageType) {} - -CountStage::~CountStage() {} + _ws(ws) { + if (child) + _children.emplace_back(child); +} bool CountStage::isEOF() { if (_specificStats.trivialCount) { @@ -68,7 +68,7 @@ bool CountStage::isEOF() { return true; } - return NULL != _child.get() && _child->isEOF(); + return !_children.empty() && child()->isEOF(); } void CountStage::trivialCount() { @@ -119,9 +119,9 @@ PlanStage::StageState CountStage::work(WorkingSetID* out) { // For non-trivial counts, we should always have a child stage from which we can retrieve // results. - invariant(_child.get()); + invariant(child()); WorkingSetID id = WorkingSet::INVALID_ID; - PlanStage::StageState state = _child->work(&id); + PlanStage::StageState state = child()->work(&id); if (PlanStage::IS_EOF == state) { _commonStats.isEOF = true; @@ -163,52 +163,20 @@ PlanStage::StageState CountStage::work(WorkingSetID* out) { return PlanStage::NEED_TIME; } -void CountStage::saveState() { - _txn = NULL; - ++_commonStats.yields; - if (_child.get()) { - _child->saveState(); - } -} - -void CountStage::restoreState(OperationContext* opCtx) { - invariant(_txn == NULL); +void CountStage::doRestoreState(OperationContext* opCtx) { _txn = opCtx; - ++_commonStats.unyields; - if (_child.get()) { - _child->restoreState(opCtx); - } -} - -void CountStage::invalidate(OperationContext* txn, const RecordId& dl, InvalidationType type) { - ++_commonStats.invalidates; - if (_child.get()) { - _child->invalidate(txn, dl, type); - } -} - -vector<PlanStage*> CountStage::getChildren() const { - vector<PlanStage*> children; - if (_child.get()) { - children.push_back(_child.get()); - } - return children; } unique_ptr<PlanStageStats> CountStage::getStats() { _commonStats.isEOF = isEOF(); unique_ptr<PlanStageStats> ret = make_unique<PlanStageStats>(_commonStats, STAGE_COUNT); ret->specific = make_unique<CountStats>(_specificStats); - if (_child.get()) { - ret->children.push_back(_child->getStats().release()); + if (!_children.empty()) { + ret->children.push_back(child()->getStats().release()); } return ret; } -const CommonStats* CountStage::getCommonStats() const { - return &_commonStats; -} - const SpecificStats* CountStage::getSpecificStats() const { return &_specificStats; } diff --git a/src/mongo/db/exec/count.h b/src/mongo/db/exec/count.h index 1dbc4dfa0f4..ccb4a4b364a 100644 --- a/src/mongo/db/exec/count.h +++ b/src/mongo/db/exec/count.h @@ -53,16 +53,10 @@ public: WorkingSet* ws, PlanStage* child); - virtual ~CountStage(); - virtual bool isEOF(); virtual StageState work(WorkingSetID* out); - virtual void saveState(); - virtual void restoreState(OperationContext* opCtx); - virtual void invalidate(OperationContext* txn, const RecordId& dl, InvalidationType type); - - virtual std::vector<PlanStage*> getChildren() const; + virtual void doRestoreState(OperationContext* opCtx); virtual StageType stageType() const { return STAGE_COUNT; @@ -70,8 +64,6 @@ public: std::unique_ptr<PlanStageStats> getStats(); - virtual const CommonStats* getCommonStats() const; - virtual const SpecificStats* getSpecificStats() const; static const char* kStageType; @@ -98,9 +90,6 @@ private: // by us. WorkingSet* _ws; - std::unique_ptr<PlanStage> _child; - - CommonStats _commonStats; CountStats _specificStats; }; diff --git a/src/mongo/db/exec/count_scan.cpp b/src/mongo/db/exec/count_scan.cpp index ccd2b7339c3..e6a9f4b667c 100644 --- a/src/mongo/db/exec/count_scan.cpp +++ b/src/mongo/db/exec/count_scan.cpp @@ -43,13 +43,13 @@ using stdx::make_unique; const char* CountScan::kStageType = "COUNT_SCAN"; CountScan::CountScan(OperationContext* txn, const CountScanParams& params, WorkingSet* workingSet) - : _txn(txn), + : PlanStage(kStageType), + _txn(txn), _workingSet(workingSet), _descriptor(params.descriptor), _iam(params.descriptor->getIndexCatalog()->getIndex(params.descriptor)), _shouldDedup(params.descriptor->isMultikey(txn)), - _params(params), - _commonStats(kStageType) { + _params(params) { _specificStats.keyPattern = _params.descriptor->keyPattern(); _specificStats.indexName = _params.descriptor->indexName(); _specificStats.isMultiKey = _params.descriptor->isMultikey(txn); @@ -120,17 +120,15 @@ bool CountScan::isEOF() { return _commonStats.isEOF; } -void CountScan::saveState() { +void CountScan::doSaveState() { _txn = NULL; - ++_commonStats.yields; if (_cursor) _cursor->savePositioned(); } -void CountScan::restoreState(OperationContext* opCtx) { +void CountScan::doRestoreState(OperationContext* opCtx) { invariant(_txn == NULL); _txn = opCtx; - ++_commonStats.unyields; if (_cursor) _cursor->restore(opCtx); @@ -140,9 +138,7 @@ void CountScan::restoreState(OperationContext* opCtx) { _shouldDedup = _descriptor->isMultikey(_txn); } -void CountScan::invalidate(OperationContext* txn, const RecordId& dl, InvalidationType type) { - ++_commonStats.invalidates; - +void CountScan::doInvalidate(OperationContext* txn, const RecordId& dl, InvalidationType type) { // The only state we're responsible for holding is what RecordIds to drop. If a document // mutates the underlying index cursor will deal with it. if (INVALIDATION_MUTATION == type) { @@ -157,11 +153,6 @@ void CountScan::invalidate(OperationContext* txn, const RecordId& dl, Invalidati } } -vector<PlanStage*> CountScan::getChildren() const { - vector<PlanStage*> empty; - return empty; -} - unique_ptr<PlanStageStats> CountScan::getStats() { unique_ptr<PlanStageStats> ret = make_unique<PlanStageStats>(_commonStats, STAGE_COUNT_SCAN); @@ -172,10 +163,6 @@ unique_ptr<PlanStageStats> CountScan::getStats() { return ret; } -const CommonStats* CountScan::getCommonStats() const { - return &_commonStats; -} - const SpecificStats* CountScan::getSpecificStats() const { return &_specificStats; } diff --git a/src/mongo/db/exec/count_scan.h b/src/mongo/db/exec/count_scan.h index 8d7afdef1b6..ffb0035417d 100644 --- a/src/mongo/db/exec/count_scan.h +++ b/src/mongo/db/exec/count_scan.h @@ -67,15 +67,12 @@ struct CountScanParams { class CountScan : public PlanStage { public: CountScan(OperationContext* txn, const CountScanParams& params, WorkingSet* workingSet); - virtual ~CountScan() {} virtual StageState work(WorkingSetID* out); virtual bool isEOF(); - virtual void saveState(); - virtual void restoreState(OperationContext* opCtx); - virtual void invalidate(OperationContext* txn, const RecordId& dl, InvalidationType type); - - virtual std::vector<PlanStage*> getChildren() const; + virtual void doSaveState(); + virtual void doRestoreState(OperationContext* opCtx); + virtual void doInvalidate(OperationContext* txn, const RecordId& dl, InvalidationType type); virtual StageType stageType() const { return STAGE_COUNT_SCAN; @@ -83,8 +80,6 @@ public: virtual std::unique_ptr<PlanStageStats> getStats(); - virtual const CommonStats* getCommonStats() const; - virtual const SpecificStats* getSpecificStats() const; static const char* kStageType; @@ -108,7 +103,6 @@ private: CountScanParams _params; - CommonStats _commonStats; CountScanStats _specificStats; }; diff --git a/src/mongo/db/exec/delete.cpp b/src/mongo/db/exec/delete.cpp index e4a89d197c0..bdc78806521 100644 --- a/src/mongo/db/exec/delete.cpp +++ b/src/mongo/db/exec/delete.cpp @@ -58,16 +58,15 @@ DeleteStage::DeleteStage(OperationContext* txn, WorkingSet* ws, Collection* collection, PlanStage* child) - : _txn(txn), + : PlanStage(kStageType), + _txn(txn), _params(params), _ws(ws), _collection(collection), - _child(child), _idRetrying(WorkingSet::INVALID_ID), - _idReturning(WorkingSet::INVALID_ID), - _commonStats(kStageType) {} - -DeleteStage::~DeleteStage() {} + _idReturning(WorkingSet::INVALID_ID) { + _children.emplace_back(child); +} bool DeleteStage::isEOF() { if (!_collection) { @@ -77,7 +76,7 @@ bool DeleteStage::isEOF() { return true; } return _idRetrying == WorkingSet::INVALID_ID && _idReturning == WorkingSet::INVALID_ID && - _child->isEOF(); + child()->isEOF(); } PlanStage::StageState DeleteStage::work(WorkingSetID* out) { @@ -110,7 +109,7 @@ PlanStage::StageState DeleteStage::work(WorkingSetID* out) { WorkingSetID id; StageState status; if (_idRetrying == WorkingSet::INVALID_ID) { - status = _child->work(&id); + status = child()->work(&id); } else { status = ADVANCED; id = _idRetrying; @@ -160,7 +159,7 @@ PlanStage::StageState DeleteStage::work(WorkingSetID* out) { // saving/restoring state repeatedly? try { - _child->saveState(); + child()->saveState(); if (supportsDocLocking()) { // Doc-locking engines require this after saveState() since they don't use // invalidations. @@ -208,7 +207,7 @@ PlanStage::StageState DeleteStage::work(WorkingSetID* out) { // transaction in which they are created, and a WriteUnitOfWork is a // transaction, make sure to restore the state outside of the WritUnitOfWork. try { - _child->restoreState(_txn); + child()->restoreState(_txn); } catch (const WriteConflictException& wce) { // Note we don't need to retry anything in this case since the delete already // was committed. However, we still need to return the deleted document @@ -258,18 +257,8 @@ PlanStage::StageState DeleteStage::work(WorkingSetID* out) { return status; } -void DeleteStage::saveState() { - _txn = NULL; - ++_commonStats.yields; - _child->saveState(); -} - -void DeleteStage::restoreState(OperationContext* opCtx) { - invariant(_txn == NULL); +void DeleteStage::doRestoreState(OperationContext* opCtx) { _txn = opCtx; - ++_commonStats.unyields; - _child->restoreState(opCtx); - const NamespaceString& ns(_collection->ns()); massert(28537, str::stream() << "Demoted from primary while removing from " << ns.ns(), @@ -277,29 +266,14 @@ void DeleteStage::restoreState(OperationContext* opCtx) { repl::getGlobalReplicationCoordinator()->canAcceptWritesFor(ns)); } -void DeleteStage::invalidate(OperationContext* txn, const RecordId& dl, InvalidationType type) { - ++_commonStats.invalidates; - _child->invalidate(txn, dl, type); -} - -vector<PlanStage*> DeleteStage::getChildren() const { - vector<PlanStage*> children; - children.push_back(_child.get()); - return children; -} - unique_ptr<PlanStageStats> DeleteStage::getStats() { _commonStats.isEOF = isEOF(); unique_ptr<PlanStageStats> ret = make_unique<PlanStageStats>(_commonStats, STAGE_DELETE); ret->specific = make_unique<DeleteStats>(_specificStats); - ret->children.push_back(_child->getStats().release()); + ret->children.push_back(child()->getStats().release()); return ret; } -const CommonStats* DeleteStage::getCommonStats() const { - return &_commonStats; -} - const SpecificStats* DeleteStage::getSpecificStats() const { return &_specificStats; } diff --git a/src/mongo/db/exec/delete.h b/src/mongo/db/exec/delete.h index ab907557bc7..76f6afdb123 100644 --- a/src/mongo/db/exec/delete.h +++ b/src/mongo/db/exec/delete.h @@ -85,16 +85,11 @@ public: WorkingSet* ws, Collection* collection, PlanStage* child); - virtual ~DeleteStage(); virtual bool isEOF(); virtual StageState work(WorkingSetID* out); - virtual void saveState(); - virtual void restoreState(OperationContext* opCtx); - virtual void invalidate(OperationContext* txn, const RecordId& dl, InvalidationType type); - - virtual std::vector<PlanStage*> getChildren() const; + virtual void doRestoreState(OperationContext* opCtx); virtual StageType stageType() const { return STAGE_DELETE; @@ -102,8 +97,6 @@ public: virtual std::unique_ptr<PlanStageStats> getStats(); - virtual const CommonStats* getCommonStats() const; - virtual const SpecificStats* getSpecificStats() const; static const char* kStageType; @@ -129,8 +122,6 @@ private: // stage. Collection* _collection; - std::unique_ptr<PlanStage> _child; - // If not WorkingSet::INVALID_ID, we use this rather than asking our child what to do next. WorkingSetID _idRetrying; @@ -138,7 +129,6 @@ private: WorkingSetID _idReturning; // Stats - CommonStats _commonStats; DeleteStats _specificStats; }; diff --git a/src/mongo/db/exec/distinct_scan.cpp b/src/mongo/db/exec/distinct_scan.cpp index e189861dc86..d838177b456 100644 --- a/src/mongo/db/exec/distinct_scan.cpp +++ b/src/mongo/db/exec/distinct_scan.cpp @@ -48,13 +48,13 @@ const char* DistinctScan::kStageType = "DISTINCT_SCAN"; DistinctScan::DistinctScan(OperationContext* txn, const DistinctParams& params, WorkingSet* workingSet) - : _txn(txn), + : PlanStage(kStageType), + _txn(txn), _workingSet(workingSet), _descriptor(params.descriptor), _iam(params.descriptor->getIndexCatalog()->getIndex(params.descriptor)), _params(params), - _checker(&_params.bounds, _descriptor->keyPattern(), _params.direction), - _commonStats(kStageType) { + _checker(&_params.bounds, _descriptor->keyPattern(), _params.direction) { _specificStats.keyPattern = _params.descriptor->keyPattern(); _specificStats.indexName = _params.descriptor->indexName(); _specificStats.indexVersion = _params.descriptor->version(); @@ -128,43 +128,28 @@ bool DistinctScan::isEOF() { return _commonStats.isEOF; } -void DistinctScan::saveState() { +void DistinctScan::doSaveState() { _txn = NULL; - ++_commonStats.yields; // We always seek, so we don't care where the cursor is. if (_cursor) _cursor->saveUnpositioned(); } -void DistinctScan::restoreState(OperationContext* opCtx) { +void DistinctScan::doRestoreState(OperationContext* opCtx) { invariant(_txn == NULL); _txn = opCtx; - ++_commonStats.unyields; if (_cursor) _cursor->restore(opCtx); } -void DistinctScan::invalidate(OperationContext* txn, const RecordId& dl, InvalidationType type) { - ++_commonStats.invalidates; -} - -vector<PlanStage*> DistinctScan::getChildren() const { - vector<PlanStage*> empty; - return empty; -} - unique_ptr<PlanStageStats> DistinctScan::getStats() { unique_ptr<PlanStageStats> ret = make_unique<PlanStageStats>(_commonStats, STAGE_DISTINCT_SCAN); ret->specific = make_unique<DistinctScanStats>(_specificStats); return ret; } -const CommonStats* DistinctScan::getCommonStats() const { - return &_commonStats; -} - const SpecificStats* DistinctScan::getSpecificStats() const { return &_specificStats; } diff --git a/src/mongo/db/exec/distinct_scan.h b/src/mongo/db/exec/distinct_scan.h index 83b4da8c216..b39ab6e9acc 100644 --- a/src/mongo/db/exec/distinct_scan.h +++ b/src/mongo/db/exec/distinct_scan.h @@ -79,11 +79,8 @@ public: virtual StageState work(WorkingSetID* out); virtual bool isEOF(); - virtual void saveState(); - virtual void restoreState(OperationContext* opCtx); - virtual void invalidate(OperationContext* txn, const RecordId& dl, InvalidationType type); - - virtual std::vector<PlanStage*> getChildren() const; + virtual void doSaveState(); + virtual void doRestoreState(OperationContext* opCtx); virtual StageType stageType() const { return STAGE_DISTINCT_SCAN; @@ -91,8 +88,6 @@ public: virtual std::unique_ptr<PlanStageStats> getStats(); - virtual const CommonStats* getCommonStats() const; - virtual const SpecificStats* getSpecificStats() const; static const char* kStageType; @@ -118,7 +113,6 @@ private: IndexSeekPoint _seekPoint; // Stats - CommonStats _commonStats; DistinctScanStats _specificStats; }; diff --git a/src/mongo/db/exec/eof.cpp b/src/mongo/db/exec/eof.cpp index a09eeaa9692..aebb31b0277 100644 --- a/src/mongo/db/exec/eof.cpp +++ b/src/mongo/db/exec/eof.cpp @@ -42,7 +42,7 @@ using stdx::make_unique; // static const char* EOFStage::kStageType = "EOF"; -EOFStage::EOFStage() : _commonStats(kStageType) {} +EOFStage::EOFStage() : PlanStage(kStageType) {} EOFStage::~EOFStage() {} @@ -57,32 +57,11 @@ PlanStage::StageState EOFStage::work(WorkingSetID* out) { return PlanStage::IS_EOF; } -void EOFStage::saveState() { - ++_commonStats.yields; -} - -void EOFStage::restoreState(OperationContext* opCtx) { - ++_commonStats.unyields; -} - -void EOFStage::invalidate(OperationContext* txn, const RecordId& dl, InvalidationType type) { - ++_commonStats.invalidates; -} - -vector<PlanStage*> EOFStage::getChildren() const { - vector<PlanStage*> empty; - return empty; -} - unique_ptr<PlanStageStats> EOFStage::getStats() { _commonStats.isEOF = isEOF(); return make_unique<PlanStageStats>(_commonStats, STAGE_EOF); } -const CommonStats* EOFStage::getCommonStats() const { - return &_commonStats; -} - const SpecificStats* EOFStage::getSpecificStats() const { return nullptr; } diff --git a/src/mongo/db/exec/eof.h b/src/mongo/db/exec/eof.h index c8825ed085f..30df7679ba1 100644 --- a/src/mongo/db/exec/eof.h +++ b/src/mongo/db/exec/eof.h @@ -45,11 +45,6 @@ public: virtual bool isEOF(); virtual StageState work(WorkingSetID* out); - virtual void saveState(); - virtual void restoreState(OperationContext* opCtx); - virtual void invalidate(OperationContext* txn, const RecordId& dl, InvalidationType type); - - virtual std::vector<PlanStage*> getChildren() const; virtual StageType stageType() const { return STAGE_EOF; @@ -57,14 +52,9 @@ public: std::unique_ptr<PlanStageStats> getStats(); - virtual const CommonStats* getCommonStats() const; - virtual const SpecificStats* getSpecificStats() const; static const char* kStageType; - -private: - CommonStats _commonStats; }; } // namespace mongo diff --git a/src/mongo/db/exec/fetch.cpp b/src/mongo/db/exec/fetch.cpp index eae3b00a361..c31d9b3f45f 100644 --- a/src/mongo/db/exec/fetch.cpp +++ b/src/mongo/db/exec/fetch.cpp @@ -54,13 +54,14 @@ FetchStage::FetchStage(OperationContext* txn, PlanStage* child, const MatchExpression* filter, const Collection* collection) - : _txn(txn), + : PlanStage(kStageType), + _txn(txn), _collection(collection), _ws(ws), - _child(child), _filter(filter), - _idRetrying(WorkingSet::INVALID_ID), - _commonStats(kStageType) {} + _idRetrying(WorkingSet::INVALID_ID) { + _children.emplace_back(child); +} FetchStage::~FetchStage() {} @@ -71,7 +72,7 @@ bool FetchStage::isEOF() { return false; } - return _child->isEOF(); + return child()->isEOF(); } PlanStage::StageState FetchStage::work(WorkingSetID* out) { @@ -88,7 +89,7 @@ PlanStage::StageState FetchStage::work(WorkingSetID* out) { WorkingSetID id; StageState status; if (_idRetrying == WorkingSet::INVALID_ID) { - status = _child->work(&id); + status = child()->work(&id); } else { status = ADVANCED; id = _idRetrying; @@ -158,28 +159,20 @@ PlanStage::StageState FetchStage::work(WorkingSetID* out) { return status; } -void FetchStage::saveState() { +void FetchStage::doSaveState() { _txn = NULL; - ++_commonStats.yields; if (_cursor) _cursor->saveUnpositioned(); - _child->saveState(); } -void FetchStage::restoreState(OperationContext* opCtx) { +void FetchStage::doRestoreState(OperationContext* opCtx) { invariant(_txn == NULL); _txn = opCtx; - ++_commonStats.unyields; if (_cursor) _cursor->restore(opCtx); - _child->restoreState(opCtx); } -void FetchStage::invalidate(OperationContext* txn, const RecordId& dl, InvalidationType type) { - ++_commonStats.invalidates; - - _child->invalidate(txn, dl, type); - +void FetchStage::doInvalidate(OperationContext* txn, const RecordId& dl, InvalidationType type) { // It's possible that the loc getting invalidated is the one we're about to // fetch. In this case we do a "forced fetch" and put the WSM in owned object state. if (WorkingSet::INVALID_ID != _idRetrying) { @@ -223,12 +216,6 @@ PlanStage::StageState FetchStage::returnIfMatches(WorkingSetMember* member, } } -vector<PlanStage*> FetchStage::getChildren() const { - vector<PlanStage*> children; - children.push_back(_child.get()); - return children; -} - unique_ptr<PlanStageStats> FetchStage::getStats() { _commonStats.isEOF = isEOF(); @@ -241,14 +228,10 @@ unique_ptr<PlanStageStats> FetchStage::getStats() { unique_ptr<PlanStageStats> ret = make_unique<PlanStageStats>(_commonStats, STAGE_FETCH); ret->specific = make_unique<FetchStats>(_specificStats); - ret->children.push_back(_child->getStats().release()); + ret->children.push_back(child()->getStats().release()); return ret; } -const CommonStats* FetchStage::getCommonStats() const { - return &_commonStats; -} - const SpecificStats* FetchStage::getSpecificStats() const { return &_specificStats; } diff --git a/src/mongo/db/exec/fetch.h b/src/mongo/db/exec/fetch.h index 9a0ff81c021..edfd6c35a5f 100644 --- a/src/mongo/db/exec/fetch.h +++ b/src/mongo/db/exec/fetch.h @@ -60,11 +60,9 @@ public: virtual bool isEOF(); virtual StageState work(WorkingSetID* out); - virtual void saveState(); - virtual void restoreState(OperationContext* opCtx); - virtual void invalidate(OperationContext* txn, const RecordId& dl, InvalidationType type); - - virtual std::vector<PlanStage*> getChildren() const; + virtual void doSaveState(); + virtual void doRestoreState(OperationContext* opCtx); + virtual void doInvalidate(OperationContext* txn, const RecordId& dl, InvalidationType type); virtual StageType stageType() const { return STAGE_FETCH; @@ -72,8 +70,6 @@ public: std::unique_ptr<PlanStageStats> getStats(); - virtual const CommonStats* getCommonStats() const; - virtual const SpecificStats* getSpecificStats() const; static const char* kStageType; @@ -95,7 +91,6 @@ private: // _ws is not owned by us. WorkingSet* _ws; - std::unique_ptr<PlanStage> _child; // The filter is not owned by us. const MatchExpression* _filter; @@ -104,7 +99,6 @@ private: WorkingSetID _idRetrying; // Stats - CommonStats _commonStats; FetchStats _specificStats; }; diff --git a/src/mongo/db/exec/geo_near.cpp b/src/mongo/db/exec/geo_near.cpp index 7eaeeac9f9a..db54e778da7 100644 --- a/src/mongo/db/exec/geo_near.cpp +++ b/src/mongo/db/exec/geo_near.cpp @@ -259,8 +259,10 @@ static R2Annulus twoDDistanceBounds(const GeoNearParams& nearParams, class GeoNear2DStage::DensityEstimator { public: - DensityEstimator(const IndexDescriptor* twoDindex, const GeoNearParams* nearParams) - : _twoDIndex(twoDindex), _nearParams(nearParams), _currentLevel(0) { + DensityEstimator(PlanStage::Children* children, + const IndexDescriptor* twoDindex, + const GeoNearParams* nearParams) + : _children(children), _twoDIndex(twoDindex), _nearParams(nearParams), _currentLevel(0) { GeoHashConverter::Parameters hashParams; Status status = GeoHashConverter::parseParameters(_twoDIndex->infoObj(), &hashParams); // The index status should always be valid. @@ -281,16 +283,13 @@ public: WorkingSetID* out, double* estimatedDistance); - void saveState(); - void restoreState(OperationContext* txn); - void invalidate(OperationContext* txn, const RecordId& dl, InvalidationType type); - private: void buildIndexScan(OperationContext* txn, WorkingSet* workingSet, Collection* collection); + PlanStage::Children* _children; // Points to PlanStage::_children in the NearStage. const IndexDescriptor* _twoDIndex; // Not owned here. const GeoNearParams* _nearParams; // Not owned here. - unique_ptr<IndexScan> _indexScan; + IndexScan* _indexScan = nullptr; // Owned in PlanStage::_children. unique_ptr<GeoHashConverter> _converter; GeoHash _centroidCell; unsigned _currentLevel; @@ -335,7 +334,9 @@ void GeoNear2DStage::DensityEstimator::buildIndexScan(OperationContext* txn, // in the scan (i.e. $within) IndexBoundsBuilder::intersectize(oil, &scanParams.bounds.fields[twoDFieldPosition]); - _indexScan.reset(new IndexScan(txn, scanParams, workingSet, NULL)); + invariant(!_indexScan); + _indexScan = new IndexScan(txn, scanParams, workingSet, NULL); + _children->emplace_back(_indexScan); } // Return IS_EOF is we find a document in it's ancestor cells and set estimated distance @@ -359,7 +360,9 @@ PlanStage::StageState GeoNear2DStage::DensityEstimator::work(OperationContext* t // Advance to the next level and search again. _currentLevel--; // Reset index scan for the next level. - _indexScan.reset(NULL); + invariant(_children->back().get() == _indexScan); + _indexScan = nullptr; + _children->pop_back(); return PlanStage::NEED_TIME; } @@ -380,33 +383,12 @@ PlanStage::StageState GeoNear2DStage::DensityEstimator::work(OperationContext* t return state; } -void GeoNear2DStage::DensityEstimator::saveState() { - if (_indexScan) { - _indexScan->saveState(); - } -} - -void GeoNear2DStage::DensityEstimator::restoreState(OperationContext* txn) { - if (_indexScan) { - _indexScan->restoreState(txn); - } -} - -void GeoNear2DStage::DensityEstimator::invalidate(OperationContext* txn, - const RecordId& dl, - InvalidationType type) { - if (_indexScan) { - _indexScan->invalidate(txn, dl, type); - } -} - - PlanStage::StageState GeoNear2DStage::initialize(OperationContext* txn, WorkingSet* workingSet, Collection* collection, WorkingSetID* out) { if (!_densityEstimator) { - _densityEstimator.reset(new DensityEstimator(_twoDIndex, &_nearParams)); + _densityEstimator.reset(new DensityEstimator(&_children, _twoDIndex, &_nearParams)); } double estimatedDistance; @@ -451,40 +433,16 @@ GeoNear2DStage::GeoNear2DStage(const GeoNearParams& nearParams, WorkingSet* workingSet, Collection* collection, IndexDescriptor* twoDIndex) - : NearStage(txn, - workingSet, - collection, - new PlanStageStats(CommonStats(kTwoDIndexNearStage.c_str()), STAGE_GEO_NEAR_2D)), + : NearStage(txn, kTwoDIndexNearStage.c_str(), STAGE_GEO_NEAR_2D, workingSet, collection), _nearParams(nearParams), _twoDIndex(twoDIndex), _fullBounds(twoDDistanceBounds(nearParams, twoDIndex)), _currBounds(_fullBounds.center(), -1, _fullBounds.getInner()), _boundsIncrement(0.0) { - getNearStats()->keyPattern = twoDIndex->keyPattern(); - getNearStats()->indexName = twoDIndex->indexName(); + _specificStats.keyPattern = twoDIndex->keyPattern(); + _specificStats.indexName = twoDIndex->indexName(); } -GeoNear2DStage::~GeoNear2DStage() {} - -void GeoNear2DStage::finishSaveState() { - if (_densityEstimator) { - _densityEstimator->saveState(); - } -} - -void GeoNear2DStage::finishRestoreState(OperationContext* txn) { - if (_densityEstimator) { - _densityEstimator->restoreState(txn); - } -} - -void GeoNear2DStage::finishInvalidate(OperationContext* txn, - const RecordId& dl, - InvalidationType type) { - if (_densityEstimator) { - _densityEstimator->invalidate(txn, dl, type); - } -} namespace { @@ -665,10 +623,8 @@ StatusWith<NearStage::CoveredInterval*> // // Setup the next interval // - const NearStats* stats = getNearStats(); - - if (!stats->intervalStats.empty()) { - const IntervalStats& lastIntervalStats = stats->intervalStats.back(); + if (!_specificStats.intervalStats.empty()) { + const IntervalStats& lastIntervalStats = _specificStats.intervalStats.back(); // TODO: Generally we want small numbers of results fast, then larger numbers later if (lastIntervalStats.numResultsBuffered < 300) @@ -805,10 +761,13 @@ StatusWith<NearStage::CoveredInterval*> // } // FetchStage owns index scan - FetchStage* fetcher(new FetchStageWithMatch(txn, workingSet, scan, docMatcher, collection)); + _children.emplace_back(new FetchStageWithMatch(txn, workingSet, scan, docMatcher, collection)); - return StatusWith<CoveredInterval*>(new CoveredInterval( - fetcher, true, nextBounds.getInner(), nextBounds.getOuter(), isLastInterval)); + return StatusWith<CoveredInterval*>(new CoveredInterval(_children.back().get(), + true, + nextBounds.getInner(), + nextBounds.getOuter(), + isLastInterval)); } StatusWith<double> GeoNear2DStage::computeDistance(WorkingSetMember* member) { @@ -843,18 +802,14 @@ GeoNear2DSphereStage::GeoNear2DSphereStage(const GeoNearParams& nearParams, WorkingSet* workingSet, Collection* collection, IndexDescriptor* s2Index) - : NearStage( - txn, - workingSet, - collection, - new PlanStageStats(CommonStats(kS2IndexNearStage.c_str()), STAGE_GEO_NEAR_2DSPHERE)), + : NearStage(txn, kS2IndexNearStage.c_str(), STAGE_GEO_NEAR_2DSPHERE, workingSet, collection), _nearParams(nearParams), _s2Index(s2Index), _fullBounds(geoNearDistanceBounds(*nearParams.nearQuery)), _currBounds(_fullBounds.center(), -1, _fullBounds.getInner()), _boundsIncrement(0.0) { - getNearStats()->keyPattern = s2Index->keyPattern(); - getNearStats()->indexName = s2Index->indexName(); + _specificStats.keyPattern = s2Index->keyPattern(); + _specificStats.indexName = s2Index->indexName(); } GeoNear2DSphereStage::~GeoNear2DSphereStage() {} @@ -940,8 +895,10 @@ private: // Estimate the density of data by search the nearest cells level by level around center. class GeoNear2DSphereStage::DensityEstimator { public: - DensityEstimator(const IndexDescriptor* s2Index, const GeoNearParams* nearParams) - : _s2Index(s2Index), _nearParams(nearParams), _currentLevel(0) { + DensityEstimator(PlanStage::Children* children, + const IndexDescriptor* s2Index, + const GeoNearParams* nearParams) + : _children(children), _s2Index(s2Index), _nearParams(nearParams), _currentLevel(0) { S2IndexingParams params; ExpressionParams::parse2dsphereParams(_s2Index->infoObj(), ¶ms); // Since cellId.AppendVertexNeighbors(level, output) requires level < cellId.level(), @@ -959,17 +916,14 @@ public: WorkingSetID* out, double* estimatedDistance); - void saveState(); - void restoreState(OperationContext* txn); - void invalidate(OperationContext* txn, const RecordId& dl, InvalidationType type); - private: void buildIndexScan(OperationContext* txn, WorkingSet* workingSet, Collection* collection); + PlanStage::Children* _children; // Points to PlanStage::_children in the NearStage. const IndexDescriptor* _s2Index; // Not owned here. const GeoNearParams* _nearParams; // Not owned here. int _currentLevel; - unique_ptr<IndexScan> _indexScan; + IndexScan* _indexScan = nullptr; // Owned in PlanStage::_children. }; // Setup the index scan stage for neighbors at this level. @@ -1016,7 +970,9 @@ void GeoNear2DSphereStage::DensityEstimator::buildIndexScan(OperationContext* tx invariant(coveredIntervals->isValidFor(1)); // Index scan - _indexScan.reset(new IndexScan(txn, scanParams, workingSet, NULL)); + invariant(!_indexScan); + _indexScan = new IndexScan(txn, scanParams, workingSet, NULL); + _children->emplace_back(_indexScan); } PlanStage::StageState GeoNear2DSphereStage::DensityEstimator::work(OperationContext* txn, @@ -1038,7 +994,9 @@ PlanStage::StageState GeoNear2DSphereStage::DensityEstimator::work(OperationCont // Advance to the next level and search again. _currentLevel--; // Reset index scan for the next level. - _indexScan.reset(NULL); + invariant(_children->back().get() == _indexScan); + _indexScan = nullptr; + _children->pop_back(); return PlanStage::NEED_TIME; } @@ -1059,33 +1017,13 @@ PlanStage::StageState GeoNear2DSphereStage::DensityEstimator::work(OperationCont return state; } -void GeoNear2DSphereStage::DensityEstimator::saveState() { - if (_indexScan) { - _indexScan->saveState(); - } -} - -void GeoNear2DSphereStage::DensityEstimator::restoreState(OperationContext* txn) { - if (_indexScan) { - _indexScan->restoreState(txn); - } -} - -void GeoNear2DSphereStage::DensityEstimator::invalidate(OperationContext* txn, - const RecordId& dl, - InvalidationType type) { - if (_indexScan) { - _indexScan->invalidate(txn, dl, type); - } -} - PlanStage::StageState GeoNear2DSphereStage::initialize(OperationContext* txn, WorkingSet* workingSet, Collection* collection, WorkingSetID* out) { if (!_densityEstimator) { - _densityEstimator.reset(new DensityEstimator(_s2Index, &_nearParams)); + _densityEstimator.reset(new DensityEstimator(&_children, _s2Index, &_nearParams)); } double estimatedDistance; @@ -1110,26 +1048,6 @@ PlanStage::StageState GeoNear2DSphereStage::initialize(OperationContext* txn, return state; } -void GeoNear2DSphereStage::finishSaveState() { - if (_densityEstimator) { - _densityEstimator->saveState(); - } -} - -void GeoNear2DSphereStage::finishRestoreState(OperationContext* txn) { - if (_densityEstimator) { - _densityEstimator->restoreState(txn); - } -} - -void GeoNear2DSphereStage::finishInvalidate(OperationContext* txn, - const RecordId& dl, - InvalidationType type) { - if (_densityEstimator) { - _densityEstimator->invalidate(txn, dl, type); - } -} - StatusWith<NearStage::CoveredInterval*> // GeoNear2DSphereStage::nextInterval(OperationContext* txn, WorkingSet* workingSet, @@ -1143,10 +1061,8 @@ StatusWith<NearStage::CoveredInterval*> // // Setup the next interval // - const NearStats* stats = getNearStats(); - - if (!stats->intervalStats.empty()) { - const IntervalStats& lastIntervalStats = stats->intervalStats.back(); + if (!_specificStats.intervalStats.empty()) { + const IntervalStats& lastIntervalStats = _specificStats.intervalStats.back(); // TODO: Generally we want small numbers of results fast, then larger numbers later if (lastIntervalStats.numResultsBuffered < 300) @@ -1196,10 +1112,13 @@ StatusWith<NearStage::CoveredInterval*> // IndexScan* scan = new IndexScanWithMatch(txn, scanParams, workingSet, keyMatcher); // FetchStage owns index scan - FetchStage* fetcher(new FetchStage(txn, workingSet, scan, _nearParams.filter, collection)); + _children.emplace_back(new FetchStage(txn, workingSet, scan, _nearParams.filter, collection)); - return StatusWith<CoveredInterval*>(new CoveredInterval( - fetcher, true, nextBounds.getInner(), nextBounds.getOuter(), isLastInterval)); + return StatusWith<CoveredInterval*>(new CoveredInterval(_children.back().get(), + true, + nextBounds.getInner(), + nextBounds.getOuter(), + isLastInterval)); } StatusWith<double> GeoNear2DSphereStage::computeDistance(WorkingSetMember* member) { diff --git a/src/mongo/db/exec/geo_near.h b/src/mongo/db/exec/geo_near.h index f9295217992..06b25ad27b7 100644 --- a/src/mongo/db/exec/geo_near.h +++ b/src/mongo/db/exec/geo_near.h @@ -69,8 +69,6 @@ public: Collection* collection, IndexDescriptor* twoDIndex); - virtual ~GeoNear2DStage(); - protected: virtual StatusWith<CoveredInterval*> nextInterval(OperationContext* txn, WorkingSet* workingSet, @@ -84,12 +82,6 @@ protected: WorkingSetID* out); private: - virtual void finishSaveState(); - - virtual void finishRestoreState(OperationContext* txn); - - virtual void finishInvalidate(OperationContext* txn, const RecordId& dl, InvalidationType type); - const GeoNearParams _nearParams; // The 2D index we're searching over @@ -135,12 +127,6 @@ protected: WorkingSetID* out); private: - virtual void finishSaveState(); - - virtual void finishRestoreState(OperationContext* txn); - - virtual void finishInvalidate(OperationContext* txn, const RecordId& dl, InvalidationType type); - const GeoNearParams _nearParams; // The 2D index we're searching over diff --git a/src/mongo/db/exec/group.cpp b/src/mongo/db/exec/group.cpp index 8c945ef11d0..a3049a1f787 100644 --- a/src/mongo/db/exec/group.cpp +++ b/src/mongo/db/exec/group.cpp @@ -77,15 +77,16 @@ GroupStage::GroupStage(OperationContext* txn, const GroupRequest& request, WorkingSet* workingSet, PlanStage* child) - : _txn(txn), + : PlanStage(kStageType), + _txn(txn), _request(request), _ws(workingSet), - _commonStats(kStageType), _specificStats(), - _child(child), _groupState(GroupState_Initializing), _reduceFunction(0), - _keyFunction(0) {} + _keyFunction(0) { + _children.emplace_back(child); +} void GroupStage::initGroupScripting() { // Initialize _scope. @@ -196,7 +197,7 @@ PlanStage::StageState GroupStage::work(WorkingSetID* out) { // Otherwise, read from our child. invariant(_groupState == GroupState_ReadingFromChild); WorkingSetID id = WorkingSet::INVALID_ID; - StageState state = _child->work(&id); + StageState state = child()->work(&id); if (PlanStage::NEED_TIME == state) { ++_commonStats.needTime; @@ -256,42 +257,18 @@ bool GroupStage::isEOF() { return _groupState == GroupState_Done; } -void GroupStage::saveState() { - _txn = NULL; - ++_commonStats.yields; - _child->saveState(); -} - -void GroupStage::restoreState(OperationContext* opCtx) { - invariant(_txn == NULL); +void GroupStage::doRestoreState(OperationContext* opCtx) { _txn = opCtx; - ++_commonStats.unyields; - _child->restoreState(opCtx); -} - -void GroupStage::invalidate(OperationContext* txn, const RecordId& dl, InvalidationType type) { - ++_commonStats.invalidates; - _child->invalidate(txn, dl, type); -} - -vector<PlanStage*> GroupStage::getChildren() const { - vector<PlanStage*> children; - children.push_back(_child.get()); - return children; } unique_ptr<PlanStageStats> GroupStage::getStats() { _commonStats.isEOF = isEOF(); unique_ptr<PlanStageStats> ret = make_unique<PlanStageStats>(_commonStats, STAGE_GROUP); ret->specific = make_unique<GroupStats>(_specificStats); - ret->children.push_back(_child->getStats().release()); + ret->children.push_back(child()->getStats().release()); return ret; } -const CommonStats* GroupStage::getCommonStats() const { - return &_commonStats; -} - const SpecificStats* GroupStage::getSpecificStats() const { return &_specificStats; } diff --git a/src/mongo/db/exec/group.h b/src/mongo/db/exec/group.h index 6b7c0fd229c..7f282fce25c 100644 --- a/src/mongo/db/exec/group.h +++ b/src/mongo/db/exec/group.h @@ -90,11 +90,7 @@ public: virtual StageState work(WorkingSetID* out); virtual bool isEOF(); - virtual void saveState(); - virtual void restoreState(OperationContext* opCtx); - virtual void invalidate(OperationContext* txn, const RecordId& dl, InvalidationType type); - - virtual std::vector<PlanStage*> getChildren() const; + virtual void doRestoreState(OperationContext* opCtx); virtual StageType stageType() const { return STAGE_GROUP; @@ -102,8 +98,6 @@ public: virtual std::unique_ptr<PlanStageStats> getStats(); - virtual const CommonStats* getCommonStats() const; - virtual const SpecificStats* getSpecificStats() const; static const char* kStageType; @@ -143,11 +137,8 @@ private: // The WorkingSet we annotate with results. Not owned by us. WorkingSet* _ws; - CommonStats _commonStats; GroupStats _specificStats; - std::unique_ptr<PlanStage> _child; - // Current state for this stage. GroupState _groupState; diff --git a/src/mongo/db/exec/idhack.cpp b/src/mongo/db/exec/idhack.cpp index 8e9e290b624..2d9a67cfa4f 100644 --- a/src/mongo/db/exec/idhack.cpp +++ b/src/mongo/db/exec/idhack.cpp @@ -54,13 +54,13 @@ IDHackStage::IDHackStage(OperationContext* txn, const Collection* collection, CanonicalQuery* query, WorkingSet* ws) - : _txn(txn), + : PlanStage(kStageType), + _txn(txn), _collection(collection), _workingSet(ws), _key(query->getQueryObj()["_id"].wrap()), _done(false), - _idBeingPagedIn(WorkingSet::INVALID_ID), - _commonStats(kStageType) { + _idBeingPagedIn(WorkingSet::INVALID_ID) { if (NULL != query->getProj()) { _addKeyMetadata = query->getProj()->wantIndexKey(); } else { @@ -72,14 +72,14 @@ IDHackStage::IDHackStage(OperationContext* txn, Collection* collection, const BSONObj& key, WorkingSet* ws) - : _txn(txn), + : PlanStage(kStageType), + _txn(txn), _collection(collection), _workingSet(ws), _key(key), _done(false), _addKeyMetadata(false), - _idBeingPagedIn(WorkingSet::INVALID_ID), - _commonStats(kStageType) {} + _idBeingPagedIn(WorkingSet::INVALID_ID) {} IDHackStage::~IDHackStage() {} @@ -199,24 +199,20 @@ PlanStage::StageState IDHackStage::advance(WorkingSetID id, return PlanStage::ADVANCED; } -void IDHackStage::saveState() { +void IDHackStage::doSaveState() { _txn = NULL; - ++_commonStats.yields; if (_recordCursor) _recordCursor->saveUnpositioned(); } -void IDHackStage::restoreState(OperationContext* opCtx) { +void IDHackStage::doRestoreState(OperationContext* opCtx) { invariant(_txn == NULL); _txn = opCtx; - ++_commonStats.unyields; if (_recordCursor) _recordCursor->restore(opCtx); } -void IDHackStage::invalidate(OperationContext* txn, const RecordId& dl, InvalidationType type) { - ++_commonStats.invalidates; - +void IDHackStage::doInvalidate(OperationContext* txn, const RecordId& dl, InvalidationType type) { // Since updates can't mutate the '_id' field, we can ignore mutation invalidations. if (INVALIDATION_MUTATION == type) { return; @@ -241,11 +237,6 @@ bool IDHackStage::supportsQuery(const CanonicalQuery& query) { !query.getParsed().isTailable(); } -vector<PlanStage*> IDHackStage::getChildren() const { - vector<PlanStage*> empty; - return empty; -} - unique_ptr<PlanStageStats> IDHackStage::getStats() { _commonStats.isEOF = isEOF(); unique_ptr<PlanStageStats> ret = make_unique<PlanStageStats>(_commonStats, STAGE_IDHACK); @@ -253,10 +244,6 @@ unique_ptr<PlanStageStats> IDHackStage::getStats() { return ret; } -const CommonStats* IDHackStage::getCommonStats() const { - return &_commonStats; -} - const SpecificStats* IDHackStage::getSpecificStats() const { return &_specificStats; } diff --git a/src/mongo/db/exec/idhack.h b/src/mongo/db/exec/idhack.h index 5377d83b643..52446c064e2 100644 --- a/src/mongo/db/exec/idhack.h +++ b/src/mongo/db/exec/idhack.h @@ -58,25 +58,21 @@ public: virtual bool isEOF(); virtual StageState work(WorkingSetID* out); - virtual void saveState(); - virtual void restoreState(OperationContext* opCtx); - virtual void invalidate(OperationContext* txn, const RecordId& dl, InvalidationType type); + virtual void doSaveState(); + virtual void doRestoreState(OperationContext* opCtx); + virtual void doInvalidate(OperationContext* txn, const RecordId& dl, InvalidationType type); /** * ID Hack has a very strict criteria for the queries it supports. */ static bool supportsQuery(const CanonicalQuery& query); - virtual std::vector<PlanStage*> getChildren() const; - virtual StageType stageType() const { return STAGE_IDHACK; } std::unique_ptr<PlanStageStats> getStats(); - virtual const CommonStats* getCommonStats() const; - virtual const SpecificStats* getSpecificStats() const; static const char* kStageType; @@ -115,7 +111,6 @@ private: // the fetch request. WorkingSetID _idBeingPagedIn; - CommonStats _commonStats; IDHackStats _specificStats; }; diff --git a/src/mongo/db/exec/index_scan.cpp b/src/mongo/db/exec/index_scan.cpp index e994404960a..34f93786b6f 100644 --- a/src/mongo/db/exec/index_scan.cpp +++ b/src/mongo/db/exec/index_scan.cpp @@ -62,7 +62,8 @@ IndexScan::IndexScan(OperationContext* txn, const IndexScanParams& params, WorkingSet* workingSet, const MatchExpression* filter) - : _txn(txn), + : PlanStage(kStageType), + _txn(txn), _workingSet(workingSet), _iam(params.descriptor->getIndexCatalog()->getIndex(params.descriptor)), _keyPattern(params.descriptor->keyPattern().getOwned()), @@ -71,7 +72,6 @@ IndexScan::IndexScan(OperationContext* txn, _shouldDedup(true), _forward(params.direction == 1), _params(params), - _commonStats(kStageType), _endKeyInclusive(false) { // We can't always access the descriptor in the call to getStats() so we pull // any info we need for stats reporting out here. @@ -233,14 +233,13 @@ bool IndexScan::isEOF() { return _commonStats.isEOF; } -void IndexScan::saveState() { +void IndexScan::doSaveState() { if (!_txn) { // We were already saved. Nothing to do. return; } - _txn = NULL; - ++_commonStats.yields; + if (!_indexCursor) return; @@ -252,18 +251,14 @@ void IndexScan::saveState() { _indexCursor->savePositioned(); } -void IndexScan::restoreState(OperationContext* opCtx) { +void IndexScan::doRestoreState(OperationContext* opCtx) { invariant(_txn == NULL); _txn = opCtx; - ++_commonStats.unyields; - if (_indexCursor) _indexCursor->restore(opCtx); } -void IndexScan::invalidate(OperationContext* txn, const RecordId& dl, InvalidationType type) { - ++_commonStats.invalidates; - +void IndexScan::doInvalidate(OperationContext* txn, const RecordId& dl, InvalidationType type) { // The only state we're responsible for holding is what RecordIds to drop. If a document // mutates the underlying index cursor will deal with it. if (INVALIDATION_MUTATION == type) { @@ -279,10 +274,6 @@ void IndexScan::invalidate(OperationContext* txn, const RecordId& dl, Invalidati } } -std::vector<PlanStage*> IndexScan::getChildren() const { - return {}; -} - std::unique_ptr<PlanStageStats> IndexScan::getStats() { // WARNING: this could be called even if the collection was dropped. Do not access any // catalog information here. @@ -309,10 +300,6 @@ std::unique_ptr<PlanStageStats> IndexScan::getStats() { return ret; } -const CommonStats* IndexScan::getCommonStats() const { - return &_commonStats; -} - const SpecificStats* IndexScan::getSpecificStats() const { return &_specificStats; } diff --git a/src/mongo/db/exec/index_scan.h b/src/mongo/db/exec/index_scan.h index fded244ff9e..d1a721588ac 100644 --- a/src/mongo/db/exec/index_scan.h +++ b/src/mongo/db/exec/index_scan.h @@ -99,11 +99,9 @@ public: virtual StageState work(WorkingSetID* out); virtual bool isEOF(); - virtual void saveState(); - virtual void restoreState(OperationContext* opCtx); - virtual void invalidate(OperationContext* txn, const RecordId& dl, InvalidationType type); - - virtual std::vector<PlanStage*> getChildren() const; + virtual void doSaveState(); + virtual void doRestoreState(OperationContext* opCtx); + virtual void doInvalidate(OperationContext* txn, const RecordId& dl, InvalidationType type); virtual StageType stageType() const { return STAGE_IXSCAN; @@ -111,8 +109,6 @@ public: virtual std::unique_ptr<PlanStageStats> getStats(); - virtual const CommonStats* getCommonStats() const; - virtual const SpecificStats* getSpecificStats() const; static const char* kStageType; @@ -150,7 +146,6 @@ private: const IndexScanParams _params; // Stats - CommonStats _commonStats; IndexScanStats _specificStats; // diff --git a/src/mongo/db/exec/keep_mutations.cpp b/src/mongo/db/exec/keep_mutations.cpp index 099052149ba..2770c2b25d3 100644 --- a/src/mongo/db/exec/keep_mutations.cpp +++ b/src/mongo/db/exec/keep_mutations.cpp @@ -44,12 +44,13 @@ const char* KeepMutationsStage::kStageType = "KEEP_MUTATIONS"; KeepMutationsStage::KeepMutationsStage(const MatchExpression* filter, WorkingSet* ws, PlanStage* child) - : _workingSet(ws), - _child(child), + : PlanStage(kStageType), + _workingSet(ws), _filter(filter), _doneReadingChild(false), - _doneReturningFlagged(false), - _commonStats(kStageType) {} + _doneReturningFlagged(false) { + _children.emplace_back(child); +} KeepMutationsStage::~KeepMutationsStage() {} @@ -70,7 +71,7 @@ PlanStage::StageState KeepMutationsStage::work(WorkingSetID* out) { // Stream child results until the child is all done. if (!_doneReadingChild) { - StageState status = _child->work(out); + StageState status = child()->work(out); // Child is still returning results. Pass them through. if (PlanStage::IS_EOF != status) { @@ -119,41 +120,14 @@ PlanStage::StageState KeepMutationsStage::work(WorkingSetID* out) { } } -void KeepMutationsStage::saveState() { - ++_commonStats.yields; - _child->saveState(); -} - -void KeepMutationsStage::restoreState(OperationContext* opCtx) { - ++_commonStats.unyields; - _child->restoreState(opCtx); -} - -void KeepMutationsStage::invalidate(OperationContext* txn, - const RecordId& dl, - InvalidationType type) { - ++_commonStats.invalidates; - _child->invalidate(txn, dl, type); -} - -vector<PlanStage*> KeepMutationsStage::getChildren() const { - vector<PlanStage*> children; - children.push_back(_child.get()); - return children; -} - unique_ptr<PlanStageStats> KeepMutationsStage::getStats() { _commonStats.isEOF = isEOF(); unique_ptr<PlanStageStats> ret = make_unique<PlanStageStats>(_commonStats, STAGE_KEEP_MUTATIONS); - ret->children.push_back(_child->getStats().release()); + ret->children.push_back(child()->getStats().release()); return ret; } -const CommonStats* KeepMutationsStage::getCommonStats() const { - return &_commonStats; -} - const SpecificStats* KeepMutationsStage::getSpecificStats() const { return NULL; } diff --git a/src/mongo/db/exec/keep_mutations.h b/src/mongo/db/exec/keep_mutations.h index 8915d363971..d76ba32dac8 100644 --- a/src/mongo/db/exec/keep_mutations.h +++ b/src/mongo/db/exec/keep_mutations.h @@ -52,20 +52,12 @@ public: virtual bool isEOF(); virtual StageState work(WorkingSetID* out); - virtual void saveState(); - virtual void restoreState(OperationContext* opCtx); - virtual void invalidate(OperationContext* txn, const RecordId& dl, InvalidationType type); - - virtual std::vector<PlanStage*> getChildren() const; - virtual StageType stageType() const { return STAGE_KEEP_MUTATIONS; } virtual std::unique_ptr<PlanStageStats> getStats(); - virtual const CommonStats* getCommonStats() const; - virtual const SpecificStats* getSpecificStats() const; static const char* kStageType; @@ -74,8 +66,6 @@ private: // Not owned here. WorkingSet* _workingSet; - std::unique_ptr<PlanStage> _child; - // Not owned here. Should be the full query expression tree. const MatchExpression* _filter; @@ -86,9 +76,6 @@ private: // stream. bool _doneReturningFlagged; - // Stats. - CommonStats _commonStats; - // Our copy of the working set's flagged results. std::vector<WorkingSetID> _flagged; diff --git a/src/mongo/db/exec/limit.cpp b/src/mongo/db/exec/limit.cpp index 06566149cd8..a2c1d73b399 100644 --- a/src/mongo/db/exec/limit.cpp +++ b/src/mongo/db/exec/limit.cpp @@ -43,14 +43,15 @@ using stdx::make_unique; const char* LimitStage::kStageType = "LIMIT"; LimitStage::LimitStage(long long limit, WorkingSet* ws, PlanStage* child) - : _ws(ws), _child(child), _numToReturn(limit), _commonStats(kStageType) { + : PlanStage(kStageType), _ws(ws), _numToReturn(limit) { _specificStats.limit = _numToReturn; + _children.emplace_back(child); } LimitStage::~LimitStage() {} bool LimitStage::isEOF() { - return (0 == _numToReturn) || _child->isEOF(); + return (0 == _numToReturn) || child()->isEOF(); } PlanStage::StageState LimitStage::work(WorkingSetID* out) { @@ -65,7 +66,7 @@ PlanStage::StageState LimitStage::work(WorkingSetID* out) { } WorkingSetID id = WorkingSet::INVALID_ID; - StageState status = _child->work(&id); + StageState status = child()->work(&id); if (PlanStage::ADVANCED == status) { *out = id; @@ -94,39 +95,14 @@ PlanStage::StageState LimitStage::work(WorkingSetID* out) { return status; } -void LimitStage::saveState() { - ++_commonStats.yields; - _child->saveState(); -} - -void LimitStage::restoreState(OperationContext* opCtx) { - ++_commonStats.unyields; - _child->restoreState(opCtx); -} - -void LimitStage::invalidate(OperationContext* txn, const RecordId& dl, InvalidationType type) { - ++_commonStats.invalidates; - _child->invalidate(txn, dl, type); -} - -vector<PlanStage*> LimitStage::getChildren() const { - vector<PlanStage*> children; - children.push_back(_child.get()); - return children; -} - unique_ptr<PlanStageStats> LimitStage::getStats() { _commonStats.isEOF = isEOF(); unique_ptr<PlanStageStats> ret = make_unique<PlanStageStats>(_commonStats, STAGE_LIMIT); ret->specific = make_unique<LimitStats>(_specificStats); - ret->children.push_back(_child->getStats().release()); + ret->children.push_back(child()->getStats().release()); return ret; } -const CommonStats* LimitStage::getCommonStats() const { - return &_commonStats; -} - const SpecificStats* LimitStage::getSpecificStats() const { return &_specificStats; } diff --git a/src/mongo/db/exec/limit.h b/src/mongo/db/exec/limit.h index 26894b7479f..33af499d5f8 100644 --- a/src/mongo/db/exec/limit.h +++ b/src/mongo/db/exec/limit.h @@ -50,33 +50,23 @@ public: virtual bool isEOF(); virtual StageState work(WorkingSetID* out); - virtual void saveState(); - virtual void restoreState(OperationContext* opCtx); - virtual void invalidate(OperationContext* txn, const RecordId& dl, InvalidationType type); - - virtual std::vector<PlanStage*> getChildren() const; - virtual StageType stageType() const { return STAGE_LIMIT; } virtual std::unique_ptr<PlanStageStats> getStats(); - virtual const CommonStats* getCommonStats() const; - virtual const SpecificStats* getSpecificStats() const; static const char* kStageType; private: WorkingSet* _ws; - std::unique_ptr<PlanStage> _child; // We only return this many results. long long _numToReturn; // Stats - CommonStats _commonStats; LimitStats _specificStats; }; diff --git a/src/mongo/db/exec/merge_sort.cpp b/src/mongo/db/exec/merge_sort.cpp index a710171975a..5bf7db4b9ea 100644 --- a/src/mongo/db/exec/merge_sort.cpp +++ b/src/mongo/db/exec/merge_sort.cpp @@ -48,21 +48,15 @@ const char* MergeSortStage::kStageType = "SORT_MERGE"; MergeSortStage::MergeSortStage(const MergeSortStageParams& params, WorkingSet* ws, const Collection* collection) - : _collection(collection), + : PlanStage(kStageType), + _collection(collection), _ws(ws), _pattern(params.pattern), _dedup(params.dedup), - _merging(StageWithValueComparison(ws, params.pattern)), - _commonStats(kStageType) {} - -MergeSortStage::~MergeSortStage() { - for (size_t i = 0; i < _children.size(); ++i) { - delete _children[i]; - } -} + _merging(StageWithValueComparison(ws, params.pattern)) {} void MergeSortStage::addChild(PlanStage* child) { - _children.push_back(child); + _children.emplace_back(child); // We have to call work(...) on every child before we can pick a min. _noResultToMerge.push(child); @@ -191,26 +185,10 @@ PlanStage::StageState MergeSortStage::work(WorkingSetID* out) { return PlanStage::ADVANCED; } -void MergeSortStage::saveState() { - ++_commonStats.yields; - for (size_t i = 0; i < _children.size(); ++i) { - _children[i]->saveState(); - } -} - -void MergeSortStage::restoreState(OperationContext* opCtx) { - ++_commonStats.unyields; - for (size_t i = 0; i < _children.size(); ++i) { - _children[i]->restoreState(opCtx); - } -} - -void MergeSortStage::invalidate(OperationContext* txn, const RecordId& dl, InvalidationType type) { - ++_commonStats.invalidates; - for (size_t i = 0; i < _children.size(); ++i) { - _children[i]->invalidate(txn, dl, type); - } +void MergeSortStage::doInvalidate(OperationContext* txn, + const RecordId& dl, + InvalidationType type) { // Go through our data and see if we're holding on to the invalidated loc. for (list<StageWithValue>::iterator valueIt = _mergingData.begin(); valueIt != _mergingData.end(); @@ -265,10 +243,6 @@ bool MergeSortStage::StageWithValueComparison::operator()(const MergingRef& lhs, return false; } -vector<PlanStage*> MergeSortStage::getChildren() const { - return _children; -} - unique_ptr<PlanStageStats> MergeSortStage::getStats() { _commonStats.isEOF = isEOF(); @@ -282,10 +256,6 @@ unique_ptr<PlanStageStats> MergeSortStage::getStats() { return ret; } -const CommonStats* MergeSortStage::getCommonStats() const { - return &_commonStats; -} - const SpecificStats* MergeSortStage::getSpecificStats() const { return &_specificStats; } diff --git a/src/mongo/db/exec/merge_sort.h b/src/mongo/db/exec/merge_sort.h index 3a2700002a5..51114bbd0ca 100644 --- a/src/mongo/db/exec/merge_sort.h +++ b/src/mongo/db/exec/merge_sort.h @@ -58,18 +58,13 @@ public: MergeSortStage(const MergeSortStageParams& params, WorkingSet* ws, const Collection* collection); - virtual ~MergeSortStage(); void addChild(PlanStage* child); virtual bool isEOF(); virtual StageState work(WorkingSetID* out); - virtual void saveState(); - virtual void restoreState(OperationContext* opCtx); - virtual void invalidate(OperationContext* txn, const RecordId& dl, InvalidationType type); - - virtual std::vector<PlanStage*> getChildren() const; + virtual void doInvalidate(OperationContext* txn, const RecordId& dl, InvalidationType type); virtual StageType stageType() const { return STAGE_SORT_MERGE; @@ -77,8 +72,6 @@ public: std::unique_ptr<PlanStageStats> getStats(); - virtual const CommonStats* getCommonStats() const; - virtual const SpecificStats* getSpecificStats() const; static const char* kStageType; @@ -99,9 +92,6 @@ private: // Which RecordIds have we seen? unordered_set<RecordId, RecordId::Hasher> _seen; - // Owned by us. All the children we're reading from. - std::vector<PlanStage*> _children; - // In order to pick the next smallest value, we need each child work(...) until it produces // a result. This is the queue of children that haven't given us a result yet. std::queue<PlanStage*> _noResultToMerge; @@ -149,7 +139,6 @@ private: std::list<StageWithValue> _mergingData; // Stats - CommonStats _commonStats; MergeSortStats _specificStats; }; diff --git a/src/mongo/db/exec/multi_iterator.cpp b/src/mongo/db/exec/multi_iterator.cpp index 84ba4e76578..f3de28c5e54 100644 --- a/src/mongo/db/exec/multi_iterator.cpp +++ b/src/mongo/db/exec/multi_iterator.cpp @@ -46,7 +46,11 @@ const char* MultiIteratorStage::kStageType = "MULTI_ITERATOR"; MultiIteratorStage::MultiIteratorStage(OperationContext* txn, WorkingSet* ws, Collection* collection) - : _txn(txn), _collection(collection), _ws(ws), _wsidForFetch(_ws->allocate()) {} + : PlanStage(kStageType), + _txn(txn), + _collection(collection), + _ws(ws), + _wsidForFetch(_ws->allocate()) {} void MultiIteratorStage::addIterator(unique_ptr<RecordCursor> it) { _iterators.push_back(std::move(it)); @@ -102,14 +106,14 @@ void MultiIteratorStage::kill() { _iterators.clear(); } -void MultiIteratorStage::saveState() { +void MultiIteratorStage::doSaveState() { _txn = NULL; for (size_t i = 0; i < _iterators.size(); i++) { _iterators[i]->savePositioned(); } } -void MultiIteratorStage::restoreState(OperationContext* opCtx) { +void MultiIteratorStage::doRestoreState(OperationContext* opCtx) { invariant(_txn == NULL); _txn = opCtx; for (size_t i = 0; i < _iterators.size(); i++) { @@ -119,9 +123,9 @@ void MultiIteratorStage::restoreState(OperationContext* opCtx) { } } -void MultiIteratorStage::invalidate(OperationContext* txn, - const RecordId& dl, - InvalidationType type) { +void MultiIteratorStage::doInvalidate(OperationContext* txn, + const RecordId& dl, + InvalidationType type) { switch (type) { case INVALIDATION_DELETION: for (size_t i = 0; i < _iterators.size(); i++) { @@ -134,11 +138,6 @@ void MultiIteratorStage::invalidate(OperationContext* txn, } } -vector<PlanStage*> MultiIteratorStage::getChildren() const { - vector<PlanStage*> empty; - return empty; -} - unique_ptr<PlanStageStats> MultiIteratorStage::getStats() { unique_ptr<PlanStageStats> ret = make_unique<PlanStageStats>(CommonStats(kStageType), STAGE_MULTI_ITERATOR); diff --git a/src/mongo/db/exec/multi_iterator.h b/src/mongo/db/exec/multi_iterator.h index 9fe8f5338c8..a0b16d57515 100644 --- a/src/mongo/db/exec/multi_iterator.h +++ b/src/mongo/db/exec/multi_iterator.h @@ -59,28 +59,19 @@ public: void kill(); - virtual void saveState(); - virtual void restoreState(OperationContext* opCtx); - - virtual void invalidate(OperationContext* txn, const RecordId& dl, InvalidationType type); + virtual void doSaveState(); + virtual void doRestoreState(OperationContext* opCtx); + virtual void doInvalidate(OperationContext* txn, const RecordId& dl, InvalidationType type); // Returns empty PlanStageStats object virtual std::unique_ptr<PlanStageStats> getStats(); // Not used. - virtual CommonStats* getCommonStats() const { - return NULL; - } - - // Not used. virtual SpecificStats* getSpecificStats() const { return NULL; } // Not used. - virtual std::vector<PlanStage*> getChildren() const; - - // Not used. virtual StageType stageType() const { return STAGE_MULTI_ITERATOR; } diff --git a/src/mongo/db/exec/multi_plan.cpp b/src/mongo/db/exec/multi_plan.cpp index 60906acc055..de58312a4b6 100644 --- a/src/mongo/db/exec/multi_plan.cpp +++ b/src/mongo/db/exec/multi_plan.cpp @@ -65,7 +65,8 @@ MultiPlanStage::MultiPlanStage(OperationContext* txn, const Collection* collection, CanonicalQuery* cq, bool shouldCache) - : _txn(txn), + : PlanStage(kStageType), + _txn(txn), _collection(collection), _shouldCache(shouldCache), _query(cq), @@ -73,20 +74,13 @@ MultiPlanStage::MultiPlanStage(OperationContext* txn, _backupPlanIdx(kNoSuchPlan), _failure(false), _failureCount(0), - _statusMemberId(WorkingSet::INVALID_ID), - _commonStats(kStageType) { + _statusMemberId(WorkingSet::INVALID_ID) { invariant(_collection); } -MultiPlanStage::~MultiPlanStage() { - for (size_t ix = 0; ix < _candidates.size(); ++ix) { - delete _candidates[ix].solution; - delete _candidates[ix].root; - } -} - void MultiPlanStage::addPlan(QuerySolution* solution, PlanStage* root, WorkingSet* ws) { _candidates.push_back(CandidatePlan(solution, root, ws)); + _children.emplace_back(root); } bool MultiPlanStage::isEOF() { @@ -255,7 +249,7 @@ Status MultiPlanStage::pickBestPlan(PlanYieldPolicy* yieldPolicy) { CandidatePlan& bestCandidate = _candidates[_bestPlanIdx]; std::list<WorkingSetID>& alreadyProduced = bestCandidate.results; - QuerySolution* bestSolution = bestCandidate.solution; + const auto& bestSolution = bestCandidate.solution; LOG(5) << "Winning solution:\n" << bestSolution->toString() << endl; LOG(2) << "Winning plan: " << Explain::getPlanSummary(bestCandidate.root); @@ -283,7 +277,7 @@ Status MultiPlanStage::pickBestPlan(PlanYieldPolicy* yieldPolicy) { for (size_t orderingIndex = 0; orderingIndex < candidateOrder.size(); ++orderingIndex) { // index into candidates/ranking size_t ix = candidateOrder[orderingIndex]; - solutions.push_back(_candidates[ix].solution); + solutions.push_back(_candidates[ix].solution.get()); } // Check solution cache data. Do not add to cache if @@ -394,20 +388,8 @@ bool MultiPlanStage::workAllPlans(size_t numResults, PlanYieldPolicy* yieldPolic return !doneWorking; } -void MultiPlanStage::saveState() { - _txn = NULL; - for (size_t i = 0; i < _candidates.size(); ++i) { - _candidates[i].root->saveState(); - } -} - -void MultiPlanStage::restoreState(OperationContext* opCtx) { - invariant(_txn == NULL); +void MultiPlanStage::doRestoreState(OperationContext* opCtx) { _txn = opCtx; - - for (size_t i = 0; i < _candidates.size(); ++i) { - _candidates[i].root->restoreState(opCtx); - } } namespace { @@ -434,23 +416,22 @@ void invalidateHelper(OperationContext* txn, } } -void MultiPlanStage::invalidate(OperationContext* txn, const RecordId& dl, InvalidationType type) { +void MultiPlanStage::doInvalidate(OperationContext* txn, + const RecordId& dl, + InvalidationType type) { if (_failure) { return; } if (bestPlanChosen()) { CandidatePlan& bestPlan = _candidates[_bestPlanIdx]; - bestPlan.root->invalidate(txn, dl, type); invalidateHelper(txn, bestPlan.ws, dl, &bestPlan.results, _collection); if (hasBackupPlan()) { CandidatePlan& backupPlan = _candidates[_backupPlanIdx]; - backupPlan.root->invalidate(txn, dl, type); invalidateHelper(txn, backupPlan.ws, dl, &backupPlan.results, _collection); } } else { for (size_t ix = 0; ix < _candidates.size(); ++ix) { - _candidates[ix].root->invalidate(txn, dl, type); invalidateHelper(txn, _candidates[ix].ws, dl, &_candidates[ix].results, _collection); } } @@ -472,21 +453,7 @@ QuerySolution* MultiPlanStage::bestSolution() { if (_bestPlanIdx == kNoSuchPlan) return NULL; - return _candidates[_bestPlanIdx].solution; -} - -vector<PlanStage*> MultiPlanStage::getChildren() const { - vector<PlanStage*> children; - - if (bestPlanChosen()) { - children.push_back(_candidates[_bestPlanIdx].root); - } else { - for (size_t i = 0; i < _candidates.size(); i++) { - children.push_back(_candidates[i].root); - } - } - - return children; + return _candidates[_bestPlanIdx].solution.get(); } unique_ptr<PlanStageStats> MultiPlanStage::getStats() { @@ -501,10 +468,6 @@ unique_ptr<PlanStageStats> MultiPlanStage::getStats() { return make_unique<PlanStageStats>(_commonStats, STAGE_MULTI_PLAN); } -const CommonStats* MultiPlanStage::getCommonStats() const { - return &_commonStats; -} - const SpecificStats* MultiPlanStage::getSpecificStats() const { return &_specificStats; } diff --git a/src/mongo/db/exec/multi_plan.h b/src/mongo/db/exec/multi_plan.h index 33948ef3f53..669197f648e 100644 --- a/src/mongo/db/exec/multi_plan.h +++ b/src/mongo/db/exec/multi_plan.h @@ -62,19 +62,13 @@ public: CanonicalQuery* cq, bool shouldCache = true); - virtual ~MultiPlanStage(); - virtual bool isEOF(); virtual StageState work(WorkingSetID* out); - virtual void saveState(); - - virtual void restoreState(OperationContext* opCtx); - - virtual void invalidate(OperationContext* txn, const RecordId& dl, InvalidationType type); + virtual void doRestoreState(OperationContext* opCtx); - virtual std::vector<PlanStage*> getChildren() const; + virtual void doInvalidate(OperationContext* txn, const RecordId& dl, InvalidationType type); virtual StageType stageType() const { return STAGE_MULTI_PLAN; @@ -82,7 +76,6 @@ public: virtual std::unique_ptr<PlanStageStats> getStats(); - virtual const CommonStats* getCommonStats() const; virtual const SpecificStats* getSpecificStats() const; @@ -187,9 +180,10 @@ private: // not owned here CanonicalQuery* _query; - // Candidate plans. Each candidate includes a child PlanStage tree and QuerySolution which - // are owned here. Ownership of all QuerySolutions is retained here, and will *not* be - // tranferred to the PlanExecutor that wraps this stage. + // Candidate plans. Each candidate includes a child PlanStage tree and QuerySolution. Ownership + // of all QuerySolutions is retained here, and will *not* be tranferred to the PlanExecutor that + // wraps this stage. Ownership of the PlanStages will be in PlanStage::_children which maps + // one-to-one with _candidates. std::vector<CandidatePlan> _candidates; // index into _candidates, of the winner of the plan competition @@ -227,7 +221,6 @@ private: std::unique_ptr<RecordFetcher> _fetcher; // Stats - CommonStats _commonStats; MultiPlanStats _specificStats; }; diff --git a/src/mongo/db/exec/near.cpp b/src/mongo/db/exec/near.cpp index 2012ef4ff9f..a79ae985bd5 100644 --- a/src/mongo/db/exec/near.cpp +++ b/src/mongo/db/exec/near.cpp @@ -42,21 +42,17 @@ using std::vector; using stdx::make_unique; NearStage::NearStage(OperationContext* txn, + const char* typeName, + StageType type, WorkingSet* workingSet, - Collection* collection, - PlanStageStats* stats) - : _txn(txn), + Collection* collection) + : PlanStage(typeName), + _txn(txn), _workingSet(workingSet), _collection(collection), _searchState(SearchState_Initializing), - _stats(stats), - _nextInterval(NULL) { - // Ensure we have specific distance search stats unless a child class specified their - // own distance stats subclass - if (!_stats->specific) { - _stats->specific.reset(new NearStats); - } -} + _stageType(type), + _nextInterval(NULL) {} NearStage::~NearStage() {} @@ -86,10 +82,10 @@ PlanStage::StageState NearStage::initNext(WorkingSetID* out) { } PlanStage::StageState NearStage::work(WorkingSetID* out) { - ++_stats->common.works; + ++_commonStats.works; // Adds the amount of time taken by work() to executionTimeMillis. - ScopedTimer timer(&_stats->common.executionTimeMillis); + ScopedTimer timer(&_commonStats.executionTimeMillis); WorkingSetID toReturn = WorkingSet::INVALID_ID; Status error = Status::OK(); @@ -118,14 +114,14 @@ PlanStage::StageState NearStage::work(WorkingSetID* out) { *out = WorkingSetCommon::allocateStatusMember(_workingSet, error); } else if (PlanStage::ADVANCED == nextState) { *out = toReturn; - ++_stats->common.advanced; + ++_commonStats.advanced; } else if (PlanStage::NEED_YIELD == nextState) { *out = toReturn; - ++_stats->common.needYield; + ++_commonStats.needYield; } else if (PlanStage::NEED_TIME == nextState) { - ++_stats->common.needTime; + ++_commonStats.needTime; } else if (PlanStage::IS_EOF == nextState) { - _stats->common.isEOF = true; + _commonStats.isEOF = true; } return nextState; @@ -178,7 +174,7 @@ PlanStage::StageState NearStage::bufferNext(WorkingSetID* toReturn, Status* erro PlanStage::StageState intervalState = _nextInterval->covering->work(&nextMemberID); if (PlanStage::IS_EOF == intervalState) { - getNearStats()->intervalStats.push_back(*_nextIntervalStats); + _specificStats.intervalStats.push_back(*_nextIntervalStats); _nextIntervalStats.reset(); _nextInterval = NULL; _searchState = SearchState_Advancing; @@ -288,35 +284,11 @@ bool NearStage::isEOF() { return SearchState_Finished == _searchState; } -void NearStage::saveState() { - _txn = NULL; - ++_stats->common.yields; - for (size_t i = 0; i < _childrenIntervals.size(); i++) { - _childrenIntervals[i]->covering->saveState(); - } - - // Subclass specific saving, e.g. saving the 2d or 2dsphere density estimator. - finishSaveState(); -} - -void NearStage::restoreState(OperationContext* opCtx) { - invariant(_txn == NULL); +void NearStage::doRestoreState(OperationContext* opCtx) { _txn = opCtx; - ++_stats->common.unyields; - for (size_t i = 0; i < _childrenIntervals.size(); i++) { - _childrenIntervals[i]->covering->restoreState(opCtx); - } - - // Subclass specific restoring, e.g. restoring the 2d or 2dsphere density estimator. - finishRestoreState(opCtx); } -void NearStage::invalidate(OperationContext* txn, const RecordId& dl, InvalidationType type) { - ++_stats->common.invalidates; - for (size_t i = 0; i < _childrenIntervals.size(); i++) { - _childrenIntervals[i]->covering->invalidate(txn, dl, type); - } - +void NearStage::doInvalidate(OperationContext* txn, const RecordId& dl, InvalidationType type) { // If a result is in _resultBuffer and has a RecordId it will be in _nextIntervalSeen as // well. It's safe to return the result w/o the RecordId, so just fetch the result. unordered_map<RecordId, WorkingSetID, RecordId::Hasher>::iterator seenIt = @@ -331,42 +303,23 @@ void NearStage::invalidate(OperationContext* txn, const RecordId& dl, Invalidati // Don't keep it around in the seen map since there's no valid RecordId anymore _nextIntervalSeen.erase(seenIt); } - - // Subclass specific invalidation, e.g. passing the invalidation to the 2d or 2dsphere - // density estimator. - finishInvalidate(txn, dl, type); -} - -vector<PlanStage*> NearStage::getChildren() const { - vector<PlanStage*> children; - for (size_t i = 0; i < _childrenIntervals.size(); i++) { - children.push_back(_childrenIntervals[i]->covering.get()); - } - return children; } unique_ptr<PlanStageStats> NearStage::getStats() { - unique_ptr<PlanStageStats> statsClone(_stats->clone()); + unique_ptr<PlanStageStats> ret = make_unique<PlanStageStats>(_commonStats, _stageType); + ret->specific.reset(_specificStats.clone()); for (size_t i = 0; i < _childrenIntervals.size(); ++i) { - statsClone->children.push_back(_childrenIntervals[i]->covering->getStats().release()); + ret->children.push_back(_childrenIntervals[i]->covering->getStats().release()); } - return statsClone; + return ret; } StageType NearStage::stageType() const { - return _stats->stageType; -} - -const CommonStats* NearStage::getCommonStats() const { - return &_stats->common; + return _stageType; } const SpecificStats* NearStage::getSpecificStats() const { - return _stats->specific.get(); -} - -NearStats* NearStage::getNearStats() { - return static_cast<NearStats*>(_stats->specific.get()); + return &_specificStats; } } // namespace mongo diff --git a/src/mongo/db/exec/near.h b/src/mongo/db/exec/near.h index 310bae591bc..09a743ae147 100644 --- a/src/mongo/db/exec/near.h +++ b/src/mongo/db/exec/near.h @@ -82,32 +82,22 @@ public: virtual bool isEOF(); virtual StageState work(WorkingSetID* out); - virtual void saveState(); - virtual void restoreState(OperationContext* opCtx); - virtual void invalidate(OperationContext* txn, const RecordId& dl, InvalidationType type); - - virtual std::vector<PlanStage*> getChildren() const; + virtual void doRestoreState(OperationContext* opCtx); + virtual void doInvalidate(OperationContext* txn, const RecordId& dl, InvalidationType type); virtual StageType stageType() const; virtual std::unique_ptr<PlanStageStats> getStats(); - virtual const CommonStats* getCommonStats() const; virtual const SpecificStats* getSpecificStats() const; protected: /** * Subclasses of NearStage must provide basics + a stats object which gets owned here. - * The stats object must have specific stats which are a subclass of NearStats, otherwise - * it's generated automatically. */ NearStage(OperationContext* txn, + const char* typeName, + StageType type, WorkingSet* workingSet, - Collection* collection, - PlanStageStats* stats); - - /** - * Exposes NearStats for adaptive search, allows additional specific stats in subclasses. - */ - NearStats* getNearStats(); + Collection* collection); // // Methods implemented for specific search functionality @@ -144,19 +134,10 @@ protected: Collection* collection, WorkingSetID* out) = 0; -private: - // - // Save/restore/invalidate work specific to the search type. - // - - virtual void finishSaveState() = 0; - - virtual void finishRestoreState(OperationContext* txn) = 0; - - virtual void finishInvalidate(OperationContext* txn, - const RecordId& dl, - InvalidationType type) = 0; + // Filled in by subclasses. + NearStats _specificStats; +private: // // Generic methods for progressive search functionality // @@ -196,7 +177,7 @@ private: std::priority_queue<SearchResult> _resultBuffer; // Stats - std::unique_ptr<PlanStageStats> _stats; + const StageType _stageType; // The current stage from which this stage should buffer results // Pointer to the last interval in _childrenIntervals. Owned by _childrenIntervals. @@ -219,8 +200,7 @@ struct NearStage::CoveredInterval { double maxDistance, bool inclusiveMax); - // Owned by NearStage - std::unique_ptr<PlanStage> const covering; + PlanStage* const covering; // Owned in PlanStage::_children. const bool dedupCovering; const double minDistance; diff --git a/src/mongo/db/exec/oplogstart.cpp b/src/mongo/db/exec/oplogstart.cpp index e077d448067..33b41aed43d 100644 --- a/src/mongo/db/exec/oplogstart.cpp +++ b/src/mongo/db/exec/oplogstart.cpp @@ -47,7 +47,8 @@ OplogStart::OplogStart(OperationContext* txn, const Collection* collection, MatchExpression* filter, WorkingSet* ws) - : _txn(txn), + : PlanStage(kStageType), + _txn(txn), _needInit(true), _backwardsScanning(false), _extentHopping(false), @@ -56,15 +57,13 @@ OplogStart::OplogStart(OperationContext* txn, _workingSet(ws), _filter(filter) {} -OplogStart::~OplogStart() {} - PlanStage::StageState OplogStart::work(WorkingSetID* out) { // We do our (heavy) init in a work(), where work is expected. if (_needInit) { CollectionScanParams params; params.collection = _collection; params.direction = CollectionScanParams::BACKWARD; - _cs.reset(new CollectionScan(_txn, params, _workingSet, NULL)); + _children.emplace_back(new CollectionScan(_txn, params, _workingSet, NULL)); _needInit = false; _backwardsScanning = true; @@ -133,11 +132,11 @@ void OplogStart::switchToExtentHopping() { _extentHopping = true; // Toss the collection scan we were using. - _cs.reset(); + _children.clear(); } PlanStage::StageState OplogStart::workBackwardsScan(WorkingSetID* out) { - PlanStage::StageState state = _cs->work(out); + PlanStage::StageState state = child()->work(out); // EOF. Just start from the beginning, which is where we've hit. if (PlanStage::IS_EOF == state) { @@ -167,7 +166,7 @@ bool OplogStart::isEOF() { return _done; } -void OplogStart::invalidate(OperationContext* txn, const RecordId& dl, InvalidationType type) { +void OplogStart::doInvalidate(OperationContext* txn, const RecordId& dl, InvalidationType type) { if (_needInit) { return; } @@ -176,32 +175,21 @@ void OplogStart::invalidate(OperationContext* txn, const RecordId& dl, Invalidat return; } - if (_cs) { - _cs->invalidate(txn, dl, type); - } - for (size_t i = 0; i < _subIterators.size(); i++) { _subIterators[i]->invalidate(dl); } } -void OplogStart::saveState() { +void OplogStart::doSaveState() { _txn = NULL; - if (_cs) { - _cs->saveState(); - } - for (size_t i = 0; i < _subIterators.size(); i++) { _subIterators[i]->savePositioned(); } } -void OplogStart::restoreState(OperationContext* opCtx) { +void OplogStart::doRestoreState(OperationContext* opCtx) { invariant(_txn == NULL); _txn = opCtx; - if (_cs) { - _cs->restoreState(opCtx); - } for (size_t i = 0; i < _subIterators.size(); i++) { if (!_subIterators[i]->restore(opCtx)) { @@ -219,11 +207,6 @@ unique_ptr<PlanStageStats> OplogStart::getStats() { return ret; } -vector<PlanStage*> OplogStart::getChildren() const { - vector<PlanStage*> empty; - return empty; -} - int OplogStart::_backwardsScanTime = 5; } // namespace mongo diff --git a/src/mongo/db/exec/oplogstart.h b/src/mongo/db/exec/oplogstart.h index 98ec934ba61..d26d8d63b4e 100644 --- a/src/mongo/db/exec/oplogstart.h +++ b/src/mongo/db/exec/oplogstart.h @@ -65,26 +65,20 @@ public: const Collection* collection, MatchExpression* filter, WorkingSet* ws); - virtual ~OplogStart(); virtual StageState work(WorkingSetID* out); virtual bool isEOF(); - virtual void invalidate(OperationContext* txn, const RecordId& dl, InvalidationType type); - virtual void saveState(); - virtual void restoreState(OperationContext* opCtx); - - virtual std::vector<PlanStage*> getChildren() const; + virtual void doInvalidate(OperationContext* txn, const RecordId& dl, InvalidationType type); + virtual void doSaveState(); + virtual void doRestoreState(OperationContext* opCtx); // Returns empty PlanStageStats object virtual std::unique_ptr<PlanStageStats> getStats(); // - // Exec stats -- do not call these for the oplog start stage. + // Exec stats -- do not call for the oplog start stage. // - virtual const CommonStats* getCommonStats() const { - return NULL; - } virtual const SpecificStats* getSpecificStats() const { return NULL; @@ -117,9 +111,6 @@ private: // transactional context for read locks. Not owned by us OperationContext* _txn; - // If we're backwards scanning we just punt to a collscan. - std::unique_ptr<CollectionScan> _cs; - // This is only used for the extent hopping scan. std::vector<std::unique_ptr<RecordCursor>> _subIterators; diff --git a/src/mongo/db/exec/or.cpp b/src/mongo/db/exec/or.cpp index b0902d683d3..f1ce36bdc5b 100644 --- a/src/mongo/db/exec/or.cpp +++ b/src/mongo/db/exec/or.cpp @@ -44,16 +44,10 @@ using stdx::make_unique; const char* OrStage::kStageType = "OR"; OrStage::OrStage(WorkingSet* ws, bool dedup, const MatchExpression* filter) - : _ws(ws), _filter(filter), _currentChild(0), _dedup(dedup), _commonStats(kStageType) {} - -OrStage::~OrStage() { - for (size_t i = 0; i < _children.size(); ++i) { - delete _children[i]; - } -} + : PlanStage(kStageType), _ws(ws), _filter(filter), _currentChild(0), _dedup(dedup) {} void OrStage::addChild(PlanStage* child) { - _children.push_back(child); + _children.emplace_back(child); } bool OrStage::isEOF() { @@ -138,31 +132,12 @@ PlanStage::StageState OrStage::work(WorkingSetID* out) { return childStatus; } -void OrStage::saveState() { - ++_commonStats.yields; - for (size_t i = 0; i < _children.size(); ++i) { - _children[i]->saveState(); - } -} - -void OrStage::restoreState(OperationContext* opCtx) { - ++_commonStats.unyields; - for (size_t i = 0; i < _children.size(); ++i) { - _children[i]->restoreState(opCtx); - } -} - -void OrStage::invalidate(OperationContext* txn, const RecordId& dl, InvalidationType type) { - ++_commonStats.invalidates; - +void OrStage::doInvalidate(OperationContext* txn, const RecordId& dl, InvalidationType type) { + // TODO remove this since calling isEOF is illegal inside of doInvalidate(). if (isEOF()) { return; } - for (size_t i = 0; i < _children.size(); ++i) { - _children[i]->invalidate(txn, dl, type); - } - // If we see DL again it is not the same record as it once was so we still want to // return it. if (_dedup && INVALIDATION_DELETION == type) { @@ -174,10 +149,6 @@ void OrStage::invalidate(OperationContext* txn, const RecordId& dl, Invalidation } } -vector<PlanStage*> OrStage::getChildren() const { - return _children; -} - unique_ptr<PlanStageStats> OrStage::getStats() { _commonStats.isEOF = isEOF(); @@ -197,10 +168,6 @@ unique_ptr<PlanStageStats> OrStage::getStats() { return ret; } -const CommonStats* OrStage::getCommonStats() const { - return &_commonStats; -} - const SpecificStats* OrStage::getSpecificStats() const { return &_specificStats; } diff --git a/src/mongo/db/exec/or.h b/src/mongo/db/exec/or.h index e2bf02d491a..7a10a78ae7d 100644 --- a/src/mongo/db/exec/or.h +++ b/src/mongo/db/exec/or.h @@ -46,7 +46,6 @@ namespace mongo { class OrStage : public PlanStage { public: OrStage(WorkingSet* ws, bool dedup, const MatchExpression* filter); - virtual ~OrStage(); void addChild(PlanStage* child); @@ -54,11 +53,7 @@ public: virtual StageState work(WorkingSetID* out); - virtual void saveState(); - virtual void restoreState(OperationContext* opCtx); - virtual void invalidate(OperationContext* txn, const RecordId& dl, InvalidationType type); - - virtual std::vector<PlanStage*> getChildren() const; + virtual void doInvalidate(OperationContext* txn, const RecordId& dl, InvalidationType type); virtual StageType stageType() const { return STAGE_OR; @@ -66,8 +61,6 @@ public: virtual std::unique_ptr<PlanStageStats> getStats(); - virtual const CommonStats* getCommonStats() const; - virtual const SpecificStats* getSpecificStats() const; static const char* kStageType; @@ -79,9 +72,6 @@ private: // The filter is not owned by us. const MatchExpression* _filter; - // Owned by us. - std::vector<PlanStage*> _children; - // Which of _children are we calling work(...) on now? size_t _currentChild; @@ -92,7 +82,6 @@ private: unordered_set<RecordId, RecordId::Hasher> _seen; // Stats - CommonStats _commonStats; OrStats _specificStats; }; diff --git a/src/mongo/db/exec/pipeline_proxy.cpp b/src/mongo/db/exec/pipeline_proxy.cpp index 3aed8d3b4fb..5c6fa17b251 100644 --- a/src/mongo/db/exec/pipeline_proxy.cpp +++ b/src/mongo/db/exec/pipeline_proxy.cpp @@ -48,9 +48,9 @@ const char* PipelineProxyStage::kStageType = "PIPELINE_PROXY"; PipelineProxyStage::PipelineProxyStage(intrusive_ptr<Pipeline> pipeline, const std::shared_ptr<PlanExecutor>& child, WorkingSet* ws) - : _pipeline(pipeline), - _includeMetaData(_pipeline->getContext()->inShard) // send metadata to merger - , + : PlanStage(kStageType), + _pipeline(pipeline), + _includeMetaData(_pipeline->getContext()->inShard), // send metadata to merger _childExec(child), _ws(ws) {} @@ -91,20 +91,20 @@ bool PipelineProxyStage::isEOF() { return true; } -void PipelineProxyStage::invalidate(OperationContext* txn, - const RecordId& dl, - InvalidationType type) { +void PipelineProxyStage::doInvalidate(OperationContext* txn, + const RecordId& dl, + InvalidationType type) { // propagate to child executor if still in use if (std::shared_ptr<PlanExecutor> exec = _childExec.lock()) { exec->invalidate(txn, dl, type); } } -void PipelineProxyStage::saveState() { +void PipelineProxyStage::doSaveState() { _pipeline->getContext()->opCtx = NULL; } -void PipelineProxyStage::restoreState(OperationContext* opCtx) { +void PipelineProxyStage::doRestoreState(OperationContext* opCtx) { invariant(_pipeline->getContext()->opCtx == NULL); _pipeline->getContext()->opCtx = opCtx; } @@ -113,11 +113,6 @@ void PipelineProxyStage::pushBack(const BSONObj& obj) { _stash.push_back(obj); } -vector<PlanStage*> PipelineProxyStage::getChildren() const { - vector<PlanStage*> empty; - return empty; -} - unique_ptr<PlanStageStats> PipelineProxyStage::getStats() { unique_ptr<PlanStageStats> ret = make_unique<PlanStageStats>(CommonStats(kStageType), STAGE_PIPELINE_PROXY); diff --git a/src/mongo/db/exec/pipeline_proxy.h b/src/mongo/db/exec/pipeline_proxy.h index f40674fff38..517cf6ef393 100644 --- a/src/mongo/db/exec/pipeline_proxy.h +++ b/src/mongo/db/exec/pipeline_proxy.h @@ -52,14 +52,14 @@ public: virtual bool isEOF(); - virtual void invalidate(OperationContext* txn, const RecordId& dl, InvalidationType type); + virtual void doInvalidate(OperationContext* txn, const RecordId& dl, InvalidationType type); // // Manage our OperationContext. We intentionally don't propagate to the child // Runner as that is handled by DocumentSourceCursor as it needs to. // - virtual void saveState(); - virtual void restoreState(OperationContext* opCtx); + virtual void doSaveState(); + virtual void doRestoreState(OperationContext* opCtx); /** * Make obj the next object returned by getNext(). @@ -75,10 +75,6 @@ public: // Returns empty PlanStageStats object virtual std::unique_ptr<PlanStageStats> getStats(); - // Not used. - virtual CommonStats* getCommonStats() const { - return NULL; - } // Not used. virtual SpecificStats* getSpecificStats() const { @@ -86,9 +82,6 @@ public: } // Not used. - virtual std::vector<PlanStage*> getChildren() const; - - // Not used. virtual StageType stageType() const { return STAGE_PIPELINE_PROXY; } diff --git a/src/mongo/db/exec/plan_stage.cpp b/src/mongo/db/exec/plan_stage.cpp new file mode 100644 index 00000000000..5c0f9c95472 --- /dev/null +++ b/src/mongo/db/exec/plan_stage.cpp @@ -0,0 +1,64 @@ +/** + * Copyright (C) 2015 MongoDB Inc. + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU Affero General Public License, version 3, + * as published by the Free Software Foundation. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU Affero General Public License for more details. + * + * You should have received a copy of the GNU Affero General Public License + * along with this program. If not, see <http://www.gnu.org/licenses/>. + * + * As a special exception, the copyright holders give permission to link the + * code of portions of this program with the OpenSSL library under certain + * conditions as described in each individual source file and distribute + * linked combinations including the program with the OpenSSL library. You + * must comply with the GNU Affero General Public License in all respects for + * all of the code used other than as permitted herein. If you modify file(s) + * with this exception, you may extend this exception to your version of the + * file(s), but you are not obligated to do so. If you do not wish to do so, + * delete this exception statement from your version. If you delete this + * exception statement from all source files in the program, then also delete + * it in the license file. + */ + +#define MONGO_LOG_DEFAULT_COMPONENT ::mongo::logger::LogComponent::kQuery + +#include "mongo/platform/basic.h" + +#include "mongo/db/exec/plan_stage.h" + +namespace mongo { + +void PlanStage::saveState() { + ++_commonStats.yields; + for (auto&& child : _children) { + child->saveState(); + } + + doSaveState(); +} + +void PlanStage::restoreState(OperationContext* opCtx) { + ++_commonStats.unyields; + for (auto&& child : _children) { + child->restoreState(opCtx); + } + + doRestoreState(opCtx); +} + +void PlanStage::invalidate(OperationContext* txn, const RecordId& dl, InvalidationType type) { + ++_commonStats.invalidates; + for (auto&& child : _children) { + child->invalidate(txn, dl, type); + } + + doInvalidate(txn, dl, type); +} + +} // namespace mongo diff --git a/src/mongo/db/exec/plan_stage.h b/src/mongo/db/exec/plan_stage.h index 289c99cc936..85884f47f9c 100644 --- a/src/mongo/db/exec/plan_stage.h +++ b/src/mongo/db/exec/plan_stage.h @@ -28,6 +28,9 @@ #pragma once +#include <memory> +#include <vector> + #include "mongo/db/exec/plan_stats.h" #include "mongo/db/exec/working_set.h" #include "mongo/db/invalidation_type.h" @@ -101,8 +104,12 @@ class OperationContext; */ class PlanStage { public: + PlanStage(const char* typeName) : _commonStats(typeName) {} + virtual ~PlanStage() {} + using Children = std::vector<std::unique_ptr<PlanStage>>; + /** * All possible return values of work(...) */ @@ -199,24 +206,22 @@ public: // /** - * Notifies the stage that all locks are about to be released. The stage must save any - * state required to resume where it was before saveState was called. + * Notifies the stage that the underlying data source may change. + * + * It is illegal to call work() or isEOF() when a stage is in the "saved" state. * - * Stages must be able to handle multiple calls to saveState() in a row without a call to - * restoreState() in between. + * Propagates to all children, then calls doSaveState(). */ - virtual void saveState() = 0; + void saveState(); /** - * Notifies the stage that any required locks have been reacquired. The stage must restore - * any saved state and be ready to handle calls to work(). + * Notifies the stage that underlying data is stable again and prepares for calls to work(). * - * Can only be called after saveState. + * Can only be called while the stage in is the "saved" state. * - * If the stage needs an OperationContext during its execution, it may keep a handle to the - * provided OperationContext (which is valid until the next call to saveState()). + * Propagates to all children, then calls doRestoreState(). */ - virtual void restoreState(OperationContext* opCtx) = 0; + void restoreState(OperationContext* opCtx); /** * Notifies a stage that a RecordId is going to be deleted (or in-place updated) so that the @@ -228,14 +233,18 @@ public: * The provided OperationContext should be used if any work needs to be performed during the * invalidate (as the state of the stage must be saved before any calls to invalidate, the * stage's own OperationContext is inactive during the invalidate and should not be used). + * + * Propagates to all children, then calls doInvalidate(). */ - virtual void invalidate(OperationContext* txn, const RecordId& dl, InvalidationType type) = 0; + void invalidate(OperationContext* txn, const RecordId& dl, InvalidationType type); /** * Retrieve a list of this stage's children. This stage keeps ownership of * its children. */ - virtual std::vector<PlanStage*> getChildren() const = 0; + const Children& getChildren() const { + return _children; + } /** * What type of stage is this? @@ -262,7 +271,9 @@ public: * It must not exist past the stage. If you need the stats to outlive the stage, * use the getStats(...) method above. */ - virtual const CommonStats* getCommonStats() const = 0; + const CommonStats* getCommonStats() const { + return &_commonStats; + } /** * Get stats specific to this stage. Some stages may not have specific stats, in which @@ -273,6 +284,42 @@ public: * use the getStats(...) method above. */ virtual const SpecificStats* getSpecificStats() const = 0; + +protected: + /** + * Saves any stage-specific state required to resume where it was if the underlying data + * changes. + * + * Stages must be able to handle multiple calls to doSaveState() in a row without a call to + * doRestoreState() in between. + */ + virtual void doSaveState() {} + + /** + * Restores any stage-specific saved state and prepares to handle calls to work(). + * + * If the stage needs an OperationContext during its execution, it may keep a handle to the + * provided OperationContext (which is valid until the next call to saveState()). + */ + virtual void doRestoreState(OperationContext* txn) {} + + /** + * Does the stage-specific invalidation work. + */ + virtual void doInvalidate(OperationContext* txn, const RecordId& dl, InvalidationType type) {} + + /** + * Returns the only child. + * + * Convenience method for PlanStages that have exactly one child. + */ + const std::unique_ptr<PlanStage>& child() const { + dassert(_children.size() == 1); + return _children.front(); + } + + Children _children; + CommonStats _commonStats; }; } // namespace mongo diff --git a/src/mongo/db/exec/projection.cpp b/src/mongo/db/exec/projection.cpp index 4a10248e6a9..a5698a266ab 100644 --- a/src/mongo/db/exec/projection.cpp +++ b/src/mongo/db/exec/projection.cpp @@ -55,7 +55,8 @@ const char* ProjectionStage::kStageType = "PROJECTION"; ProjectionStage::ProjectionStage(const ProjectionStageParams& params, WorkingSet* ws, PlanStage* child) - : _ws(ws), _child(child), _commonStats(kStageType), _projImpl(params.projImpl) { + : PlanStage(kStageType), _ws(ws), _projImpl(params.projImpl) { + _children.emplace_back(child); _projObj = params.projObj; if (ProjectionStageParams::NO_FAST_PATH == _projImpl) { @@ -189,10 +190,8 @@ Status ProjectionStage::transform(WorkingSetMember* member) { return Status::OK(); } -ProjectionStage::~ProjectionStage() {} - bool ProjectionStage::isEOF() { - return _child->isEOF(); + return child()->isEOF(); } PlanStage::StageState ProjectionStage::work(WorkingSetID* out) { @@ -202,7 +201,7 @@ PlanStage::StageState ProjectionStage::work(WorkingSetID* out) { ScopedTimer timer(&_commonStats.executionTimeMillis); WorkingSetID id = WorkingSet::INVALID_ID; - StageState status = _child->work(&id); + StageState status = child()->work(&id); // Note that we don't do the normal if isEOF() return EOF thing here. Our child might be a // tailable cursor and isEOF() would be true even if it had more data... @@ -239,27 +238,6 @@ PlanStage::StageState ProjectionStage::work(WorkingSetID* out) { return status; } -void ProjectionStage::saveState() { - ++_commonStats.yields; - _child->saveState(); -} - -void ProjectionStage::restoreState(OperationContext* opCtx) { - ++_commonStats.unyields; - _child->restoreState(opCtx); -} - -void ProjectionStage::invalidate(OperationContext* txn, const RecordId& dl, InvalidationType type) { - ++_commonStats.invalidates; - _child->invalidate(txn, dl, type); -} - -vector<PlanStage*> ProjectionStage::getChildren() const { - vector<PlanStage*> children; - children.push_back(_child.get()); - return children; -} - unique_ptr<PlanStageStats> ProjectionStage::getStats() { _commonStats.isEOF = isEOF(); unique_ptr<PlanStageStats> ret = make_unique<PlanStageStats>(_commonStats, STAGE_PROJECTION); @@ -268,14 +246,10 @@ unique_ptr<PlanStageStats> ProjectionStage::getStats() { projStats->projObj = _projObj; ret->specific = std::move(projStats); - ret->children.push_back(_child->getStats().release()); + ret->children.push_back(child()->getStats().release()); return ret; } -const CommonStats* ProjectionStage::getCommonStats() const { - return &_commonStats; -} - const SpecificStats* ProjectionStage::getSpecificStats() const { return &_specificStats; } diff --git a/src/mongo/db/exec/projection.h b/src/mongo/db/exec/projection.h index 1810f727ce6..7fa5f0fcc2d 100644 --- a/src/mongo/db/exec/projection.h +++ b/src/mongo/db/exec/projection.h @@ -77,25 +77,15 @@ class ProjectionStage : public PlanStage { public: ProjectionStage(const ProjectionStageParams& params, WorkingSet* ws, PlanStage* child); - virtual ~ProjectionStage(); - virtual bool isEOF(); virtual StageState work(WorkingSetID* out); - virtual void saveState(); - virtual void restoreState(OperationContext* opCtx); - virtual void invalidate(OperationContext* txn, const RecordId& dl, InvalidationType type); - - virtual std::vector<PlanStage*> getChildren() const; - virtual StageType stageType() const { return STAGE_PROJECTION; } std::unique_ptr<PlanStageStats> getStats(); - virtual const CommonStats* getCommonStats() const; - virtual const SpecificStats* getSpecificStats() const; typedef unordered_set<StringData, StringData::Hasher> FieldSet; @@ -126,10 +116,8 @@ private: // _ws is not owned by us. WorkingSet* _ws; - std::unique_ptr<PlanStage> _child; // Stats - CommonStats _commonStats; ProjectionStats _specificStats; // Fast paths: diff --git a/src/mongo/db/exec/queued_data_stage.cpp b/src/mongo/db/exec/queued_data_stage.cpp index e51ae60c347..36edcab1893 100644 --- a/src/mongo/db/exec/queued_data_stage.cpp +++ b/src/mongo/db/exec/queued_data_stage.cpp @@ -40,7 +40,7 @@ using stdx::make_unique; const char* QueuedDataStage::kStageType = "QUEUED_DATA"; -QueuedDataStage::QueuedDataStage(WorkingSet* ws) : _ws(ws), _commonStats(kStageType) {} +QueuedDataStage::QueuedDataStage(WorkingSet* ws) : PlanStage(kStageType), _ws(ws) {} PlanStage::StageState QueuedDataStage::work(WorkingSetID* out) { ++_commonStats.works; @@ -70,18 +70,6 @@ bool QueuedDataStage::isEOF() { return _results.empty(); } -void QueuedDataStage::saveState() { - ++_commonStats.yields; -} - -void QueuedDataStage::restoreState(OperationContext* opCtx) { - ++_commonStats.unyields; -} - -void QueuedDataStage::invalidate(OperationContext* txn, const RecordId& dl, InvalidationType type) { - ++_commonStats.invalidates; -} - unique_ptr<PlanStageStats> QueuedDataStage::getStats() { _commonStats.isEOF = isEOF(); unique_ptr<PlanStageStats> ret = make_unique<PlanStageStats>(_commonStats, STAGE_QUEUED_DATA); @@ -89,9 +77,6 @@ unique_ptr<PlanStageStats> QueuedDataStage::getStats() { return ret; } -const CommonStats* QueuedDataStage::getCommonStats() const { - return &_commonStats; -} const SpecificStats* QueuedDataStage::getSpecificStats() const { return &_specificStats; @@ -109,9 +94,4 @@ void QueuedDataStage::pushBack(const WorkingSetID& id) { _members.push(id); } -vector<PlanStage*> QueuedDataStage::getChildren() const { - vector<PlanStage*> empty; - return empty; -} - } // namespace mongo diff --git a/src/mongo/db/exec/queued_data_stage.h b/src/mongo/db/exec/queued_data_stage.h index ec93eb1dfb3..cceaaf10457 100644 --- a/src/mongo/db/exec/queued_data_stage.h +++ b/src/mongo/db/exec/queued_data_stage.h @@ -48,21 +48,11 @@ class RecordId; class QueuedDataStage : public PlanStage { public: QueuedDataStage(WorkingSet* ws); - virtual ~QueuedDataStage() {} virtual StageState work(WorkingSetID* out); virtual bool isEOF(); - // These don't really mean anything here. - // Some day we could count the # of calls to the yield functions to check that other stages - // have correct yielding behavior. - virtual void saveState(); - virtual void restoreState(OperationContext* opCtx); - virtual void invalidate(OperationContext* txn, const RecordId& dl, InvalidationType type); - - virtual std::vector<PlanStage*> getChildren() const; - virtual StageType stageType() const { return STAGE_QUEUED_DATA; } @@ -73,8 +63,6 @@ public: virtual std::unique_ptr<PlanStageStats> getStats(); - virtual const CommonStats* getCommonStats() const; - virtual const SpecificStats* getSpecificStats() const; /** @@ -110,7 +98,6 @@ private: std::queue<WorkingSetID> _members; // Stats - CommonStats _commonStats; MockStats _specificStats; }; diff --git a/src/mongo/db/exec/shard_filter.cpp b/src/mongo/db/exec/shard_filter.cpp index 26fe05144dd..1339e13bd3e 100644 --- a/src/mongo/db/exec/shard_filter.cpp +++ b/src/mongo/db/exec/shard_filter.cpp @@ -53,12 +53,14 @@ const char* ShardFilterStage::kStageType = "SHARDING_FILTER"; ShardFilterStage::ShardFilterStage(const shared_ptr<CollectionMetadata>& metadata, WorkingSet* ws, PlanStage* child) - : _ws(ws), _child(child), _commonStats(kStageType), _metadata(metadata) {} + : PlanStage(kStageType), _ws(ws), _metadata(metadata) { + _children.emplace_back(child); +} ShardFilterStage::~ShardFilterStage() {} bool ShardFilterStage::isEOF() { - return _child->isEOF(); + return child()->isEOF(); } PlanStage::StageState ShardFilterStage::work(WorkingSetID* out) { @@ -72,7 +74,7 @@ PlanStage::StageState ShardFilterStage::work(WorkingSetID* out) { return PlanStage::IS_EOF; } - StageState status = _child->work(out); + StageState status = child()->work(out); if (PlanStage::ADVANCED == status) { // If we're sharded make sure that we don't return data that is not owned by us, @@ -129,42 +131,15 @@ PlanStage::StageState ShardFilterStage::work(WorkingSetID* out) { return status; } -void ShardFilterStage::saveState() { - ++_commonStats.yields; - _child->saveState(); -} - -void ShardFilterStage::restoreState(OperationContext* opCtx) { - ++_commonStats.unyields; - _child->restoreState(opCtx); -} - -void ShardFilterStage::invalidate(OperationContext* txn, - const RecordId& dl, - InvalidationType type) { - ++_commonStats.invalidates; - _child->invalidate(txn, dl, type); -} - -vector<PlanStage*> ShardFilterStage::getChildren() const { - vector<PlanStage*> children; - children.push_back(_child.get()); - return children; -} - unique_ptr<PlanStageStats> ShardFilterStage::getStats() { _commonStats.isEOF = isEOF(); unique_ptr<PlanStageStats> ret = make_unique<PlanStageStats>(_commonStats, STAGE_SHARDING_FILTER); - ret->children.push_back(_child->getStats().release()); + ret->children.push_back(child()->getStats().release()); ret->specific = make_unique<ShardingFilterStats>(_specificStats); return ret; } -const CommonStats* ShardFilterStage::getCommonStats() const { - return &_commonStats; -} - const SpecificStats* ShardFilterStage::getSpecificStats() const { return &_specificStats; } diff --git a/src/mongo/db/exec/shard_filter.h b/src/mongo/db/exec/shard_filter.h index a61eefc2f23..be3f98d526b 100644 --- a/src/mongo/db/exec/shard_filter.h +++ b/src/mongo/db/exec/shard_filter.h @@ -79,30 +79,20 @@ public: virtual bool isEOF(); virtual StageState work(WorkingSetID* out); - virtual void saveState(); - virtual void restoreState(OperationContext* opCtx); - virtual void invalidate(OperationContext* txn, const RecordId& dl, InvalidationType type); - - virtual std::vector<PlanStage*> getChildren() const; - virtual StageType stageType() const { return STAGE_SHARDING_FILTER; } virtual std::unique_ptr<PlanStageStats> getStats(); - virtual const CommonStats* getCommonStats() const; - virtual const SpecificStats* getSpecificStats() const; static const char* kStageType; private: WorkingSet* _ws; - std::unique_ptr<PlanStage> _child; // Stats - CommonStats _commonStats; ShardingFilterStats _specificStats; // Note: it is important that this is the metadata from the time this stage is constructed. diff --git a/src/mongo/db/exec/skip.cpp b/src/mongo/db/exec/skip.cpp index b223b75f364..140c4a1bdb9 100644 --- a/src/mongo/db/exec/skip.cpp +++ b/src/mongo/db/exec/skip.cpp @@ -42,12 +42,14 @@ using stdx::make_unique; const char* SkipStage::kStageType = "SKIP"; SkipStage::SkipStage(long long toSkip, WorkingSet* ws, PlanStage* child) - : _ws(ws), _child(child), _toSkip(toSkip), _commonStats(kStageType) {} + : PlanStage(kStageType), _ws(ws), _toSkip(toSkip) { + _children.emplace_back(child); +} SkipStage::~SkipStage() {} bool SkipStage::isEOF() { - return _child->isEOF(); + return child()->isEOF(); } PlanStage::StageState SkipStage::work(WorkingSetID* out) { @@ -57,7 +59,7 @@ PlanStage::StageState SkipStage::work(WorkingSetID* out) { ScopedTimer timer(&_commonStats.executionTimeMillis); WorkingSetID id = WorkingSet::INVALID_ID; - StageState status = _child->work(&id); + StageState status = child()->work(&id); if (PlanStage::ADVANCED == status) { // If we're still skipping results... @@ -95,40 +97,15 @@ PlanStage::StageState SkipStage::work(WorkingSetID* out) { return status; } -void SkipStage::saveState() { - ++_commonStats.yields; - _child->saveState(); -} - -void SkipStage::restoreState(OperationContext* opCtx) { - ++_commonStats.unyields; - _child->restoreState(opCtx); -} - -void SkipStage::invalidate(OperationContext* txn, const RecordId& dl, InvalidationType type) { - ++_commonStats.invalidates; - _child->invalidate(txn, dl, type); -} - -vector<PlanStage*> SkipStage::getChildren() const { - vector<PlanStage*> children; - children.push_back(_child.get()); - return children; -} - unique_ptr<PlanStageStats> SkipStage::getStats() { _commonStats.isEOF = isEOF(); _specificStats.skip = _toSkip; unique_ptr<PlanStageStats> ret = make_unique<PlanStageStats>(_commonStats, STAGE_SKIP); ret->specific = make_unique<SkipStats>(_specificStats); - ret->children.push_back(_child->getStats().release()); + ret->children.push_back(child()->getStats().release()); return ret; } -const CommonStats* SkipStage::getCommonStats() const { - return &_commonStats; -} - const SpecificStats* SkipStage::getSpecificStats() const { return &_specificStats; } diff --git a/src/mongo/db/exec/skip.h b/src/mongo/db/exec/skip.h index c8f5105e3da..3d2b165abd8 100644 --- a/src/mongo/db/exec/skip.h +++ b/src/mongo/db/exec/skip.h @@ -49,33 +49,23 @@ public: virtual bool isEOF(); virtual StageState work(WorkingSetID* out); - virtual void saveState(); - virtual void restoreState(OperationContext* opCtx); - virtual void invalidate(OperationContext* txn, const RecordId& dl, InvalidationType type); - - virtual std::vector<PlanStage*> getChildren() const; - virtual StageType stageType() const { return STAGE_SKIP; } virtual std::unique_ptr<PlanStageStats> getStats(); - virtual const CommonStats* getCommonStats() const; - virtual const SpecificStats* getSpecificStats() const; static const char* kStageType; private: WorkingSet* _ws; - std::unique_ptr<PlanStage> _child; // We drop the first _toSkip results that we would have returned. long long _toSkip; // Stats - CommonStats _commonStats; SkipStats _specificStats; }; diff --git a/src/mongo/db/exec/sort.cpp b/src/mongo/db/exec/sort.cpp index 246462f953c..d7281e1b38e 100644 --- a/src/mongo/db/exec/sort.cpp +++ b/src/mongo/db/exec/sort.cpp @@ -279,23 +279,24 @@ bool SortStage::WorkingSetComparator::operator()(const SortableDataItem& lhs, } SortStage::SortStage(const SortStageParams& params, WorkingSet* ws, PlanStage* child) - : _collection(params.collection), + : PlanStage(kStageType), + _collection(params.collection), _ws(ws), - _child(child), _pattern(params.pattern), _query(params.query), _limit(params.limit), _sorted(false), _resultIterator(_data.end()), - _commonStats(kStageType), - _memUsage(0) {} + _memUsage(0) { + _children.emplace_back(child); +} SortStage::~SortStage() {} bool SortStage::isEOF() { // We're done when our child has no more results, we've sorted the child's results, and // we've returned all sorted results. - return _child->isEOF() && _sorted && (_data.end() == _resultIterator); + return child()->isEOF() && _sorted && (_data.end() == _resultIterator); } PlanStage::StageState SortStage::work(WorkingSetID* out) { @@ -334,7 +335,7 @@ PlanStage::StageState SortStage::work(WorkingSetID* out) { // Still reading in results to sort. if (!_sorted) { WorkingSetID id = WorkingSet::INVALID_ID; - StageState code = _child->work(&id); + StageState code = child()->work(&id); if (PlanStage::ADVANCED == code) { // Add it into the map for quick invalidation if it has a valid RecordId. @@ -414,20 +415,7 @@ PlanStage::StageState SortStage::work(WorkingSetID* out) { return PlanStage::ADVANCED; } -void SortStage::saveState() { - ++_commonStats.yields; - _child->saveState(); -} - -void SortStage::restoreState(OperationContext* opCtx) { - ++_commonStats.unyields; - _child->restoreState(opCtx); -} - -void SortStage::invalidate(OperationContext* txn, const RecordId& dl, InvalidationType type) { - ++_commonStats.invalidates; - _child->invalidate(txn, dl, type); - +void SortStage::doInvalidate(OperationContext* txn, const RecordId& dl, InvalidationType type) { // If we have a deletion, we can fetch and carry on. // If we have a mutation, it's easier to fetch and use the previous document. // So, no matter what, fetch and keep the doc in play. @@ -451,12 +439,6 @@ void SortStage::invalidate(OperationContext* txn, const RecordId& dl, Invalidati } } -vector<PlanStage*> SortStage::getChildren() const { - vector<PlanStage*> children; - children.push_back(_child.get()); - return children; -} - unique_ptr<PlanStageStats> SortStage::getStats() { _commonStats.isEOF = isEOF(); const size_t maxBytes = static_cast<size_t>(internalQueryExecMaxBlockingSortBytes); @@ -467,14 +449,10 @@ unique_ptr<PlanStageStats> SortStage::getStats() { unique_ptr<PlanStageStats> ret = make_unique<PlanStageStats>(_commonStats, STAGE_SORT); ret->specific = make_unique<SortStats>(_specificStats); - ret->children.push_back(_child->getStats().release()); + ret->children.push_back(child()->getStats().release()); return ret; } -const CommonStats* SortStage::getCommonStats() const { - return &_commonStats; -} - const SpecificStats* SortStage::getSpecificStats() const { return &_specificStats; } diff --git a/src/mongo/db/exec/sort.h b/src/mongo/db/exec/sort.h index 289ab0772b0..39a32ba9c88 100644 --- a/src/mongo/db/exec/sort.h +++ b/src/mongo/db/exec/sort.h @@ -142,17 +142,12 @@ private: class SortStage : public PlanStage { public: SortStage(const SortStageParams& params, WorkingSet* ws, PlanStage* child); - virtual ~SortStage(); virtual bool isEOF(); virtual StageState work(WorkingSetID* out); - virtual void saveState(); - virtual void restoreState(OperationContext* opCtx); - virtual void invalidate(OperationContext* txn, const RecordId& dl, InvalidationType type); - - virtual std::vector<PlanStage*> getChildren() const; + virtual void doInvalidate(OperationContext* txn, const RecordId& dl, InvalidationType type); virtual StageType stageType() const { return STAGE_SORT; @@ -160,8 +155,6 @@ public: std::unique_ptr<PlanStageStats> getStats(); - virtual const CommonStats* getCommonStats() const; - virtual const SpecificStats* getSpecificStats() const; static const char* kStageType; @@ -177,9 +170,6 @@ private: // Not owned by us. WorkingSet* _ws; - // Where we're reading data to sort from. - std::unique_ptr<PlanStage> _child; - // The raw sort _pattern as expressed by the user BSONObj _pattern; @@ -260,11 +250,6 @@ private: typedef unordered_map<RecordId, WorkingSetID, RecordId::Hasher> DataMap; DataMap _wsidByDiskLoc; - // - // Stats - // - - CommonStats _commonStats; SortStats _specificStats; // The usage in bytes of all buffered data that we're sorting. diff --git a/src/mongo/db/exec/subplan.cpp b/src/mongo/db/exec/subplan.cpp index b0a9717ba64..bb9b0abb14f 100644 --- a/src/mongo/db/exec/subplan.cpp +++ b/src/mongo/db/exec/subplan.cpp @@ -59,12 +59,12 @@ SubplanStage::SubplanStage(OperationContext* txn, WorkingSet* ws, const QueryPlannerParams& params, CanonicalQuery* cq) - : _txn(txn), + : PlanStage(kStageType), + _txn(txn), _collection(collection), _ws(ws), _plannerParams(params), - _query(cq), - _commonStats(kStageType) { + _query(cq) { invariant(_collection); } @@ -323,8 +323,7 @@ Status SubplanStage::choosePlanForSubqueries(PlanYieldPolicy* yieldPolicy) { _ws->clear(); - _child.reset(new MultiPlanStage(_txn, _collection, branchResult->canonicalQuery.get())); - MultiPlanStage* multiPlanStage = static_cast<MultiPlanStage*>(_child.get()); + MultiPlanStage multiPlanStage(_txn, _collection, branchResult->canonicalQuery.get()); // Dump all the solutions into the MPS. for (size_t ix = 0; ix < branchResult->solutions.size(); ++ix) { @@ -333,22 +332,22 @@ Status SubplanStage::choosePlanForSubqueries(PlanYieldPolicy* yieldPolicy) { _txn, _collection, *branchResult->solutions[ix], _ws, &nextPlanRoot)); // Takes ownership of solution with index 'ix' and 'nextPlanRoot'. - multiPlanStage->addPlan(branchResult->solutions.releaseAt(ix), nextPlanRoot, _ws); + multiPlanStage.addPlan(branchResult->solutions.releaseAt(ix), nextPlanRoot, _ws); } - Status planSelectStat = multiPlanStage->pickBestPlan(yieldPolicy); + Status planSelectStat = multiPlanStage.pickBestPlan(yieldPolicy); if (!planSelectStat.isOK()) { return planSelectStat; } - if (!multiPlanStage->bestPlanChosen()) { + if (!multiPlanStage.bestPlanChosen()) { mongoutils::str::stream ss; ss << "Failed to pick best plan for subchild " << branchResult->canonicalQuery->toString(); return Status(ErrorCodes::BadValue, ss); } - QuerySolution* bestSoln = multiPlanStage->bestSolution(); + QuerySolution* bestSoln = multiPlanStage.bestSolution(); // Check that we have good cache data. For example, we don't cache things // for 2d indices. @@ -410,7 +409,8 @@ Status SubplanStage::choosePlanForSubqueries(PlanYieldPolicy* yieldPolicy) { _ws->clear(); PlanStage* root; invariant(StageBuilder::build(_txn, _collection, *_compositeSolution.get(), _ws, &root)); - _child.reset(root); + invariant(_children.empty()); + _children.emplace_back(root); return Status::OK(); } @@ -442,7 +442,8 @@ Status SubplanStage::choosePlanWholeQuery(PlanYieldPolicy* yieldPolicy) { PlanStage* root; // Only one possible plan. Run it. Build the stages from the solution. verify(StageBuilder::build(_txn, _collection, *solutions[0], _ws, &root)); - _child.reset(root); + invariant(_children.empty()); + _children.emplace_back(root); // This SubplanStage takes ownership of the query solution. _compositeSolution.reset(solutions.popAndReleaseBack()); @@ -451,8 +452,9 @@ Status SubplanStage::choosePlanWholeQuery(PlanYieldPolicy* yieldPolicy) { } else { // Many solutions. Create a MultiPlanStage to pick the best, update the cache, // and so on. The working set will be shared by all candidate plans. - _child.reset(new MultiPlanStage(_txn, _collection, _query)); - MultiPlanStage* multiPlanStage = static_cast<MultiPlanStage*>(_child.get()); + invariant(_children.empty()); + _children.emplace_back(new MultiPlanStage(_txn, _collection, _query)); + MultiPlanStage* multiPlanStage = static_cast<MultiPlanStage*>(child().get()); for (size_t ix = 0; ix < solutions.size(); ++ix) { if (solutions[ix]->cacheData.get()) { @@ -500,8 +502,8 @@ Status SubplanStage::pickBestPlan(PlanYieldPolicy* yieldPolicy) { bool SubplanStage::isEOF() { // If we're running we best have a runner. - invariant(_child.get()); - return _child->isEOF(); + invariant(child()); + return child()->isEOF(); } PlanStage::StageState SubplanStage::work(WorkingSetID* out) { @@ -514,8 +516,8 @@ PlanStage::StageState SubplanStage::work(WorkingSetID* out) { return PlanStage::IS_EOF; } - invariant(_child.get()); - StageState state = _child->work(out); + invariant(child()); + StageState state = child()->work(out); if (PlanStage::NEED_TIME == state) { ++_commonStats.needTime; @@ -528,49 +530,14 @@ PlanStage::StageState SubplanStage::work(WorkingSetID* out) { return state; } -void SubplanStage::saveState() { - _txn = NULL; - ++_commonStats.yields; - - // We're ranking a sub-plan via an MPS or we're streaming results from this stage. Either - // way, pass on the request. - if (NULL != _child.get()) { - _child->saveState(); - } -} - -void SubplanStage::restoreState(OperationContext* opCtx) { - invariant(_txn == NULL); +void SubplanStage::doRestoreState(OperationContext* opCtx) { _txn = opCtx; - ++_commonStats.unyields; - - // We're ranking a sub-plan via an MPS or we're streaming results from this stage. Either - // way, pass on the request. - if (NULL != _child.get()) { - _child->restoreState(opCtx); - } -} - -void SubplanStage::invalidate(OperationContext* txn, const RecordId& dl, InvalidationType type) { - ++_commonStats.invalidates; - - if (NULL != _child.get()) { - _child->invalidate(txn, dl, type); - } -} - -std::vector<PlanStage*> SubplanStage::getChildren() const { - std::vector<PlanStage*> children; - if (NULL != _child.get()) { - children.push_back(_child.get()); - } - return children; } unique_ptr<PlanStageStats> SubplanStage::getStats() { _commonStats.isEOF = isEOF(); unique_ptr<PlanStageStats> ret = make_unique<PlanStageStats>(_commonStats, STAGE_SUBPLAN); - ret->children.push_back(_child->getStats().release()); + ret->children.push_back(child()->getStats().release()); return ret; } @@ -578,10 +545,6 @@ bool SubplanStage::branchPlannedFromCache(size_t i) const { return NULL != _branchResults[i]->cachedSolution.get(); } -const CommonStats* SubplanStage::getCommonStats() const { - return &_commonStats; -} - const SpecificStats* SubplanStage::getSpecificStats() const { return NULL; } diff --git a/src/mongo/db/exec/subplan.h b/src/mongo/db/exec/subplan.h index c2db2c34fee..d1a54db9d34 100644 --- a/src/mongo/db/exec/subplan.h +++ b/src/mongo/db/exec/subplan.h @@ -77,11 +77,7 @@ public: virtual bool isEOF(); virtual StageState work(WorkingSetID* out); - virtual void saveState(); - virtual void restoreState(OperationContext* opCtx); - virtual void invalidate(OperationContext* txn, const RecordId& dl, InvalidationType type); - - virtual std::vector<PlanStage*> getChildren() const; + virtual void doRestoreState(OperationContext* opCtx); virtual StageType stageType() const { return STAGE_SUBPLAN; @@ -89,8 +85,6 @@ public: std::unique_ptr<PlanStageStats> getStats(); - virtual const CommonStats* getCommonStats() const; - virtual const SpecificStats* getSpecificStats() const; static const char* kStageType; @@ -203,15 +197,11 @@ private: // independently, that solution is owned here. std::unique_ptr<QuerySolution> _compositeSolution; - std::unique_ptr<PlanStage> _child; - // Holds a list of the results from planning each branch. OwnedPointerVector<BranchPlanningResult> _branchResults; // We need this to extract cache-friendly index data from the index assignments. std::map<BSONObj, size_t> _indexMap; - - CommonStats _commonStats; }; } // namespace mongo diff --git a/src/mongo/db/exec/text.cpp b/src/mongo/db/exec/text.cpp index 56192851bd9..b7cc0789286 100644 --- a/src/mongo/db/exec/text.cpp +++ b/src/mongo/db/exec/text.cpp @@ -60,16 +60,15 @@ TextStage::TextStage(OperationContext* txn, const TextStageParams& params, WorkingSet* ws, const MatchExpression* filter) - : _params(params), _textTreeRoot(buildTextTree(txn, ws, filter)), _commonStats(kStageType) { + : PlanStage(kStageType), _params(params) { + _children.emplace_back(buildTextTree(txn, ws, filter)); _specificStats.indexPrefix = _params.indexPrefix; _specificStats.indexName = _params.index->indexName(); _specificStats.parsedTextQuery = _params.query.toBSON(); } -TextStage::~TextStage() {} - bool TextStage::isEOF() { - return _textTreeRoot->isEOF(); + return child()->isEOF(); } PlanStage::StageState TextStage::work(WorkingSetID* out) { @@ -82,7 +81,7 @@ PlanStage::StageState TextStage::work(WorkingSetID* out) { return PlanStage::IS_EOF; } - PlanStage::StageState stageState = _textTreeRoot->work(out); + PlanStage::StageState stageState = child()->work(out); // Increment common stats counters that are specific to the return value of work(). switch (stageState) { @@ -102,41 +101,15 @@ PlanStage::StageState TextStage::work(WorkingSetID* out) { return stageState; } -void TextStage::saveState() { - ++_commonStats.yields; - - _textTreeRoot->saveState(); -} - -void TextStage::restoreState(OperationContext* opCtx) { - ++_commonStats.unyields; - - _textTreeRoot->restoreState(opCtx); -} - -void TextStage::invalidate(OperationContext* txn, const RecordId& dl, InvalidationType type) { - ++_commonStats.invalidates; - - _textTreeRoot->invalidate(txn, dl, type); -} - -vector<PlanStage*> TextStage::getChildren() const { - return {_textTreeRoot.get()}; -} - unique_ptr<PlanStageStats> TextStage::getStats() { _commonStats.isEOF = isEOF(); unique_ptr<PlanStageStats> ret = make_unique<PlanStageStats>(_commonStats, STAGE_TEXT); ret->specific = make_unique<TextStats>(_specificStats); - ret->children.push_back(_textTreeRoot->getStats().release()); + ret->children.push_back(child()->getStats().release()); return ret; } -const CommonStats* TextStage::getCommonStats() const { - return &_commonStats; -} - const SpecificStats* TextStage::getSpecificStats() const { return &_specificStats; } diff --git a/src/mongo/db/exec/text.h b/src/mongo/db/exec/text.h index 27b5bc62231..4d0d57f66d0 100644 --- a/src/mongo/db/exec/text.h +++ b/src/mongo/db/exec/text.h @@ -76,25 +76,16 @@ public: WorkingSet* ws, const MatchExpression* filter); - ~TextStage() final; StageState work(WorkingSetID* out) final; bool isEOF() final; - void saveState() final; - void restoreState(OperationContext* opCtx) final; - void invalidate(OperationContext* txn, const RecordId& dl, InvalidationType type) final; - - vector<PlanStage*> getChildren() const; - StageType stageType() const final { return STAGE_TEXT; } std::unique_ptr<PlanStageStats> getStats(); - const CommonStats* getCommonStats() const final; - const SpecificStats* getSpecificStats() const final; static const char* kStageType; @@ -110,11 +101,7 @@ private: // Parameters of this text stage. TextStageParams _params; - // The root of the text query tree. - unique_ptr<PlanStage> _textTreeRoot; - // Stats. - CommonStats _commonStats; TextStats _specificStats; }; diff --git a/src/mongo/db/exec/text_match.cpp b/src/mongo/db/exec/text_match.cpp index 8edb78b2a3e..bf92b38a57b 100644 --- a/src/mongo/db/exec/text_match.cpp +++ b/src/mongo/db/exec/text_match.cpp @@ -49,34 +49,14 @@ TextMatchStage::TextMatchStage(unique_ptr<PlanStage> child, const FTSQuery& query, const FTSSpec& spec, WorkingSet* ws) - : _ftsMatcher(query, spec), _ws(ws), _child(std::move(child)), _commonStats(kStageType) {} + : PlanStage(kStageType), _ftsMatcher(query, spec), _ws(ws) { + _children.emplace_back(std::move(child)); +} TextMatchStage::~TextMatchStage() {} bool TextMatchStage::isEOF() { - return _child->isEOF(); -} - -void TextMatchStage::saveState() { - ++_commonStats.yields; - - _child->saveState(); -} - -void TextMatchStage::restoreState(OperationContext* opCtx) { - ++_commonStats.unyields; - - _child->restoreState(opCtx); -} - -void TextMatchStage::invalidate(OperationContext* txn, const RecordId& dl, InvalidationType type) { - ++_commonStats.invalidates; - - _child->invalidate(txn, dl, type); -} - -vector<PlanStage*> TextMatchStage::getChildren() const { - return {_child.get()}; + return child()->isEOF(); } std::unique_ptr<PlanStageStats> TextMatchStage::getStats() { @@ -84,15 +64,11 @@ std::unique_ptr<PlanStageStats> TextMatchStage::getStats() { unique_ptr<PlanStageStats> ret = make_unique<PlanStageStats>(_commonStats, STAGE_TEXT_MATCH); ret->specific = make_unique<TextMatchStats>(_specificStats); - ret->children.push_back(_child->getStats().release()); + ret->children.push_back(child()->getStats().release()); return ret; } -const CommonStats* TextMatchStage::getCommonStats() const { - return &_commonStats; -} - const SpecificStats* TextMatchStage::getSpecificStats() const { return &_specificStats; } @@ -108,7 +84,7 @@ PlanStage::StageState TextMatchStage::work(WorkingSetID* out) { } // Retrieve fetched document from child. - StageState stageState = _child->work(out); + StageState stageState = child()->work(out); if (stageState == PlanStage::ADVANCED) { // We just successfully retrieved a fetched doc. diff --git a/src/mongo/db/exec/text_match.h b/src/mongo/db/exec/text_match.h index bc1cf6b528f..cacec80c4e6 100644 --- a/src/mongo/db/exec/text_match.h +++ b/src/mongo/db/exec/text_match.h @@ -69,20 +69,12 @@ public: StageState work(WorkingSetID* out) final; - void saveState() final; - void restoreState(OperationContext* opCtx) final; - void invalidate(OperationContext* txn, const RecordId& dl, InvalidationType type) final; - - std::vector<PlanStage*> getChildren() const final; - StageType stageType() const final { return STAGE_TEXT_MATCH; } std::unique_ptr<PlanStageStats> getStats() final; - const CommonStats* getCommonStats() const final; - const SpecificStats* getSpecificStats() const final; static const char* kStageType; @@ -94,11 +86,6 @@ private: // Not owned by us. WorkingSet* _ws; - // The child PlanStage that provides the RecordIDs and scores for text matching. - unique_ptr<PlanStage> _child; - - // Stats - CommonStats _commonStats; TextMatchStats _specificStats; }; } // namespace mongo diff --git a/src/mongo/db/exec/text_or.cpp b/src/mongo/db/exec/text_or.cpp index be600e3639d..d1e57871593 100644 --- a/src/mongo/db/exec/text_or.cpp +++ b/src/mongo/db/exec/text_or.cpp @@ -59,10 +59,10 @@ TextOrStage::TextOrStage(OperationContext* txn, WorkingSet* ws, const MatchExpression* filter, IndexDescriptor* index) - : _ftsSpec(ftsSpec), + : PlanStage(kStageType), + _ftsSpec(ftsSpec), _ws(ws), _scoreIterator(_scores.end()), - _commonStats(kStageType), _filter(filter), _txn(txn), _idRetrying(WorkingSet::INVALID_ID), @@ -78,41 +78,22 @@ bool TextOrStage::isEOF() { return _internalState == State::kDone; } -void TextOrStage::saveState() { +void TextOrStage::doSaveState() { _txn = NULL; - ++_commonStats.yields; - - for (auto& child : _children) { - child->saveState(); - } - if (_recordCursor) { _recordCursor->saveUnpositioned(); } } -void TextOrStage::restoreState(OperationContext* opCtx) { +void TextOrStage::doRestoreState(OperationContext* opCtx) { invariant(_txn == NULL); _txn = opCtx; - ++_commonStats.unyields; - - for (auto& child : _children) { - child->restoreState(opCtx); - } - if (_recordCursor) { invariant(_recordCursor->restore(opCtx)); } } -void TextOrStage::invalidate(OperationContext* txn, const RecordId& dl, InvalidationType type) { - ++_commonStats.invalidates; - - // Propagate invalidate to children. - for (auto& child : _children) { - child->invalidate(txn, dl, type); - } - +void TextOrStage::doInvalidate(OperationContext* txn, const RecordId& dl, InvalidationType type) { // Remove the RecordID from the ScoreMap. ScoreMap::iterator scoreIt = _scores.find(dl); if (scoreIt != _scores.end()) { @@ -123,14 +104,6 @@ void TextOrStage::invalidate(OperationContext* txn, const RecordId& dl, Invalida } } -vector<PlanStage*> TextOrStage::getChildren() const { - std::vector<PlanStage*> vec; - for (auto& child : _children) { - vec.push_back(child.get()); - } - return vec; -} - std::unique_ptr<PlanStageStats> TextOrStage::getStats() { _commonStats.isEOF = isEOF(); @@ -150,10 +123,6 @@ std::unique_ptr<PlanStageStats> TextOrStage::getStats() { return ret; } -const CommonStats* TextOrStage::getCommonStats() const { - return &_commonStats; -} - const SpecificStats* TextOrStage::getSpecificStats() const { return &_specificStats; } diff --git a/src/mongo/db/exec/text_or.h b/src/mongo/db/exec/text_or.h index 4de8b5bade2..a51a91a3919 100644 --- a/src/mongo/db/exec/text_or.h +++ b/src/mongo/db/exec/text_or.h @@ -86,11 +86,9 @@ public: StageState work(WorkingSetID* out) final; - void saveState() final; - void restoreState(OperationContext* opCtx) final; - void invalidate(OperationContext* txn, const RecordId& dl, InvalidationType type) final; - - std::vector<PlanStage*> getChildren() const final; + void doSaveState() final; + void doRestoreState(OperationContext* opCtx) final; + void doInvalidate(OperationContext* txn, const RecordId& dl, InvalidationType type) final; StageType stageType() const final { return STAGE_TEXT_OR; @@ -98,8 +96,6 @@ public: std::unique_ptr<PlanStageStats> getStats() final; - const CommonStats* getCommonStats() const final; - const SpecificStats* getSpecificStats() const final; static const char* kStageType; @@ -137,9 +133,6 @@ private: // What state are we in? See the State enum above. State _internalState = State::kInit; - // Children owned by us. - vector<unique_ptr<PlanStage>> _children; - // Which of _children are we calling work(...) on now? size_t _currentChild = 0; @@ -158,8 +151,6 @@ private: ScoreMap _scores; ScoreMap::const_iterator _scoreIterator; - // Stats - CommonStats _commonStats; TextOrStats _specificStats; // Members needed only for using the TextMatchableDocument. diff --git a/src/mongo/db/exec/update.cpp b/src/mongo/db/exec/update.cpp index 9a523c4756b..970137bc6e9 100644 --- a/src/mongo/db/exec/update.cpp +++ b/src/mongo/db/exec/update.cpp @@ -415,16 +415,16 @@ UpdateStage::UpdateStage(OperationContext* txn, WorkingSet* ws, Collection* collection, PlanStage* child) - : _txn(txn), + : PlanStage(kStageType), + _txn(txn), _params(params), _ws(ws), _collection(collection), - _child(child), _idRetrying(WorkingSet::INVALID_ID), _idReturning(WorkingSet::INVALID_ID), - _commonStats(kStageType), _updatedLocs(params.request->isMulti() ? new DiskLocSet() : NULL), _doc(params.driver->getDocument()) { + _children.emplace_back(child); // We are an update until we fall into the insert case. params.driver->setContext(ModifierInterface::ExecInfo::UPDATE_CONTEXT); @@ -715,7 +715,7 @@ bool UpdateStage::doneUpdating() { // We're done updating if either the child has no more results to give us, or we've // already gotten a result back and we're not a multi-update. return _idRetrying == WorkingSet::INVALID_ID && _idReturning == WorkingSet::INVALID_ID && - (_child->isEOF() || (_specificStats.nMatched > 0 && !_params.request->isMulti())); + (child()->isEOF() || (_specificStats.nMatched > 0 && !_params.request->isMulti())); } bool UpdateStage::needInsert() { @@ -795,7 +795,7 @@ PlanStage::StageState UpdateStage::work(WorkingSetID* out) { WorkingSetID id; StageState status; if (_idRetrying == WorkingSet::INVALID_ID) { - status = _child->work(&id); + status = child()->work(&id); } else { status = ADVANCED; id = _idRetrying; @@ -855,7 +855,7 @@ PlanStage::StageState UpdateStage::work(WorkingSetID* out) { // Save state before making changes try { - _child->saveState(); + child()->saveState(); if (supportsDocLocking()) { // Doc-locking engines require this after saveState() since they don't use // invalidations. @@ -902,7 +902,7 @@ PlanStage::StageState UpdateStage::work(WorkingSetID* out) { // As restoreState may restore (recreate) cursors, make sure to restore the // state outside of the WritUnitOfWork. try { - _child->restoreState(_txn); + child()->restoreState(_txn); } catch (const WriteConflictException& wce) { // Note we don't need to retry updating anything in this case since the update // already was committed. However, we still need to return the updated document @@ -958,12 +958,6 @@ PlanStage::StageState UpdateStage::work(WorkingSetID* out) { return status; } -void UpdateStage::saveState() { - _txn = NULL; - ++_commonStats.yields; - _child->saveState(); -} - Status UpdateStage::restoreUpdateState(OperationContext* opCtx) { const UpdateRequest& request = *_params.request; const NamespaceString& nsString(request.getNamespaceString()); @@ -994,39 +988,20 @@ Status UpdateStage::restoreUpdateState(OperationContext* opCtx) { return Status::OK(); } -void UpdateStage::restoreState(OperationContext* opCtx) { - invariant(_txn == NULL); +void UpdateStage::doRestoreState(OperationContext* opCtx) { _txn = opCtx; - ++_commonStats.unyields; - // Restore our child. - _child->restoreState(opCtx); - // Restore self. uassertStatusOK(restoreUpdateState(opCtx)); } -void UpdateStage::invalidate(OperationContext* txn, const RecordId& dl, InvalidationType type) { - ++_commonStats.invalidates; - _child->invalidate(txn, dl, type); -} - -vector<PlanStage*> UpdateStage::getChildren() const { - vector<PlanStage*> children; - children.push_back(_child.get()); - return children; -} unique_ptr<PlanStageStats> UpdateStage::getStats() { _commonStats.isEOF = isEOF(); unique_ptr<PlanStageStats> ret = make_unique<PlanStageStats>(_commonStats, STAGE_UPDATE); ret->specific = make_unique<UpdateStats>(_specificStats); - ret->children.push_back(_child->getStats().release()); + ret->children.push_back(child()->getStats().release()); return ret; } -const CommonStats* UpdateStage::getCommonStats() const { - return &_commonStats; -} - const SpecificStats* UpdateStage::getSpecificStats() const { return &_specificStats; } diff --git a/src/mongo/db/exec/update.h b/src/mongo/db/exec/update.h index b0dda4ffc4c..4d59dca50f2 100644 --- a/src/mongo/db/exec/update.h +++ b/src/mongo/db/exec/update.h @@ -84,11 +84,7 @@ public: virtual bool isEOF(); virtual StageState work(WorkingSetID* out); - virtual void saveState(); - virtual void restoreState(OperationContext* opCtx); - virtual void invalidate(OperationContext* txn, const RecordId& dl, InvalidationType type); - - virtual std::vector<PlanStage*> getChildren() const; + virtual void doRestoreState(OperationContext* opCtx); virtual StageType stageType() const { return STAGE_UPDATE; @@ -96,8 +92,6 @@ public: virtual std::unique_ptr<PlanStageStats> getStats(); - virtual const CommonStats* getCommonStats() const; - virtual const SpecificStats* getSpecificStats() const; static const char* kStageType; @@ -182,9 +176,6 @@ private: // Not owned by us. May be NULL. Collection* _collection; - // Owned by us. - std::unique_ptr<PlanStage> _child; - // If not WorkingSet::INVALID_ID, we use this rather than asking our child what to do next. WorkingSetID _idRetrying; @@ -192,7 +183,6 @@ private: WorkingSetID _idReturning; // Stats - CommonStats _commonStats; UpdateStats _specificStats; // If the update was in-place, we may see it again. This only matters if we're doing diff --git a/src/mongo/db/query/explain.cpp b/src/mongo/db/query/explain.cpp index 28aa656fbe5..895c4a6fa88 100644 --- a/src/mongo/db/query/explain.cpp +++ b/src/mongo/db/query/explain.cpp @@ -66,9 +66,9 @@ void flattenStatsTree(const PlanStageStats* root, vector<const PlanStageStats*>* */ void flattenExecTree(const PlanStage* root, vector<const PlanStage*>* flattened) { flattened->push_back(root); - vector<PlanStage*> children = root->getChildren(); + const auto& children = root->getChildren(); for (size_t i = 0; i < children.size(); ++i) { - flattenExecTree(children[i], flattened); + flattenExecTree(children[i].get(), flattened); } } @@ -82,9 +82,9 @@ MultiPlanStage* getMultiPlanStage(PlanStage* root) { return mps; } - vector<PlanStage*> children = root->getChildren(); + const auto& children = root->getChildren(); for (size_t i = 0; i < children.size(); i++) { - MultiPlanStage* mps = getMultiPlanStage(children[i]); + MultiPlanStage* mps = getMultiPlanStage(children[i].get()); if (mps != NULL) { return mps; } diff --git a/src/mongo/db/query/plan_executor.cpp b/src/mongo/db/query/plan_executor.cpp index 3c216ba313e..dfc97724b6f 100644 --- a/src/mongo/db/query/plan_executor.cpp +++ b/src/mongo/db/query/plan_executor.cpp @@ -66,9 +66,9 @@ PlanStage* getStageByType(PlanStage* root, StageType type) { return root; } - vector<PlanStage*> children = root->getChildren(); + const auto& children = root->getChildren(); for (size_t i = 0; i < children.size(); i++) { - PlanStage* result = getStageByType(children[i], type); + PlanStage* result = getStageByType(children[i].get(), type); if (result) { return result; } diff --git a/src/mongo/db/query/plan_ranker.h b/src/mongo/db/query/plan_ranker.h index 653fb332f12..1ae03b083ee 100644 --- a/src/mongo/db/query/plan_ranker.h +++ b/src/mongo/db/query/plan_ranker.h @@ -29,6 +29,7 @@ #pragma once #include <list> +#include <memory> #include <vector> #include "mongo/base/owned_pointer_vector.h" @@ -71,9 +72,27 @@ struct CandidatePlan { CandidatePlan(QuerySolution* s, PlanStage* r, WorkingSet* w) : solution(s), root(r), ws(w), failed(false) {} - QuerySolution* solution; - PlanStage* root; - WorkingSet* ws; +#if defined(_MSC_VER) && _MSC_VER < 1900 // MVSC++ <= 2013 can't generate default move operations + CandidatePlan(CandidatePlan&& other) + : solution(std::move(other.solution)), + root(std::move(other.root)), + ws(std::move(other.ws)), + results(std::move(other.results)), + failed(std::move(other.failed)) {} + + CandidatePlan& operator=(CandidatePlan&& other) { + solution = std::move(other.solution); + root = std::move(other.root); + ws = std::move(other.ws); + results = std::move(other.results); + failed = std::move(other.failed); + return *this; + } +#endif + + std::unique_ptr<QuerySolution> solution; + PlanStage* root; // Not owned here. + WorkingSet* ws; // Not owned here. // Any results produced during the plan's execution prior to ranking are retained here. std::list<WorkingSetID> results; diff --git a/src/mongo/db/s/migration_source_manager.cpp b/src/mongo/db/s/migration_source_manager.cpp index 96b575419f4..0e9d14d5f22 100644 --- a/src/mongo/db/s/migration_source_manager.cpp +++ b/src/mongo/db/s/migration_source_manager.cpp @@ -69,9 +69,9 @@ Tee* migrateLog = RamLog::get("migrate"); class DeleteNotificationStage final : public PlanStage { public: DeleteNotificationStage(MigrationSourceManager* migrationSourceManager) - : _migrationSourceManager(migrationSourceManager) {} + : PlanStage("NOTIFY_DELETE"), _migrationSourceManager(migrationSourceManager) {} - void invalidate(OperationContext* txn, const RecordId& dl, InvalidationType type) override { + void doInvalidate(OperationContext* txn, const RecordId& dl, InvalidationType type) override { if (type == INVALIDATION_DELETION) { _migrationSourceManager->aboutToDelete(dl); } @@ -85,32 +85,14 @@ public: MONGO_UNREACHABLE; } - virtual void kill() {} - - virtual void saveState() { - MONGO_UNREACHABLE; - } - - virtual void restoreState(OperationContext* opCtx) { - MONGO_UNREACHABLE; - } - virtual unique_ptr<PlanStageStats> getStats() { MONGO_UNREACHABLE; } - virtual CommonStats* getCommonStats() const { - MONGO_UNREACHABLE; - } - virtual SpecificStats* getSpecificStats() const { MONGO_UNREACHABLE; } - virtual std::vector<PlanStage*> getChildren() const { - return {}; - } - virtual StageType stageType() const { return STAGE_NOTIFY_DELETE; } diff --git a/src/mongo/dbtests/query_stage_near.cpp b/src/mongo/dbtests/query_stage_near.cpp index f7694d19018..0832dbf77cb 100644 --- a/src/mongo/dbtests/query_stage_near.cpp +++ b/src/mongo/dbtests/query_stage_near.cpp @@ -52,12 +52,12 @@ using stdx::make_unique; class MockStage : public PlanStage { public: MockStage(const vector<BSONObj>& data, WorkingSet* workingSet) - : _data(data), _pos(0), _workingSet(workingSet), _stats("MOCK_STAGE") {} + : PlanStage("MOCK_STAGE"), _data(data), _pos(0), _workingSet(workingSet) {} virtual ~MockStage() {} virtual StageState work(WorkingSetID* out) { - ++_stats.works; + ++_commonStats.works; if (isEOF()) return PlanStage::IS_EOF; @@ -82,25 +82,12 @@ public: return _pos == static_cast<int>(_data.size()); } - virtual void saveState() {} - - virtual void restoreState(OperationContext* opCtx) {} - - virtual void invalidate(OperationContext* txn, const RecordId& dl, InvalidationType type) {} - virtual vector<PlanStage*> getChildren() const { - return vector<PlanStage*>(); - } - virtual StageType stageType() const { return STAGE_UNKNOWN; } virtual unique_ptr<PlanStageStats> getStats() { - return make_unique<PlanStageStats>(_stats, STAGE_UNKNOWN); - } - - virtual const CommonStats* getCommonStats() const { - return &_stats; + return make_unique<PlanStageStats>(_commonStats, STAGE_UNKNOWN); } virtual const SpecificStats* getSpecificStats() const { @@ -113,8 +100,6 @@ private: // Not owned here WorkingSet* const _workingSet; - - CommonStats _stats; }; /** @@ -133,11 +118,7 @@ public: }; MockNearStage(WorkingSet* workingSet) - : NearStage(NULL, - workingSet, - NULL, - new PlanStageStats(CommonStats("MOCK_DISTANCE_SEARCH_STAGE"), STAGE_UNKNOWN)), - _pos(0) {} + : NearStage(NULL, "MOCK_DISTANCE_SEARCH_STAGE", STAGE_UNKNOWN, workingSet, NULL), _pos(0) {} virtual ~MockNearStage() {} @@ -154,12 +135,9 @@ public: const MockInterval& interval = *_intervals.vector()[_pos++]; bool lastInterval = _pos == static_cast<int>(_intervals.vector().size()); - return StatusWith<CoveredInterval*>( - new CoveredInterval(new MockStage(interval.data, workingSet), - true, - interval.min, - interval.max, - lastInterval)); + _children.emplace_back(new MockStage(interval.data, workingSet)); + return StatusWith<CoveredInterval*>(new CoveredInterval( + _children.back().get(), true, interval.min, interval.max, lastInterval)); } virtual StatusWith<double> computeDistance(WorkingSetMember* member) { @@ -174,14 +152,6 @@ public: return IS_EOF; } - virtual void finishSaveState() {} - - virtual void finishRestoreState(OperationContext* txn) {} - - virtual void finishInvalidate(OperationContext* txn, - const RecordId& dl, - InvalidationType type) {} - private: OwnedPointerVector<MockInterval> _intervals; int _pos; diff --git a/src/mongo/dbtests/query_stage_sort.cpp b/src/mongo/dbtests/query_stage_sort.cpp index b49ccc9dec8..b28abb5b1d5 100644 --- a/src/mongo/dbtests/query_stage_sort.cpp +++ b/src/mongo/dbtests/query_stage_sort.cpp @@ -317,7 +317,7 @@ public: unique_ptr<PlanExecutor> exec(makePlanExecutorWithSortStage(coll)); SortStage* ss = static_cast<SortStage*>(exec->getRootStage()); - QueuedDataStage* ms = static_cast<QueuedDataStage*>(ss->getChildren()[0]); + QueuedDataStage* ms = static_cast<QueuedDataStage*>(ss->getChildren()[0].get()); // Have sort read in data from the queued data stage. const int firstRead = 5; @@ -426,7 +426,7 @@ public: unique_ptr<PlanExecutor> exec(makePlanExecutorWithSortStage(coll)); SortStage* ss = static_cast<SortStage*>(exec->getRootStage()); - QueuedDataStage* ms = static_cast<QueuedDataStage*>(ss->getChildren()[0]); + QueuedDataStage* ms = static_cast<QueuedDataStage*>(ss->getChildren()[0].get()); const int firstRead = 10; // Have sort read in data from the queued data stage. |