summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--src/mongo/db/exec/count_scan.cpp53
-rw-r--r--src/mongo/db/exec/count_scan.h66
-rw-r--r--src/mongo/db/exec/distinct_scan.cpp44
-rw-r--r--src/mongo/db/exec/distinct_scan.h58
-rw-r--r--src/mongo/db/exec/idhack.cpp30
-rw-r--r--src/mongo/db/exec/idhack.h24
-rw-r--r--src/mongo/db/exec/text.cpp8
-rw-r--r--src/mongo/db/exec/text.h2
-rw-r--r--src/mongo/db/exec/text_or.cpp15
-rw-r--r--src/mongo/db/exec/text_or.h16
-rw-r--r--src/mongo/db/query/get_executor.cpp8
-rw-r--r--src/mongo/db/query/internal_plans.cpp2
-rw-r--r--src/mongo/db/query/stage_builder.cpp4
-rw-r--r--src/mongo/dbtests/query_stage_count_scan.cpp18
-rw-r--r--src/mongo/dbtests/query_stage_distinct.cpp7
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;