summaryrefslogtreecommitdiff
path: root/src/mongo/db/exec/count_scan.cpp
diff options
context:
space:
mode:
Diffstat (limited to 'src/mongo/db/exec/count_scan.cpp')
-rw-r--r--src/mongo/db/exec/count_scan.cpp249
1 files changed, 124 insertions, 125 deletions
diff --git a/src/mongo/db/exec/count_scan.cpp b/src/mongo/db/exec/count_scan.cpp
index c002e72e9ca..23499102147 100644
--- a/src/mongo/db/exec/count_scan.cpp
+++ b/src/mongo/db/exec/count_scan.cpp
@@ -34,149 +34,148 @@
namespace mongo {
- using std::unique_ptr;
- using std::vector;
-
- // static
- const char* CountScan::kStageType = "COUNT_SCAN";
-
- CountScan::CountScan(OperationContext* txn,
- const CountScanParams& params,
- WorkingSet* workingSet)
- : _txn(txn),
- _workingSet(workingSet),
- _descriptor(params.descriptor),
- _iam(params.descriptor->getIndexCatalog()->getIndex(params.descriptor)),
- _shouldDedup(params.descriptor->isMultikey(txn)),
- _params(params),
- _commonStats(kStageType) {
- _specificStats.keyPattern = _params.descriptor->keyPattern();
- _specificStats.indexName = _params.descriptor->indexName();
- _specificStats.isMultiKey = _params.descriptor->isMultikey(txn);
- _specificStats.isUnique = _params.descriptor->unique();
- _specificStats.isSparse = _params.descriptor->isSparse();
- _specificStats.isPartial = _params.descriptor->isPartial();
- _specificStats.indexVersion = _params.descriptor->version();
-
- // endKey must be after startKey in index order since we only do forward scans.
- dassert(_params.startKey.woCompare(_params.endKey,
- Ordering::make(params.descriptor->keyPattern()),
- /*compareFieldNames*/false) <= 0);
- }
-
-
- PlanStage::StageState CountScan::work(WorkingSetID* out) {
- ++_commonStats.works;
- if (_commonStats.isEOF) return PlanStage::IS_EOF;
-
- // Adds the amount of time taken by work() to executionTimeMillis.
- ScopedTimer timer(&_commonStats.executionTimeMillis);
-
- boost::optional<IndexKeyEntry> entry;
- const bool needInit = !_cursor;
- try {
- // We don't care about the keys.
- const auto kWantLoc = SortedDataInterface::Cursor::kWantLoc;
-
- if (needInit) {
- // First call to work(). Perform cursor init.
- _cursor = _iam->newCursor(_txn);
- _cursor->setEndPosition(_params.endKey, _params.endKeyInclusive);
-
- entry = _cursor->seek(_params.startKey, _params.startKeyInclusive, kWantLoc);
- }
- else {
- entry = _cursor->next(kWantLoc);
- }
- }
- catch (const WriteConflictException& wce) {
- if (needInit) {
- // Release our cursor and try again next time.
- _cursor.reset();
- }
- *out = WorkingSet::INVALID_ID;
- return PlanStage::NEED_YIELD;
+using std::unique_ptr;
+using std::vector;
+
+// static
+const char* CountScan::kStageType = "COUNT_SCAN";
+
+CountScan::CountScan(OperationContext* txn, const CountScanParams& params, WorkingSet* workingSet)
+ : _txn(txn),
+ _workingSet(workingSet),
+ _descriptor(params.descriptor),
+ _iam(params.descriptor->getIndexCatalog()->getIndex(params.descriptor)),
+ _shouldDedup(params.descriptor->isMultikey(txn)),
+ _params(params),
+ _commonStats(kStageType) {
+ _specificStats.keyPattern = _params.descriptor->keyPattern();
+ _specificStats.indexName = _params.descriptor->indexName();
+ _specificStats.isMultiKey = _params.descriptor->isMultikey(txn);
+ _specificStats.isUnique = _params.descriptor->unique();
+ _specificStats.isSparse = _params.descriptor->isSparse();
+ _specificStats.isPartial = _params.descriptor->isPartial();
+ _specificStats.indexVersion = _params.descriptor->version();
+
+ // endKey must be after startKey in index order since we only do forward scans.
+ dassert(_params.startKey.woCompare(_params.endKey,
+ Ordering::make(params.descriptor->keyPattern()),
+ /*compareFieldNames*/ false) <= 0);
+}
+
+
+PlanStage::StageState CountScan::work(WorkingSetID* out) {
+ ++_commonStats.works;
+ if (_commonStats.isEOF)
+ return PlanStage::IS_EOF;
+
+ // Adds the amount of time taken by work() to executionTimeMillis.
+ ScopedTimer timer(&_commonStats.executionTimeMillis);
+
+ boost::optional<IndexKeyEntry> entry;
+ const bool needInit = !_cursor;
+ try {
+ // We don't care about the keys.
+ const auto kWantLoc = SortedDataInterface::Cursor::kWantLoc;
+
+ if (needInit) {
+ // First call to work(). Perform cursor init.
+ _cursor = _iam->newCursor(_txn);
+ _cursor->setEndPosition(_params.endKey, _params.endKeyInclusive);
+
+ entry = _cursor->seek(_params.startKey, _params.startKeyInclusive, kWantLoc);
+ } else {
+ entry = _cursor->next(kWantLoc);
}
-
- ++_specificStats.keysExamined;
-
- if (!entry) {
- _commonStats.isEOF = true;
+ } catch (const WriteConflictException& wce) {
+ if (needInit) {
+ // Release our cursor and try again next time.
_cursor.reset();
- return PlanStage::IS_EOF;
- }
-
- if (_shouldDedup && !_returned.insert(entry->loc).second) {
- // *loc was already in _returned.
- ++_commonStats.needTime;
- return PlanStage::NEED_TIME;
}
-
*out = WorkingSet::INVALID_ID;
- ++_commonStats.advanced;
- return PlanStage::ADVANCED;
+ return PlanStage::NEED_YIELD;
}
- bool CountScan::isEOF() {
- return _commonStats.isEOF;
- }
+ ++_specificStats.keysExamined;
- void CountScan::saveState() {
- _txn = NULL;
- ++_commonStats.yields;
- if (_cursor) _cursor->savePositioned();
+ if (!entry) {
+ _commonStats.isEOF = true;
+ _cursor.reset();
+ return PlanStage::IS_EOF;
}
- void CountScan::restoreState(OperationContext* opCtx) {
- invariant(_txn == NULL);
- _txn = opCtx;
- ++_commonStats.unyields;
-
- if (_cursor) _cursor->restore(opCtx);
-
- // This can change during yielding.
- // TODO this isn't sufficient. See SERVER-17678.
- _shouldDedup = _descriptor->isMultikey(_txn);
+ if (_shouldDedup && !_returned.insert(entry->loc).second) {
+ // *loc was already in _returned.
+ ++_commonStats.needTime;
+ return PlanStage::NEED_TIME;
}
- void CountScan::invalidate(OperationContext* txn, const RecordId& dl, InvalidationType type) {
- ++_commonStats.invalidates;
-
- // 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) {
- return;
- }
-
- // If we see this RecordId again, it may not be the same document it was before, so we want
- // to return it if we see it again.
- unordered_set<RecordId, RecordId::Hasher>::iterator it = _returned.find(dl);
- if (it != _returned.end()) {
- _returned.erase(it);
- }
+ *out = WorkingSet::INVALID_ID;
+ ++_commonStats.advanced;
+ return PlanStage::ADVANCED;
+}
+
+bool CountScan::isEOF() {
+ return _commonStats.isEOF;
+}
+
+void CountScan::saveState() {
+ _txn = NULL;
+ ++_commonStats.yields;
+ if (_cursor)
+ _cursor->savePositioned();
+}
+
+void CountScan::restoreState(OperationContext* opCtx) {
+ invariant(_txn == NULL);
+ _txn = opCtx;
+ ++_commonStats.unyields;
+
+ if (_cursor)
+ _cursor->restore(opCtx);
+
+ // This can change during yielding.
+ // TODO this isn't sufficient. See SERVER-17678.
+ _shouldDedup = _descriptor->isMultikey(_txn);
+}
+
+void CountScan::invalidate(OperationContext* txn, const RecordId& dl, InvalidationType type) {
+ ++_commonStats.invalidates;
+
+ // 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) {
+ return;
}
- vector<PlanStage*> CountScan::getChildren() const {
- vector<PlanStage*> empty;
- return empty;
+ // If we see this RecordId again, it may not be the same document it was before, so we want
+ // to return it if we see it again.
+ unordered_set<RecordId, RecordId::Hasher>::iterator it = _returned.find(dl);
+ if (it != _returned.end()) {
+ _returned.erase(it);
}
+}
- PlanStageStats* CountScan::getStats() {
- unique_ptr<PlanStageStats> ret(new PlanStageStats(_commonStats, STAGE_COUNT_SCAN));
+vector<PlanStage*> CountScan::getChildren() const {
+ vector<PlanStage*> empty;
+ return empty;
+}
- CountScanStats* countStats = new CountScanStats(_specificStats);
- countStats->keyPattern = _specificStats.keyPattern.getOwned();
- ret->specific.reset(countStats);
+PlanStageStats* CountScan::getStats() {
+ unique_ptr<PlanStageStats> ret(new PlanStageStats(_commonStats, STAGE_COUNT_SCAN));
- return ret.release();
- }
+ CountScanStats* countStats = new CountScanStats(_specificStats);
+ countStats->keyPattern = _specificStats.keyPattern.getOwned();
+ ret->specific.reset(countStats);
- const CommonStats* CountScan::getCommonStats() const {
- return &_commonStats;
- }
+ return ret.release();
+}
- const SpecificStats* CountScan::getSpecificStats() const {
- return &_specificStats;
- }
+const CommonStats* CountScan::getCommonStats() const {
+ return &_commonStats;
+}
+
+const SpecificStats* CountScan::getSpecificStats() const {
+ return &_specificStats;
+}
} // namespace mongo