diff options
Diffstat (limited to 'src/mongo/db/exec/count_scan.cpp')
-rw-r--r-- | src/mongo/db/exec/count_scan.cpp | 249 |
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 |