diff options
Diffstat (limited to 'src/mongo/db/exec/sbe/stages')
-rw-r--r-- | src/mongo/db/exec/sbe/stages/column_scan.cpp | 91 | ||||
-rw-r--r-- | src/mongo/db/exec/sbe/stages/column_scan.h | 22 |
2 files changed, 58 insertions, 55 deletions
diff --git a/src/mongo/db/exec/sbe/stages/column_scan.cpp b/src/mongo/db/exec/sbe/stages/column_scan.cpp index addf5fe25e3..66da5619ceb 100644 --- a/src/mongo/db/exec/sbe/stages/column_scan.cpp +++ b/src/mongo/db/exec/sbe/stages/column_scan.cpp @@ -303,7 +303,7 @@ void ColumnScanStage::open(bool reOpen) { _specificStats.cursorStats.emplace_back(_paths[i], _includeInOutput[i])); } } - _recordId = RecordId(); + _rowId = ColumnStore::kNullRowId; _open = true; } @@ -345,7 +345,7 @@ void ColumnScanStage::readParentsIntoObj(StringData path, } boost::optional<SplitCellView> splitCellView; - if (auto optCell = it->second->seekExact(_recordId)) { + if (auto optCell = it->second->seekExact(_rowId)) { splitCellView = SplitCellView::parse(optCell->value); } @@ -468,17 +468,17 @@ bool ColumnScanStage::checkFilter(CellView cell, size_t filterIndex, const PathV return false; } -RecordId ColumnScanStage::findNextRecordIdForFilteredColumns() { +RowId ColumnScanStage::findNextRowIdForFilteredColumns() { invariant(!_filteredPaths.empty()); // Initialize 'targetRecordId' from the filtered cursor we are currently iterating. - RecordId targetRecordId; + RowId targetRowId; { auto& cursor = cursorForFilteredPath(_filteredPaths[_nextUnmatched]); if (!cursor.lastCell()) { - return RecordId(); // Have exhausted one of the columns. + return ColumnStore::kNullRowId; // Have exhausted one of the columns. } - targetRecordId = cursor.lastCell()->rid; + targetRowId = cursor.lastCell()->rid; } size_t matchedSinceAdvance = 0; @@ -491,17 +491,17 @@ RecordId ColumnScanStage::findNextRecordIdForFilteredColumns() { // Avoid seeking into the column that we started with. auto& result = cursor.lastCell(); - if (result && result->rid < targetRecordId) { - result = cursor.seekAtOrPast(targetRecordId); + if (result && result->rid < targetRowId) { + result = cursor.seekAtOrPast(targetRowId); } if (!result) { - return RecordId(); + return ColumnStore::kNullRowId; } - if (result->rid > targetRecordId) { + if (result->rid > targetRowId) { // The column skipped ahead - have to restart at this new record ID. matchedSinceAdvance = 0; - targetRecordId = result->rid; + targetRowId = result->rid; } if (!checkFilter(result->value, _nextUnmatched, cursor.path())) { @@ -509,97 +509,97 @@ RecordId ColumnScanStage::findNextRecordIdForFilteredColumns() { do { result = cursor.next(); if (!result) { - return RecordId(); + return ColumnStore::kNullRowId; } } while (!checkFilter(result->value, _nextUnmatched, cursor.path())); matchedSinceAdvance = 0; - invariant(result->rid > targetRecordId); - targetRecordId = result->rid; + invariant(result->rid > targetRowId); + targetRowId = result->rid; } ++matchedSinceAdvance; _nextUnmatched = (_nextUnmatched + 1) % _filteredPaths.size(); } - invariant(!targetRecordId.isNull()); + invariant(targetRowId != ColumnStore::kNullRowId); // Ensure that _all_ cursors have caugth up with the filtered record ID. Some of the cursors // might skip ahead, which would mean the column is missing a value for this 'recordId'. for (auto& cursor : _columnCursors) { const auto& result = cursor.lastCell(); - if (result && result->rid < targetRecordId) { - cursor.seekAtOrPast(targetRecordId); + if (result && result->rid < targetRowId) { + cursor.seekAtOrPast(targetRowId); } } - return targetRecordId; + return targetRowId; } -RecordId ColumnScanStage::findMinRecordId() const { +RowId ColumnScanStage::findMinRowId() const { if (_denseColumnCursor) { // The cursor of the dense column cannot be ahead of any other, so it's always at the // minimum. auto& result = _denseColumnCursor->lastCell(); if (!result) { - return RecordId(); + return ColumnStore::kNullRowId; } return result->rid; } - auto recordId = RecordId(); + auto recordId = ColumnStore::kNullRowId; for (const auto& cursor : _columnCursors) { const auto& result = cursor.lastCell(); - if (result && (recordId.isNull() || result->rid < recordId)) { + if (result && (recordId == ColumnStore::kNullRowId || result->rid < recordId)) { recordId = result->rid; } } return recordId; } -RecordId ColumnScanStage::advanceCursors() { - if (_recordId.isNull()) { +RowId ColumnScanStage::advanceCursors() { + if (_rowId == ColumnStore::kNullRowId) { if (_denseColumnCursor) { - _denseColumnCursor->seekAtOrPast(RecordId()); + _denseColumnCursor->seekAtOrPast(ColumnStore::kNullRowId); } for (auto& columnCursor : _columnCursors) { - columnCursor.seekAtOrPast(RecordId()); + columnCursor.seekAtOrPast(ColumnStore::kNullRowId); } - return _filteredPaths.empty() ? findMinRecordId() : findNextRecordIdForFilteredColumns(); + return _filteredPaths.empty() ? findMinRowId() : findNextRowIdForFilteredColumns(); } if (!_filteredPaths.empty()) { // Nudge forward the "active" filtered cursor. The remaining ones will be synchronized // by 'findNextRecordIdForFilteredColumns()'. cursorForFilteredPath(_filteredPaths[_nextUnmatched]).next(); - return findNextRecordIdForFilteredColumns(); + return findNextRowIdForFilteredColumns(); } // In absence of filters all cursors iterate forward on their own. Some of the cursors might - // be ahead of the current '_recordId' because there are gaps in their columns - don't move - // them but only those that are at '_recordId' and therefore their values have been - // consumed. While at it, compute the new min record ID. - auto nextRecordId = RecordId(); + // be ahead of the current '_rowId' because there are gaps in their columns - don't move them + // but only those that are at '_rowId' and therefore their values have been consumed. + // While at it, compute the new min row ID. auto nextRecordId = RecordId(); + auto nextRowId = ColumnStore::kNullRowId; if (_denseColumnCursor) { - invariant(_denseColumnCursor->lastCell()->rid == _recordId, + invariant(_denseColumnCursor->lastCell()->rid == _rowId, "Dense cursor should always be at the current minimum record ID"); auto cell = _denseColumnCursor->next(); if (!cell) { - return RecordId(); + return ColumnStore::kNullRowId; } - nextRecordId = cell->rid; + nextRowId = cell->rid; } for (auto& cursor : _columnCursors) { auto& cell = cursor.lastCell(); if (!cell) { continue; // this column has been exhausted } - if (cell->rid == _recordId) { + if (cell->rid == _rowId) { cell = cursor.next(); } - if (cell && (nextRecordId.isNull() || cell->rid < nextRecordId)) { + if (cell && (nextRowId == ColumnStore::kNullRowId || cell->rid < nextRowId)) { invariant(!_denseColumnCursor, "Dense cursor should have the next lowest record ID"); - nextRecordId = cell->rid; + nextRowId = cell->rid; } } - return nextRecordId; + return nextRowId; } PlanState ColumnScanStage::getNext() { @@ -612,8 +612,8 @@ PlanState ColumnScanStage::getNext() { checkForInterrupt(_opCtx); - _recordId = advanceCursors(); - if (_recordId.isNull()) { + _rowId = advanceCursors(); + if (_rowId == ColumnStore::kNullRowId) { return trackPlanState(PlanState::IS_EOF); } @@ -632,7 +632,7 @@ PlanState ColumnScanStage::getNext() { auto& lastCell = cursor.lastCell(); boost::optional<SplitCellView> splitCellView; - if (lastCell && lastCell->rid == _recordId) { + if (lastCell && lastCell->rid == _rowId) { splitCellView = SplitCellView::parse(lastCell->value); } @@ -658,9 +658,9 @@ PlanState ColumnScanStage::getNext() { if (useRowStore) { ++_specificStats.numRowStoreFetches; - // TODO: In some cases we can avoid calling seek() on the row store cursor, and instead - // do a next() which should be much cheaper. - auto record = _rowStoreCursor->seekExact(_recordId); + // TODO: In some cases we can avoid calling seek() on the row store cursor, and instead do + // a next() which should be much cheaper. + auto record = _rowStoreCursor->seekExact(RecordId(_rowId)); // If there's no record, the index is out of sync with the row store. invariant(record); @@ -684,6 +684,7 @@ PlanState ColumnScanStage::getNext() { } if (_recordIdAccessor) { + _recordId = RecordId(_rowId); _recordIdAccessor->reset( false, value::TypeTags::RecordId, value::bitcastFrom<RecordId*>(&_recordId)); } diff --git a/src/mongo/db/exec/sbe/stages/column_scan.h b/src/mongo/db/exec/sbe/stages/column_scan.h index 7d30152f46d..71f8489dfb3 100644 --- a/src/mongo/db/exec/sbe/stages/column_scan.h +++ b/src/mongo/db/exec/sbe/stages/column_scan.h @@ -38,6 +38,7 @@ namespace mongo { namespace sbe { + /** * A stage that scans provided columnar index. * @@ -127,17 +128,17 @@ private: return _lastCell; } - boost::optional<FullCellView>& seekAtOrPast(RecordId id) { + boost::optional<FullCellView>& seekAtOrPast(RowId rid) { _lastCell.reset(); - _lastCell = _cursor->seekAtOrPast(id); + _lastCell = _cursor->seekAtOrPast(rid); clearOwned(); ++_stats.numSeeks; return _lastCell; } - boost::optional<FullCellView>& seekExact(RecordId id) { + boost::optional<FullCellView>& seekExact(RowId rid) { _lastCell.reset(); - _lastCell = _cursor->seekExact(id); + _lastCell = _cursor->seekExact(rid); clearOwned(); ++_stats.numSeeks; return _lastCell; @@ -205,18 +206,18 @@ private: bool checkFilter(CellView cell, size_t filterIndex, const PathValue& path); - // Finds the smallest record ID such that: - // 1) it is greater or equal to the record ID of all filtered columns cursors prior to the call; + // Finds the smallest row ID such that: + // 1) it is greater or equal to the row ID of all filtered columns cursors prior to the call; // 2) the record with this ID passes the filters of all filtered columns. - // Ensures that the cursors are set to this record ID unless it's missing in the column (which + // Ensures that the cursors are set to this row ID unless it's missing in the column (which // is only possible for the non-filtered columns). - RecordId findNextRecordIdForFilteredColumns(); + RowId findNextRowIdForFilteredColumns(); // Finds the lowest record ID across all cursors. Doesn't move any of the cursors. - RecordId findMinRecordId() const; + RowId findMinRowId() const; // Move cursors to the next record to be processed. - RecordId advanceCursors(); + RowId advanceCursors(); // The columnar index this stage is scanning and the associated row store collection. const UUID _collUuid; @@ -237,6 +238,7 @@ private: // The record id in the row store that is used to connect the per-path entries in the columnar // index and to retrieve the full record from the row store, if necessary. RecordId _recordId; + RowId _rowId; const boost::optional<value::SlotId> _recordIdSlot; // The object that is equivalent to the record from the associated row store when accessing |