diff options
-rw-r--r-- | src/mongo/db/exec/count_scan.cpp | 53 | ||||
-rw-r--r-- | src/mongo/db/exec/count_scan.h | 66 | ||||
-rw-r--r-- | src/mongo/db/exec/distinct_scan.cpp | 44 | ||||
-rw-r--r-- | src/mongo/db/exec/distinct_scan.h | 58 | ||||
-rw-r--r-- | src/mongo/db/exec/idhack.cpp | 30 | ||||
-rw-r--r-- | src/mongo/db/exec/idhack.h | 24 | ||||
-rw-r--r-- | src/mongo/db/exec/text.cpp | 8 | ||||
-rw-r--r-- | src/mongo/db/exec/text.h | 2 | ||||
-rw-r--r-- | src/mongo/db/exec/text_or.cpp | 15 | ||||
-rw-r--r-- | src/mongo/db/exec/text_or.h | 16 | ||||
-rw-r--r-- | src/mongo/db/query/get_executor.cpp | 8 | ||||
-rw-r--r-- | src/mongo/db/query/internal_plans.cpp | 2 | ||||
-rw-r--r-- | src/mongo/db/query/stage_builder.cpp | 4 | ||||
-rw-r--r-- | src/mongo/dbtests/query_stage_count_scan.cpp | 18 | ||||
-rw-r--r-- | src/mongo/dbtests/query_stage_distinct.cpp | 7 |
15 files changed, 160 insertions, 195 deletions
diff --git a/src/mongo/db/exec/count_scan.cpp b/src/mongo/db/exec/count_scan.cpp index 2df35f1c223..09bba26072c 100644 --- a/src/mongo/db/exec/count_scan.cpp +++ b/src/mongo/db/exec/count_scan.cpp @@ -75,25 +75,30 @@ const char* CountScan::kStageType = "COUNT_SCAN"; // the CountScanParams rather than resolving them via the IndexDescriptor, since these may differ // from the descriptor's contents. CountScan::CountScan(OperationContext* opCtx, CountScanParams params, WorkingSet* workingSet) - : PlanStage(kStageType, opCtx), + : RequiresIndexStage(kStageType, opCtx, params.indexDescriptor), _workingSet(workingSet), - _iam(params.accessMethod), + _keyPattern(std::move(params.keyPattern)), _shouldDedup(params.isMultiKey), - _params(std::move(params)) { - _specificStats.indexName = _params.name; - _specificStats.keyPattern = _params.keyPattern; - _specificStats.isMultiKey = _params.isMultiKey; - _specificStats.multiKeyPaths = _params.multikeyPaths; - _specificStats.isUnique = _params.isUnique; - _specificStats.isSparse = _params.isSparse; - _specificStats.isPartial = _params.isPartial; - _specificStats.indexVersion = static_cast<int>(_params.version); - _specificStats.collation = _params.collation.getOwned(); + _startKey(std::move(params.startKey)), + _startKeyInclusive(params.startKeyInclusive), + _endKey(std::move(params.endKey)), + _endKeyInclusive(params.endKeyInclusive) { + _specificStats.indexName = params.name; + _specificStats.keyPattern = _keyPattern; + _specificStats.isMultiKey = params.isMultiKey; + _specificStats.multiKeyPaths = params.multikeyPaths; + _specificStats.isUnique = params.indexDescriptor->unique(); + _specificStats.isSparse = params.indexDescriptor->isSparse(); + _specificStats.isPartial = params.indexDescriptor->isPartial(); + _specificStats.indexVersion = static_cast<int>(params.indexDescriptor->version()); + _specificStats.collation = params.indexDescriptor->infoObj() + .getObjectField(IndexDescriptor::kCollationFieldName) + .getOwned(); // endKey must be after startKey in index order since we only do forward scans. - dassert(_params.startKey.woCompare(_params.endKey, - Ordering::make(_params.keyPattern), - /*compareFieldNames*/ false) <= 0); + dassert(_startKey.woCompare(_endKey, + Ordering::make(_keyPattern), + /*compareFieldNames*/ false) <= 0); } PlanStage::StageState CountScan::doWork(WorkingSetID* out) { @@ -108,10 +113,10 @@ PlanStage::StageState CountScan::doWork(WorkingSetID* out) { if (needInit) { // First call to work(). Perform cursor init. - _cursor = _iam->newCursor(getOpCtx()); - _cursor->setEndPosition(_params.endKey, _params.endKeyInclusive); + _cursor = indexAccessMethod()->newCursor(getOpCtx()); + _cursor->setEndPosition(_endKey, _endKeyInclusive); - entry = _cursor->seek(_params.startKey, _params.startKeyInclusive, kWantLoc); + entry = _cursor->seek(_startKey, _startKeyInclusive, kWantLoc); } else { entry = _cursor->next(kWantLoc); } @@ -147,12 +152,12 @@ bool CountScan::isEOF() { return _commonStats.isEOF; } -void CountScan::doSaveState() { +void CountScan::doSaveStateRequiresIndex() { if (_cursor) _cursor->save(); } -void CountScan::doRestoreState() { +void CountScan::doRestoreStateRequiresIndex() { if (_cursor) _cursor->restore(); } @@ -173,10 +178,10 @@ unique_ptr<PlanStageStats> CountScan::getStats() { unique_ptr<CountScanStats> countStats = make_unique<CountScanStats>(_specificStats); countStats->keyPattern = _specificStats.keyPattern.getOwned(); - countStats->startKey = replaceBSONFieldNames(_params.startKey, countStats->keyPattern); - countStats->startKeyInclusive = _params.startKeyInclusive; - countStats->endKey = replaceBSONFieldNames(_params.endKey, countStats->keyPattern); - countStats->endKeyInclusive = _params.endKeyInclusive; + countStats->startKey = replaceBSONFieldNames(_startKey, countStats->keyPattern); + countStats->startKeyInclusive = _startKeyInclusive; + countStats->endKey = replaceBSONFieldNames(_endKey, countStats->keyPattern); + countStats->endKeyInclusive = _endKeyInclusive; ret->specific = std::move(countStats); diff --git a/src/mongo/db/exec/count_scan.h b/src/mongo/db/exec/count_scan.h index dd831951f49..c4b4ea23123 100644 --- a/src/mongo/db/exec/count_scan.h +++ b/src/mongo/db/exec/count_scan.h @@ -30,10 +30,7 @@ #pragma once -#include "mongo/db/exec/plan_stage.h" -#include "mongo/db/index/index_access_method.h" -#include "mongo/db/index/index_descriptor.h" -#include "mongo/db/jsobj.h" +#include "mongo/db/exec/requires_index_stage.h" #include "mongo/db/matcher/expression.h" #include "mongo/db/operation_context.h" #include "mongo/db/record_id.h" @@ -44,34 +41,27 @@ namespace mongo { class WorkingSet; struct CountScanParams { - CountScanParams(const IndexDescriptor& descriptor, + CountScanParams(const IndexDescriptor* descriptor, std::string indexName, BSONObj keyPattern, MultikeyPaths multikeyPaths, bool multikey) - : accessMethod(descriptor.getIndexCatalog()->getIndex(&descriptor)), + : indexDescriptor(descriptor), name(std::move(indexName)), keyPattern(std::move(keyPattern)), multikeyPaths(std::move(multikeyPaths)), - isMultiKey(multikey), - isSparse(descriptor.isSparse()), - isUnique(descriptor.unique()), - isPartial(descriptor.isPartial()), - version(descriptor.version()), - collation(descriptor.infoObj() - .getObjectField(IndexDescriptor::kCollationFieldName) - .getOwned()) { - invariant(accessMethod); + isMultiKey(multikey) { + invariant(descriptor); } - CountScanParams(OperationContext* opCtx, const IndexDescriptor& descriptor) + CountScanParams(OperationContext* opCtx, const IndexDescriptor* descriptor) : CountScanParams(descriptor, - descriptor.indexName(), - descriptor.keyPattern(), - descriptor.getMultikeyPaths(opCtx), - descriptor.isMultikey(opCtx)) {} + descriptor->indexName(), + descriptor->keyPattern(), + descriptor->getMultikeyPaths(opCtx), + descriptor->isMultikey(opCtx)) {} - const IndexAccessMethod* accessMethod; + const IndexDescriptor* indexDescriptor; std::string name; BSONObj keyPattern; @@ -79,14 +69,6 @@ struct CountScanParams { MultikeyPaths multikeyPaths; bool isMultiKey; - bool isSparse; - bool isUnique; - bool isPartial; - - IndexDescriptor::IndexVersion version; - - BSONObj collation; - BSONObj startKey; bool startKeyInclusive{true}; @@ -103,14 +85,12 @@ struct CountScanParams { * Only created through the getExecutorCount() path, as count is the only operation that doesn't * care about its data. */ -class CountScan final : public PlanStage { +class CountScan final : public RequiresIndexStage { public: CountScan(OperationContext* opCtx, CountScanParams params, WorkingSet* workingSet); StageState doWork(WorkingSetID* out) final; bool isEOF() final; - void doSaveState() final; - void doRestoreState() final; void doDetachFromOperationContext() final; void doReattachToOperationContext() final; @@ -124,21 +104,31 @@ public: static const char* kStageType; +protected: + void doSaveStateRequiresIndex() final; + + void doRestoreStateRequiresIndex() final; + private: // The WorkingSet we annotate with results. Not owned by us. WorkingSet* _workingSet; - // Index access. The pointer below is owned by Collection -> IndexCatalog. - const IndexAccessMethod* _iam; + const BSONObj _keyPattern; + + const bool _shouldDedup; + + const BSONObj _startKey; + const bool _startKeyInclusive = true; + + const BSONObj _endKey; + const bool _endKeyInclusive = true; std::unique_ptr<SortedDataInterface::Cursor> _cursor; - // Could our index have duplicates? If so, we use _returned to dedup. - const bool _shouldDedup; + // The set of record ids we've returned so far. Used to avoid returning duplicates, if + // '_shouldDedup' is set to true. stdx::unordered_set<RecordId, RecordId::Hasher> _returned; - CountScanParams _params; - CountScanStats _specificStats; }; diff --git a/src/mongo/db/exec/distinct_scan.cpp b/src/mongo/db/exec/distinct_scan.cpp index 6add722db0e..bcdfd79fff4 100644 --- a/src/mongo/db/exec/distinct_scan.cpp +++ b/src/mongo/db/exec/distinct_scan.cpp @@ -49,21 +49,25 @@ using stdx::make_unique; const char* DistinctScan::kStageType = "DISTINCT_SCAN"; DistinctScan::DistinctScan(OperationContext* opCtx, DistinctParams params, WorkingSet* workingSet) - : PlanStage(kStageType, opCtx), - _params(std::move(params)), + : RequiresIndexStage(kStageType, opCtx, params.indexDescriptor), _workingSet(workingSet), - _iam(_params.accessMethod), - _checker(&_params.bounds, _params.keyPattern, _params.scanDirection) { - _specificStats.keyPattern = _params.keyPattern; - _specificStats.indexName = _params.name; - _specificStats.indexVersion = static_cast<int>(_params.version); - _specificStats.isMultiKey = _params.isMultiKey; - _specificStats.multiKeyPaths = _params.multikeyPaths; - _specificStats.isUnique = _params.isUnique; - _specificStats.isSparse = _params.isSparse; - _specificStats.isPartial = _params.isPartial; - _specificStats.direction = _params.scanDirection; - _specificStats.collation = _params.collation.getOwned(); + _keyPattern(std::move(params.keyPattern)), + _scanDirection(params.scanDirection), + _bounds(std::move(params.bounds)), + _fieldNo(params.fieldNo), + _checker(&_bounds, _keyPattern, _scanDirection) { + _specificStats.keyPattern = _keyPattern; + _specificStats.indexName = params.name; + _specificStats.indexVersion = static_cast<int>(params.indexDescriptor->version()); + _specificStats.isMultiKey = params.isMultiKey; + _specificStats.multiKeyPaths = params.multikeyPaths; + _specificStats.isUnique = params.indexDescriptor->unique(); + _specificStats.isSparse = params.indexDescriptor->isSparse(); + _specificStats.isPartial = params.indexDescriptor->isPartial(); + _specificStats.direction = _scanDirection; + _specificStats.collation = params.indexDescriptor->infoObj() + .getObjectField(IndexDescriptor::kCollationFieldName) + .getOwned(); // Set up our initial seek. If there is no valid data, just mark as EOF. _commonStats.isEOF = !_checker.getStartSeekPoint(&_seekPoint); @@ -76,7 +80,7 @@ PlanStage::StageState DistinctScan::doWork(WorkingSetID* out) { boost::optional<IndexKeyEntry> kv; try { if (!_cursor) - _cursor = _iam->newCursor(getOpCtx(), _params.scanDirection == 1); + _cursor = indexAccessMethod()->newCursor(getOpCtx(), _scanDirection == 1); kv = _cursor->seek(_seekPoint); } catch (const WriteConflictException&) { *out = WorkingSet::INVALID_ID; @@ -108,14 +112,14 @@ PlanStage::StageState DistinctScan::doWork(WorkingSetID* out) { if (!kv->key.isOwned()) kv->key = kv->key.getOwned(); _seekPoint.keyPrefix = kv->key; - _seekPoint.prefixLen = _params.fieldNo + 1; + _seekPoint.prefixLen = _fieldNo + 1; _seekPoint.prefixExclusive = true; // Package up the result for the caller. WorkingSetID id = _workingSet->allocate(); WorkingSetMember* member = _workingSet->get(id); member->recordId = kv->loc; - member->keyData.push_back(IndexKeyDatum(_params.keyPattern, kv->key, _iam)); + member->keyData.push_back(IndexKeyDatum(_keyPattern, kv->key, indexAccessMethod())); _workingSet->transitionToRecordIdAndIdx(id); *out = id; @@ -128,13 +132,13 @@ bool DistinctScan::isEOF() { return _commonStats.isEOF; } -void DistinctScan::doSaveState() { +void DistinctScan::doSaveStateRequiresIndex() { // We always seek, so we don't care where the cursor is. if (_cursor) _cursor->saveUnpositioned(); } -void DistinctScan::doRestoreState() { +void DistinctScan::doRestoreStateRequiresIndex() { if (_cursor) _cursor->restore(); } @@ -154,7 +158,7 @@ unique_ptr<PlanStageStats> DistinctScan::getStats() { // the constructor in order to avoid the expensive serialization operation unless the distinct // command is being explained. if (_specificStats.indexBounds.isEmpty()) { - _specificStats.indexBounds = _params.bounds.toBSON(); + _specificStats.indexBounds = _bounds.toBSON(); } unique_ptr<PlanStageStats> ret = make_unique<PlanStageStats>(_commonStats, STAGE_DISTINCT_SCAN); diff --git a/src/mongo/db/exec/distinct_scan.h b/src/mongo/db/exec/distinct_scan.h index c1b86aa8e83..37fbac616db 100644 --- a/src/mongo/db/exec/distinct_scan.h +++ b/src/mongo/db/exec/distinct_scan.h @@ -31,9 +31,8 @@ #pragma once -#include "mongo/db/exec/plan_stage.h" +#include "mongo/db/exec/requires_index_stage.h" #include "mongo/db/index/index_access_method.h" -#include "mongo/db/jsobj.h" #include "mongo/db/matcher/expression.h" #include "mongo/db/query/index_bounds.h" #include "mongo/db/record_id.h" @@ -45,34 +44,27 @@ class IndexDescriptor; class WorkingSet; struct DistinctParams { - DistinctParams(const IndexDescriptor& descriptor, + DistinctParams(const IndexDescriptor* descriptor, std::string indexName, BSONObj keyPattern, MultikeyPaths multikeyPaths, bool multikey) - : accessMethod(descriptor.getIndexCatalog()->getIndex(&descriptor)), + : indexDescriptor(descriptor), name(std::move(indexName)), keyPattern(std::move(keyPattern)), multikeyPaths(std::move(multikeyPaths)), - isMultiKey(multikey), - isSparse(descriptor.isSparse()), - isUnique(descriptor.unique()), - isPartial(descriptor.isPartial()), - version(descriptor.version()), - collation(descriptor.infoObj() - .getObjectField(IndexDescriptor::kCollationFieldName) - .getOwned()) { - invariant(accessMethod); + isMultiKey(multikey) { + invariant(indexDescriptor); } - DistinctParams(OperationContext* opCtx, const IndexDescriptor& descriptor) + DistinctParams(OperationContext* opCtx, const IndexDescriptor* descriptor) : DistinctParams(descriptor, - descriptor.indexName(), - descriptor.keyPattern(), - descriptor.getMultikeyPaths(opCtx), - descriptor.isMultikey(opCtx)) {} + descriptor->indexName(), + descriptor->keyPattern(), + descriptor->getMultikeyPaths(opCtx), + descriptor->isMultikey(opCtx)) {} - const IndexAccessMethod* accessMethod; + const IndexDescriptor* indexDescriptor; std::string name; BSONObj keyPattern; @@ -80,14 +72,6 @@ struct DistinctParams { MultikeyPaths multikeyPaths; bool isMultiKey; - bool isSparse; - bool isUnique; - bool isPartial; - - IndexDescriptor::IndexVersion version; - - BSONObj collation; - int scanDirection{1}; // What are the bounds? @@ -110,14 +94,12 @@ struct DistinctParams { * * Only created through the getExecutorDistinct path. See db/query/get_executor.cpp */ -class DistinctScan final : public PlanStage { +class DistinctScan final : public RequiresIndexStage { public: DistinctScan(OperationContext* opCtx, DistinctParams params, WorkingSet* workingSet); StageState doWork(WorkingSetID* out) final; bool isEOF() final; - void doSaveState() final; - void doRestoreState() final; void doDetachFromOperationContext() final; void doReattachToOperationContext() final; @@ -131,14 +113,22 @@ public: static const char* kStageType; -private: - // The parameters used to configure this DistinctScan stage. - DistinctParams _params; +protected: + void doSaveStateRequiresIndex() final; + + void doRestoreStateRequiresIndex() final; +private: // The WorkingSet we annotate with results. Not owned by us. WorkingSet* _workingSet; - const IndexAccessMethod* _iam; + const BSONObj _keyPattern; + + const int _scanDirection = 1; + + const IndexBounds _bounds; + + const int _fieldNo = 0; // The cursor we use to navigate the tree. std::unique_ptr<SortedDataInterface::Cursor> _cursor; diff --git a/src/mongo/db/exec/idhack.cpp b/src/mongo/db/exec/idhack.cpp index e2c67d70f09..3ffec7cfeb9 100644 --- a/src/mongo/db/exec/idhack.cpp +++ b/src/mongo/db/exec/idhack.cpp @@ -52,40 +52,24 @@ using stdx::make_unique; const char* IDHackStage::kStageType = "IDHACK"; IDHackStage::IDHackStage(OperationContext* opCtx, - const Collection* collection, CanonicalQuery* query, WorkingSet* ws, const IndexDescriptor* descriptor) - : PlanStage(kStageType, opCtx), - _collection(collection), + : RequiresIndexStage(kStageType, opCtx, descriptor), _workingSet(ws), - _key(query->getQueryObj()["_id"].wrap()), - _done(false) { - const IndexCatalog* catalog = _collection->getIndexCatalog(); + _key(query->getQueryObj()["_id"].wrap()) { _specificStats.indexName = descriptor->indexName(); - _accessMethod = catalog->getIndex(descriptor); - if (NULL != query->getProj()) { _addKeyMetadata = query->getProj()->wantIndexKey(); - } else { - _addKeyMetadata = false; } } IDHackStage::IDHackStage(OperationContext* opCtx, - Collection* collection, const BSONObj& key, WorkingSet* ws, const IndexDescriptor* descriptor) - : PlanStage(kStageType, opCtx), - _collection(collection), - _workingSet(ws), - _key(key), - _done(false), - _addKeyMetadata(false) { - const IndexCatalog* catalog = _collection->getIndexCatalog(); + : RequiresIndexStage(kStageType, opCtx, descriptor), _workingSet(ws), _key(key) { _specificStats.indexName = descriptor->indexName(); - _accessMethod = catalog->getIndex(descriptor); } IDHackStage::~IDHackStage() {} @@ -102,7 +86,7 @@ PlanStage::StageState IDHackStage::doWork(WorkingSetID* out) { WorkingSetID id = WorkingSet::INVALID_ID; try { // Look up the key by going directly to the index. - RecordId recordId = _accessMethod->findSingle(getOpCtx(), _key); + RecordId recordId = indexAccessMethod()->findSingle(getOpCtx(), _key); // Key not found. if (recordId.isNull()) { @@ -120,7 +104,7 @@ PlanStage::StageState IDHackStage::doWork(WorkingSetID* out) { _workingSet->transitionToRecordIdAndIdx(id); if (!_recordCursor) - _recordCursor = _collection->getCursor(getOpCtx()); + _recordCursor = collection()->getCursor(getOpCtx()); // Find the document associated with 'id' in the collection's record store. if (!WorkingSetCommon::fetch(getOpCtx(), _workingSet, id, _recordCursor)) { @@ -159,12 +143,12 @@ PlanStage::StageState IDHackStage::advance(WorkingSetID id, return PlanStage::ADVANCED; } -void IDHackStage::doSaveState() { +void IDHackStage::doSaveStateRequiresIndex() { if (_recordCursor) _recordCursor->saveUnpositioned(); } -void IDHackStage::doRestoreState() { +void IDHackStage::doRestoreStateRequiresIndex() { if (_recordCursor) _recordCursor->restore(); } diff --git a/src/mongo/db/exec/idhack.h b/src/mongo/db/exec/idhack.h index 293d6adf80f..d2a0edb8756 100644 --- a/src/mongo/db/exec/idhack.h +++ b/src/mongo/db/exec/idhack.h @@ -32,8 +32,7 @@ #include <memory> -#include "mongo/db/catalog/collection.h" -#include "mongo/db/exec/plan_stage.h" +#include "mongo/db/exec/requires_index_stage.h" #include "mongo/db/query/canonical_query.h" #include "mongo/db/record_id.h" @@ -47,17 +46,15 @@ class RecordCursor; * the _id index always has the collection default collation, the IDHackStage can only be used when * the query's collation is equal to the collection default. */ -class IDHackStage final : public PlanStage { +class IDHackStage final : public RequiresIndexStage { public: /** Takes ownership of all the arguments -collection. */ IDHackStage(OperationContext* opCtx, - const Collection* collection, CanonicalQuery* query, WorkingSet* ws, const IndexDescriptor* descriptor); IDHackStage(OperationContext* opCtx, - Collection* collection, const BSONObj& key, WorkingSet* ws, const IndexDescriptor* descriptor); @@ -67,8 +64,6 @@ public: bool isEOF() final; StageState doWork(WorkingSetID* out) final; - void doSaveState() final; - void doRestoreState() final; void doDetachFromOperationContext() final; void doReattachToOperationContext() final; @@ -87,6 +82,11 @@ public: static const char* kStageType; +protected: + void doSaveStateRequiresIndex() final; + + void doRestoreStateRequiresIndex() final; + private: /** * Marks this stage as done, optionally adds key metadata, and returns PlanStage::ADVANCED. @@ -95,25 +95,19 @@ private: */ StageState advance(WorkingSetID id, WorkingSetMember* member, WorkingSetID* out); - // Not owned here. - const Collection* _collection; - std::unique_ptr<SeekableRecordCursor> _recordCursor; // The WorkingSet we annotate with results. Not owned by us. WorkingSet* _workingSet; - // Not owned here. - const IndexAccessMethod* _accessMethod; - // The value to match against the _id field. BSONObj _key; // Have we returned our one document? - bool _done; + bool _done = false; // Do we need to add index key metadata for returnKey? - bool _addKeyMetadata; + bool _addKeyMetadata = false; IDHackStats _specificStats; }; diff --git a/src/mongo/db/exec/text.cpp b/src/mongo/db/exec/text.cpp index 015b517b005..0d49ce314fd 100644 --- a/src/mongo/db/exec/text.cpp +++ b/src/mongo/db/exec/text.cpp @@ -100,6 +100,8 @@ unique_ptr<PlanStage> TextStage::buildTextTree(OperationContext* opCtx, WorkingSet* ws, const MatchExpression* filter, bool wantTextScore) const { + const auto* collection = _params.index->getCollection(); + // Get all the index scans for each term in our query. std::vector<std::unique_ptr<PlanStage>> indexScanList; for (const auto& term : _params.query.getTermsForBounds()) { @@ -122,7 +124,7 @@ unique_ptr<PlanStage> TextStage::buildTextTree(OperationContext* opCtx, if (wantTextScore) { // We use a TEXT_OR stage to get the union of the results from the index scans and then // compute their text scores. This is a blocking operation. - auto textScorer = make_unique<TextOrStage>(opCtx, _params.spec, ws, filter, _params.index); + auto textScorer = make_unique<TextOrStage>(opCtx, _params.spec, ws, filter, collection); textScorer->addChildren(std::move(indexScanList)); @@ -139,8 +141,8 @@ unique_ptr<PlanStage> TextStage::buildTextTree(OperationContext* opCtx, // add our own FETCH stage to satisfy the requirement of the TEXT_MATCH stage that its // WorkingSetMember inputs have fetched data. const MatchExpression* emptyFilter = nullptr; - auto fetchStage = make_unique<FetchStage>( - opCtx, ws, textSearcher.release(), emptyFilter, _params.index->getCollection()); + auto fetchStage = + make_unique<FetchStage>(opCtx, ws, textSearcher.release(), emptyFilter, collection); textMatchStage = make_unique<TextMatchStage>( opCtx, std::move(fetchStage), _params.query, _params.spec, ws); diff --git a/src/mongo/db/exec/text.h b/src/mongo/db/exec/text.h index 78df02ca5e9..c9cd2fcf038 100644 --- a/src/mongo/db/exec/text.h +++ b/src/mongo/db/exec/text.h @@ -51,7 +51,7 @@ struct TextStageParams { TextStageParams(const FTSSpec& s) : spec(s) {} // Text index descriptor. IndexCatalog owns this. - IndexDescriptor* index; + const IndexDescriptor* index; // Index spec. FTSSpec spec; diff --git a/src/mongo/db/exec/text_or.cpp b/src/mongo/db/exec/text_or.cpp index 04b754621bd..55cdf0a747b 100644 --- a/src/mongo/db/exec/text_or.cpp +++ b/src/mongo/db/exec/text_or.cpp @@ -59,16 +59,13 @@ TextOrStage::TextOrStage(OperationContext* opCtx, const FTSSpec& ftsSpec, WorkingSet* ws, const MatchExpression* filter, - IndexDescriptor* index) - : PlanStage(kStageType, opCtx), + const Collection* collection) + : RequiresCollectionStage(kStageType, opCtx, collection), _ftsSpec(ftsSpec), _ws(ws), _scoreIterator(_scores.end()), _filter(filter), - _idRetrying(WorkingSet::INVALID_ID), - _index(index) {} - -TextOrStage::~TextOrStage() {} + _idRetrying(WorkingSet::INVALID_ID) {} void TextOrStage::addChild(unique_ptr<PlanStage> child) { _children.push_back(std::move(child)); @@ -84,13 +81,13 @@ bool TextOrStage::isEOF() { return _internalState == State::kDone; } -void TextOrStage::doSaveState() { +void TextOrStage::doSaveStateRequiresCollection() { if (_recordCursor) { _recordCursor->saveUnpositioned(); } } -void TextOrStage::doRestoreState() { +void TextOrStage::doRestoreStateRequiresCollection() { if (_recordCursor) { invariant(_recordCursor->restore()); } @@ -158,7 +155,7 @@ PlanStage::StageState TextOrStage::doWork(WorkingSetID* out) { PlanStage::StageState TextOrStage::initStage(WorkingSetID* out) { *out = WorkingSet::INVALID_ID; try { - _recordCursor = _index->getCollection()->getCursor(getOpCtx()); + _recordCursor = collection()->getCursor(getOpCtx()); _internalState = State::kReadingTerms; return PlanStage::NEED_TIME; } catch (const WriteConflictException&) { diff --git a/src/mongo/db/exec/text_or.h b/src/mongo/db/exec/text_or.h index b66866156f0..eacf5fc18e5 100644 --- a/src/mongo/db/exec/text_or.h +++ b/src/mongo/db/exec/text_or.h @@ -32,10 +32,8 @@ #include <memory> -#include "mongo/db/catalog/collection.h" -#include "mongo/db/exec/plan_stage.h" +#include "mongo/db/exec/requires_collection_stage.h" #include "mongo/db/fts/fts_spec.h" -#include "mongo/db/index/index_descriptor.h" #include "mongo/db/matcher/expression.h" #include "mongo/db/record_id.h" @@ -51,7 +49,7 @@ class OperationContext; * * The WorkingSetMembers returned are fetched and in the LOC_AND_OBJ state. */ -class TextOrStage final : public PlanStage { +class TextOrStage final : public RequiresCollectionStage { public: /** * Internal states. @@ -74,8 +72,7 @@ public: const FTSSpec& ftsSpec, WorkingSet* ws, const MatchExpression* filter, - IndexDescriptor* index); - ~TextOrStage(); + const Collection* collection); void addChild(std::unique_ptr<PlanStage> child); @@ -85,8 +82,6 @@ public: StageState doWork(WorkingSetID* out) final; - void doSaveState() final; - void doRestoreState() final; void doDetachFromOperationContext() final; void doReattachToOperationContext() final; @@ -100,6 +95,11 @@ public: static const char* kStageType; +protected: + void doSaveStateRequiresCollection() final; + + void doRestoreStateRequiresCollection() final; + private: /** * Worker for kInit. Initializes the _recordCursor member and handles the potential for diff --git a/src/mongo/db/query/get_executor.cpp b/src/mongo/db/query/get_executor.cpp index e8c67924f94..d56410ec580 100644 --- a/src/mongo/db/query/get_executor.cpp +++ b/src/mongo/db/query/get_executor.cpp @@ -342,7 +342,7 @@ StatusWith<PrepareExecutionResult> prepareExecution(OperationContext* opCtx, if (descriptor && IDHackStage::supportsQuery(collection, *canonicalQuery)) { LOG(2) << "Using idhack: " << redact(canonicalQuery->toStringShort()); - root = make_unique<IDHackStage>(opCtx, collection, canonicalQuery.get(), ws, descriptor); + root = make_unique<IDHackStage>(opCtx, canonicalQuery.get(), ws, descriptor); // Might have to filter out orphaned docs. if (plannerParams.options & QueryPlannerParams::INCLUDE_SHARD_FILTER) { @@ -854,10 +854,10 @@ StatusWith<unique_ptr<PlanExecutor, PlanExecutor::Deleter>> getExecutorDelete( request->getProj().isEmpty() && hasCollectionDefaultCollation) { LOG(2) << "Using idhack: " << redact(unparsedQuery); - PlanStage* idHackStage = new IDHackStage( - opCtx, collection, unparsedQuery["_id"].wrap(), ws.get(), descriptor); + auto idHackStage = std::make_unique<IDHackStage>( + opCtx, unparsedQuery["_id"].wrap(), ws.get(), descriptor); unique_ptr<DeleteStage> root = make_unique<DeleteStage>( - opCtx, deleteStageParams, ws.get(), collection, idHackStage); + opCtx, deleteStageParams, ws.get(), collection, idHackStage.release()); return PlanExecutor::make(opCtx, std::move(ws), std::move(root), collection, policy); } diff --git a/src/mongo/db/query/internal_plans.cpp b/src/mongo/db/query/internal_plans.cpp index 6f4d976bd87..cc29c363412 100644 --- a/src/mongo/db/query/internal_plans.cpp +++ b/src/mongo/db/query/internal_plans.cpp @@ -165,7 +165,7 @@ std::unique_ptr<PlanExecutor, PlanExecutor::Deleter> InternalPlanner::updateWith invariant(collection); auto ws = stdx::make_unique<WorkingSet>(); - auto idHackStage = stdx::make_unique<IDHackStage>(opCtx, collection, key, ws.get(), descriptor); + auto idHackStage = stdx::make_unique<IDHackStage>(opCtx, key, ws.get(), descriptor); auto root = stdx::make_unique<UpdateStage>(opCtx, params, ws.get(), collection, idHackStage.release()); diff --git a/src/mongo/db/query/stage_builder.cpp b/src/mongo/db/query/stage_builder.cpp index 0ea2780935e..c0bc1958371 100644 --- a/src/mongo/db/query/stage_builder.cpp +++ b/src/mongo/db/query/stage_builder.cpp @@ -318,7 +318,7 @@ PlanStage* buildStages(OperationContext* opCtx, // We use the node's internal name, keyPattern and multikey details here. For $** // indexes, these may differ from the information recorded in the index's descriptor. - DistinctParams params{*descriptor, + DistinctParams params{descriptor, dn->index.identifier.catalogName, dn->index.keyPattern, dn->index.multikeyPaths, @@ -343,7 +343,7 @@ PlanStage* buildStages(OperationContext* opCtx, // We use the node's internal name, keyPattern and multikey details here. For $** // indexes, these may differ from the information recorded in the index's descriptor. - CountScanParams params{*descriptor, + CountScanParams params{descriptor, csn->index.identifier.catalogName, csn->index.keyPattern, csn->index.multikeyPaths, diff --git a/src/mongo/dbtests/query_stage_count_scan.cpp b/src/mongo/dbtests/query_stage_count_scan.cpp index ea5711cbccd..7edfb5cbdaa 100644 --- a/src/mongo/dbtests/query_stage_count_scan.cpp +++ b/src/mongo/dbtests/query_stage_count_scan.cpp @@ -101,7 +101,7 @@ public: CountScanParams makeCountScanParams(OperationContext* opCtx, const IndexDescriptor* descriptor) { - return {opCtx, *descriptor}; + return {opCtx, descriptor}; } static const char* ns() { @@ -330,10 +330,10 @@ public: } // Prepare the cursor to yield - count.saveState(); + static_cast<PlanStage*>(&count)->saveState(); // Recover from yield - count.restoreState(); + static_cast<PlanStage*>(&count)->restoreState(); // finish counting while (PlanStage::IS_EOF != countState) { @@ -382,13 +382,13 @@ public: } // Prepare the cursor to yield - count.saveState(); + static_cast<PlanStage*>(&count)->saveState(); // Remove remaining objects remove(BSON("a" << GTE << 5)); // Recover from yield - count.restoreState(); + static_cast<PlanStage*>(&count)->restoreState(); // finish counting while (PlanStage::IS_EOF != countState) { @@ -437,7 +437,7 @@ public: } // Prepare the cursor to yield - count.saveState(); + static_cast<PlanStage*>(&count)->saveState(); // Insert one document before the end insert(BSON("a" << 5.5)); @@ -446,7 +446,7 @@ public: insert(BSON("a" << 6.5)); // Recover from yield - count.restoreState(); + static_cast<PlanStage*>(&count)->restoreState(); // finish counting while (PlanStage::IS_EOF != countState) { @@ -560,13 +560,13 @@ public: } // Prepare the cursor to yield - count.saveState(); + static_cast<PlanStage*>(&count)->saveState(); // Mark the key at position 5 as 'unused' remove(BSON("a" << 1 << "b" << 5)); // Recover from yield - count.restoreState(); + static_cast<PlanStage*>(&count)->restoreState(); // finish counting while (PlanStage::IS_EOF != countState) { diff --git a/src/mongo/dbtests/query_stage_distinct.cpp b/src/mongo/dbtests/query_stage_distinct.cpp index b4b441a6eca..0fddca8c238 100644 --- a/src/mongo/dbtests/query_stage_distinct.cpp +++ b/src/mongo/dbtests/query_stage_distinct.cpp @@ -132,7 +132,7 @@ public: coll->getIndexCatalog()->findIndexesByKeyPattern(&_opCtx, BSON("a" << 1), false, &indexes); ASSERT_EQ(indexes.size(), 1U); - DistinctParams params{&_opCtx, *indexes[0]}; + DistinctParams params{&_opCtx, indexes[0]}; params.scanDirection = 1; // Distinct-ing over the 0-th field of the keypattern. params.fieldNo = 0; @@ -198,10 +198,9 @@ public: coll->getIndexCatalog()->findIndexesByKeyPattern(&_opCtx, BSON("a" << 1), false, &indexes); verify(indexes.size() == 1); - DistinctParams params{&_opCtx, *indexes[0]}; + DistinctParams params{&_opCtx, indexes[0]}; ASSERT_TRUE(params.isMultiKey); - verify(params.accessMethod); params.scanDirection = 1; // Distinct-ing over the 0-th field of the keypattern. params.fieldNo = 0; @@ -266,7 +265,7 @@ public: &_opCtx, BSON("a" << 1 << "b" << 1), false, &indices); ASSERT_EQ(1U, indices.size()); - DistinctParams params{&_opCtx, *indices[0]}; + DistinctParams params{&_opCtx, indices[0]}; params.scanDirection = 1; params.fieldNo = 1; |