diff options
author | David Storch <david.storch@mongodb.com> | 2021-06-04 16:41:11 -0400 |
---|---|---|
committer | Evergreen Agent <no-reply@evergreen.mongodb.com> | 2021-06-15 20:40:09 +0000 |
commit | 71cfc41653768c29c719689a949a75a0ebbaa941 (patch) | |
tree | 12e2162f584662640055ca53456d4c771bf06c3e | |
parent | 214defdb236b3620806d7ce3b2d9eb485d68cd89 (diff) | |
download | mongo-71cfc41653768c29c719689a949a75a0ebbaa941.tar.gz |
SERVER-57096 Make SBE rely purely on the kExternal lock policy
After this patch, the AutoGet db_raii object is no longer
held by the SBE scan/ixscan stages. SBE now assumes that any
lock/snapshot acquisition is done at a higher level.
28 files changed, 156 insertions, 301 deletions
diff --git a/src/mongo/db/commands/index_filter_commands_test.cpp b/src/mongo/db/commands/index_filter_commands_test.cpp index 1293a0d0db3..785530ca6f4 100644 --- a/src/mongo/db/commands/index_filter_commands_test.cpp +++ b/src/mongo/db/commands/index_filter_commands_test.cpp @@ -139,7 +139,7 @@ void addQueryShapeToPlanCache(OperationContext* opCtx, ASSERT_OK(statusWithCQ.getStatus()); std::unique_ptr<CanonicalQuery> cq = std::move(statusWithCQ.getValue()); - QuerySolution qs{QueryPlannerParams::Options::DEFAULT}; + QuerySolution qs{}; qs.cacheData.reset(new SolutionCacheData()); qs.cacheData->tree.reset(new PlanCacheIndexTree()); std::vector<QuerySolution*> solns; diff --git a/src/mongo/db/dbhelpers.cpp b/src/mongo/db/dbhelpers.cpp index ccb5a9e7c43..0a1a5e44fd2 100644 --- a/src/mongo/db/dbhelpers.cpp +++ b/src/mongo/db/dbhelpers.cpp @@ -108,7 +108,6 @@ RecordId Helpers::findOne(OperationContext* opCtx, unique_ptr<CanonicalQuery> cq = std::move(statusWithCQ.getValue()); size_t options = requireIndex ? QueryPlannerParams::NO_TABLE_SCAN : QueryPlannerParams::DEFAULT; - options = options | QueryPlannerParams::OMIT_REPL_STATE_PERMITS_READS_CHECK; auto exec = uassertStatusOK(getExecutor( opCtx, &collection, std::move(cq), PlanYieldPolicy::YieldPolicy::NO_YIELD, options)); diff --git a/src/mongo/db/exec/sbe/parser/parser.cpp b/src/mongo/db/exec/sbe/parser/parser.cpp index adf65024aca..eae7fccded7 100644 --- a/src/mongo/db/exec/sbe/parser/parser.cpp +++ b/src/mongo/db/exec/sbe/parser/parser.cpp @@ -682,7 +682,7 @@ void Parser::walkScan(AstQuery& ast) { forward, _yieldPolicy, getCurrentPlanNodeId(), - ScanCallbacks({})); + ScanCallbacks{}); } void Parser::walkParallelScan(AstQuery& ast) { @@ -733,7 +733,7 @@ void Parser::walkParallelScan(AstQuery& ast) { lookupSlots(ast.nodes[projectsPos]->renames), _yieldPolicy, getCurrentPlanNodeId(), - ScanCallbacks({})); + ScanCallbacks{}); } void Parser::walkSeek(AstQuery& ast) { @@ -796,7 +796,7 @@ void Parser::walkSeek(AstQuery& ast) { forward, _yieldPolicy, getCurrentPlanNodeId(), - ScanCallbacks({})); + ScanCallbacks{}); } void Parser::walkIndexScan(AstQuery& ast) { @@ -856,8 +856,7 @@ void Parser::walkIndexScan(AstQuery& ast) { boost::none, boost::none, _yieldPolicy, - getCurrentPlanNodeId(), - LockAcquisitionCallback{}); + getCurrentPlanNodeId()); } void Parser::walkIndexSeek(AstQuery& ast) { @@ -917,8 +916,7 @@ void Parser::walkIndexSeek(AstQuery& ast) { lookupSlot(ast.nodes[0]->identifier), lookupSlot(ast.nodes[1]->identifier), _yieldPolicy, - getCurrentPlanNodeId(), - LockAcquisitionCallback{}); + getCurrentPlanNodeId()); } void Parser::walkProject(AstQuery& ast) { diff --git a/src/mongo/db/exec/sbe/parser/sbe_parser_test.cpp b/src/mongo/db/exec/sbe/parser/sbe_parser_test.cpp index 80ed5112dc9..29532022114 100644 --- a/src/mongo/db/exec/sbe/parser/sbe_parser_test.cpp +++ b/src/mongo/db/exec/sbe/parser/sbe_parser_test.cpp @@ -123,8 +123,7 @@ protected: boost::none, boost::none, nullptr, - planNodeId, - nullptr), + planNodeId), // IXSCAN with 'seekKeySlotLow' / 'seekKeySlotHigh' present. sbe::makeS<sbe::IndexScanStage>(fakeUuid, "_id", @@ -137,8 +136,7 @@ protected: sbe::value::SlotId{1}, sbe::value::SlotId{2}, nullptr, - planNodeId, - nullptr), + planNodeId), // IXSCAN with 'recordIdSlot' missing and 'seekKeySlotLow' present. sbe::makeS<sbe::IndexScanStage>(fakeUuid, "_id", @@ -151,8 +149,7 @@ protected: sbe::value::SlotId{2}, boost::none, nullptr, - planNodeId, - nullptr), + planNodeId), // IXSCAN with all slots except seek keys present. sbe::makeS<sbe::IndexScanStage>(fakeUuid, "_id", @@ -165,8 +162,7 @@ protected: boost::none, boost::none, nullptr, - planNodeId, - nullptr), + planNodeId), // IXSCAN with all slots present. sbe::makeS<sbe::IndexScanStage>(fakeUuid, "_id", @@ -179,8 +175,7 @@ protected: sbe::value::SlotId{4}, sbe::value::SlotId{5}, nullptr, - planNodeId, - nullptr), + planNodeId), // SCAN with 'recordSlot' and 'recordIdSlot' slots only. sbe::makeS<sbe::ScanStage>(fakeUuid, sbe::value::SlotId{1}, @@ -196,7 +191,7 @@ protected: true /* forward */, nullptr, planNodeId, - sbe::ScanCallbacks({})), + sbe::ScanCallbacks{}), // SCAN with 'recordSlot', 'recordIdSlot' and 'seekKeySlot' slots. sbe::makeS<sbe::ScanStage>(fakeUuid, sbe::value::SlotId{1}, @@ -212,7 +207,7 @@ protected: true /* forward */, nullptr, planNodeId, - sbe::ScanCallbacks({})), + sbe::ScanCallbacks{}), // SCAN with all slots present. sbe::makeS<sbe::ScanStage>( fakeUuid, @@ -229,7 +224,7 @@ protected: true /* forward */, nullptr, planNodeId, - sbe::ScanCallbacks({})), + sbe::ScanCallbacks{}), // PSCAN with both 'recordSlot' and 'recordIdSlot' slots present. sbe::makeS<sbe::ParallelScanStage>(fakeUuid, sbe::value::SlotId{1}, @@ -242,7 +237,7 @@ protected: sbe::makeSV(1, 2), nullptr, planNodeId, - sbe::ScanCallbacks({})), + sbe::ScanCallbacks{}), // PSCAN with 'recordSlot' missing. sbe::makeS<sbe::ParallelScanStage>(fakeUuid, sbe::value::SlotId{1}, @@ -255,7 +250,7 @@ protected: sbe::makeSV(1, 2), nullptr, planNodeId, - sbe::ScanCallbacks({})), + sbe::ScanCallbacks{}), // PSCAN with all slots. sbe::makeS<sbe::ParallelScanStage>(fakeUuid, sbe::value::SlotId{1}, @@ -268,7 +263,7 @@ protected: sbe::makeSV(1, 2), nullptr, planNodeId, - sbe::ScanCallbacks({})), + sbe::ScanCallbacks{}), // COSCAN sbe::makeS<sbe::CoScanStage>(planNodeId), // PROJECT diff --git a/src/mongo/db/exec/sbe/stages/collection_helpers.cpp b/src/mongo/db/exec/sbe/stages/collection_helpers.cpp index 41b6d8b4075..01139f3c5c5 100644 --- a/src/mongo/db/exec/sbe/stages/collection_helpers.cpp +++ b/src/mongo/db/exec/sbe/stages/collection_helpers.cpp @@ -35,59 +35,41 @@ namespace mongo::sbe { -std::pair<NamespaceString, uint64_t> acquireCollection( - OperationContext* opCtx, - CollectionUUID collUuid, - const LockAcquisitionCallback& lockAcquisitionCallback, - boost::optional<AutoGetCollectionForReadMaybeLockFree>& coll) { - tassert(5071012, "cannot restore 'coll' if already held", !coll.has_value()); - // The caller is expected to hold the appropriate db_raii object to give us a consistent view of - // the catalog, so the UUID must still exist. - auto collName = CollectionCatalog::get(opCtx)->lookupNSSByUUID(opCtx, collUuid); - tassert(5071000, - str::stream() << "Collection uuid " << collUuid << " does not exist", - collName.has_value()); +std::tuple<CollectionPtr, NamespaceString, uint64_t> acquireCollection(OperationContext* opCtx, + CollectionUUID collUuid) { + // The collection is either locked at a higher level or a snapshot of the catalog (consistent + // with the storage engine snapshot from which we are reading) has been stashed on the + // 'OperationContext'. Either way, this means that the UUID must still exist in our view of the + // collection catalog. + CollectionPtr collPtr = CollectionCatalog::get(opCtx)->lookupCollectionByUUID(opCtx, collUuid); + tassert(5071000, str::stream() << "Collection uuid " << collUuid << " does not exist", collPtr); - coll.emplace(opCtx, NamespaceStringOrUUID{collName->db().toString(), collUuid}); - if (lockAcquisitionCallback) { - lockAcquisitionCallback(opCtx, *coll); - } - - tassert(4938501, - str::stream() << "expected CollectionPtr for: " << *collName, - static_cast<bool>(coll->getCollection())); - - return {*collName, CollectionCatalog::get(opCtx)->getEpoch()}; + return std::make_tuple( + std::move(collPtr), collPtr->ns(), CollectionCatalog::get(opCtx)->getEpoch()); } -void restoreCollection(OperationContext* opCtx, - const NamespaceString& collName, - CollectionUUID collUuid, - uint64_t catalogEpoch, - const LockAcquisitionCallback& lockAcquisitionCallback, - boost::optional<AutoGetCollectionForReadMaybeLockFree>& coll) { - tassert(5071011, "cannot restore 'coll' if already held", !coll.has_value()); - // Reaquire the AutoGet object, looking up in the catalog by UUID. If the collection has been - // dropped, then this UUID lookup will fail, throwing an exception and terminating the query. - NamespaceStringOrUUID nssOrUuid{collName.db().toString(), collUuid}; - try { - coll.emplace(opCtx, nssOrUuid); - } catch (ExceptionFor<ErrorCodes::NamespaceNotFound>& ex) { - ex.addContext(str::stream() << "collection dropped: '" << collName << "'"); - throw; +CollectionPtr restoreCollection(OperationContext* opCtx, + const NamespaceString& collName, + CollectionUUID collUuid, + uint64_t catalogEpoch) { + // Re-lookup the collection pointer, by UUID. If the collection has been dropped, then this UUID + // lookup will result in a null pointer. If the collection has been renamed, then the resulting + // collection object should have a different name from the original 'collName'. In either + // scenario, we throw a 'QueryPlanKilled' error and terminate the query. + CollectionPtr collPtr = CollectionCatalog::get(opCtx)->lookupCollectionByUUID(opCtx, collUuid); + if (!collPtr) { + PlanYieldPolicy::throwCollectionDroppedError(collUuid); } - if (collName != coll->getNss()) { - PlanYieldPolicy::throwCollectionRenamedError(collName, coll->getNss(), collUuid); + if (collName != collPtr->ns()) { + PlanYieldPolicy::throwCollectionRenamedError(collName, collPtr->ns(), collUuid); } uassert(ErrorCodes::QueryPlanKilled, "the catalog was closed and reopened", CollectionCatalog::get(opCtx)->getEpoch() == catalogEpoch); - if (lockAcquisitionCallback) { - lockAcquisitionCallback(opCtx, *coll); - } + return collPtr; } } // namespace mongo::sbe diff --git a/src/mongo/db/exec/sbe/stages/collection_helpers.h b/src/mongo/db/exec/sbe/stages/collection_helpers.h index 65ea730c9b5..ed446c8aaee 100644 --- a/src/mongo/db/exec/sbe/stages/collection_helpers.h +++ b/src/mongo/db/exec/sbe/stages/collection_helpers.h @@ -37,14 +37,6 @@ namespace mongo::sbe { /** - * A callback which gets called whenever a stage which accesses the storage engine (e.g. "scan", - * "seek", or "ixscan") obtains or re-obtains its AutoGet*. - */ -using LockAcquisitionCallback = - std::function<void(OperationContext*, const AutoGetCollectionForReadMaybeLockFree&)>; - - -/** * A callback which gets called whenever a SCAN stage asks an underlying index scan for a result. */ using IndexKeyConsistencyCheckCallback = std::function<bool(OperationContext* opCtx, @@ -63,29 +55,25 @@ using IndexKeyCorruptionCheckCallback = const NamespaceString& nss)>; /** - * Given a collection UUID, acquires 'coll', invokes the provided 'lockAcquisiionCallback', and - * returns the collection's name as well as the current catalog epoch. + * Given a collection UUID, looks up the UUID in the catalog and returns a pointer to the + * collection, the collection's name, and the current catalog epoch. * * This is intended for use during the preparation of an SBE plan. The caller must hold the * appropriate db_raii object in order to ensure that SBE plan preparation sees a consistent view of * the catalog. */ -std::pair<NamespaceString, uint64_t> acquireCollection( - OperationContext* opCtx, - CollectionUUID collUuid, - const LockAcquisitionCallback& lockAcquisitionCallback, - boost::optional<AutoGetCollectionForReadMaybeLockFree>& coll); +std::tuple<CollectionPtr, NamespaceString, uint64_t> acquireCollection(OperationContext* opCtx, + CollectionUUID collUuid); /** - * Re-acquires 'coll', intended for use during SBE yield recovery or when a closed SBE plan is - * re-opened. In addition to acquiring 'coll', throws a UserException if the collection has been - * dropped or renamed, or if the catalog has been closed and re-opened. SBE query execution - * currently cannot survive such events if they occur during a yield or between getMores. + * Re-acquires a pointer to the collection, intended for use during SBE yield recovery or when a + * closed SBE plan is re-opened. In addition to acquiring the collection pointer, throws a + * UserException if the collection has been dropped or renamed, or if the catalog has been closed + * and re-opened. SBE query execution currently cannot survive such events if they occur during a + * yield or between getMores. */ -void restoreCollection(OperationContext* opCtx, - const NamespaceString& collName, - CollectionUUID collUuid, - uint64_t catalogEpoch, - const LockAcquisitionCallback& lockAcquisitionCallback, - boost::optional<AutoGetCollectionForReadMaybeLockFree>& coll); +CollectionPtr restoreCollection(OperationContext* opCtx, + const NamespaceString& collName, + CollectionUUID collUuid, + uint64_t catalogEpoch); } // namespace mongo::sbe diff --git a/src/mongo/db/exec/sbe/stages/ix_scan.cpp b/src/mongo/db/exec/sbe/stages/ix_scan.cpp index a5e679b65ce..63cea42e018 100644 --- a/src/mongo/db/exec/sbe/stages/ix_scan.cpp +++ b/src/mongo/db/exec/sbe/stages/ix_scan.cpp @@ -49,8 +49,7 @@ IndexScanStage::IndexScanStage(CollectionUUID collUuid, boost::optional<value::SlotId> seekKeySlotLow, boost::optional<value::SlotId> seekKeySlotHigh, PlanYieldPolicy* yieldPolicy, - PlanNodeId nodeId, - LockAcquisitionCallback lockAcquisitionCallback) + PlanNodeId nodeId) : PlanStage(seekKeySlotLow ? "ixseek"_sd : "ixscan"_sd, yieldPolicy, nodeId), _collUuid(collUuid), _indexName(indexName), @@ -61,8 +60,7 @@ IndexScanStage::IndexScanStage(CollectionUUID collUuid, _indexKeysToInclude(indexKeysToInclude), _vars(std::move(vars)), _seekKeySlotLow(seekKeySlotLow), - _seekKeySlotHigh(seekKeySlotHigh), - _lockAcquisitionCallback(std::move(lockAcquisitionCallback)) { + _seekKeySlotHigh(seekKeySlotHigh) { // The valid state is when both boundaries, or none is set, or only low key is set. invariant((_seekKeySlotLow && _seekKeySlotHigh) || (!_seekKeySlotLow && !_seekKeySlotHigh) || (_seekKeySlotLow && !_seekKeySlotHigh)); @@ -82,8 +80,7 @@ std::unique_ptr<PlanStage> IndexScanStage::clone() const { _seekKeySlotLow, _seekKeySlotHigh, _yieldPolicy, - _commonStats.nodeId, - _lockAcquisitionCallback); + _commonStats.nodeId); } void IndexScanStage::prepare(CompileCtx& ctx) { @@ -114,10 +111,10 @@ void IndexScanStage::prepare(CompileCtx& ctx) { } _seekKeyLowHolder = std::make_unique<value::OwnedValueAccessor>(); - std::tie(_collName, _catalogEpoch) = - acquireCollection(_opCtx, _collUuid, _lockAcquisitionCallback, _coll); + tassert(5709602, "'_coll' should not be initialized prior to 'acquireCollection()'", !_coll); + std::tie(_coll, _collName, _catalogEpoch) = acquireCollection(_opCtx, _collUuid); - auto indexCatalog = _coll->getCollection()->getIndexCatalog(); + auto indexCatalog = _coll->getIndexCatalog(); auto indexDesc = indexCatalog->findIndexByName(_opCtx, _indexName); tassert(4938500, str::stream() << "could not find index named '" << _indexName << "' in collection '" @@ -189,7 +186,7 @@ void IndexScanStage::doSaveState() { } void IndexScanStage::restoreCollectionAndIndex() { - restoreCollection(_opCtx, _collName, _collUuid, _catalogEpoch, _lockAcquisitionCallback, _coll); + _coll = restoreCollection(_opCtx, _collName, _collUuid, _catalogEpoch); auto indexCatalogEntry = _weakIndexCatalogEntry.lock(); uassert(ErrorCodes::QueryPlanKilled, str::stream() << "query plan killed :: index '" << _indexName << "' dropped", @@ -248,7 +245,7 @@ void IndexScanStage::open(bool reOpen) { if (_open) { tassert(5071006, "reopened IndexScanStage but reOpen=false", reOpen); - tassert(5071007, "IndexScanStage is open but _coll is not held", _coll); + tassert(5071007, "IndexScanStage is open but _coll is null", _coll); tassert(5071008, "IndexScanStage is open but don't have _cursor", _cursor); } else { tassert(5071009, "first open to IndexScanStage but reOpen=true", !reOpen); diff --git a/src/mongo/db/exec/sbe/stages/ix_scan.h b/src/mongo/db/exec/sbe/stages/ix_scan.h index 00e3dd16bfb..4d52c7d7881 100644 --- a/src/mongo/db/exec/sbe/stages/ix_scan.h +++ b/src/mongo/db/exec/sbe/stages/ix_scan.h @@ -71,8 +71,7 @@ public: boost::optional<value::SlotId> seekKeySlotLow, boost::optional<value::SlotId> seekKeySlotHigh, PlanYieldPolicy* yieldPolicy, - PlanNodeId nodeId, - LockAcquisitionCallback lockAcquisitionCallback); + PlanNodeId nodeId); std::unique_ptr<PlanStage> clone() const final; @@ -119,7 +118,7 @@ private: NamespaceString _collName; uint64_t _catalogEpoch; - LockAcquisitionCallback _lockAcquisitionCallback; + CollectionPtr _coll; std::unique_ptr<value::OwnedValueAccessor> _recordAccessor; std::unique_ptr<value::OwnedValueAccessor> _recordIdAccessor; @@ -139,7 +138,6 @@ private: std::unique_ptr<SortedDataInterface::Cursor> _cursor; std::weak_ptr<const IndexCatalogEntry> _weakIndexCatalogEntry; boost::optional<Ordering> _ordering{boost::none}; - boost::optional<AutoGetCollectionForReadMaybeLockFree> _coll; boost::optional<KeyStringEntry> _nextRecord; // This buffer stores values that are projected out of the index entry. Values in the diff --git a/src/mongo/db/exec/sbe/stages/scan.cpp b/src/mongo/db/exec/sbe/stages/scan.cpp index 61f6010a458..f5e282e7b5e 100644 --- a/src/mongo/db/exec/sbe/stages/scan.cpp +++ b/src/mongo/db/exec/sbe/stages/scan.cpp @@ -136,8 +136,8 @@ void ScanStage::prepare(CompileCtx& ctx) { _oplogTsAccessor = ctx.getRuntimeEnvAccessor(*_oplogTsSlot); } - std::tie(_collName, _catalogEpoch) = - acquireCollection(_opCtx, _collUuid, _scanCallbacks.lockAcquisitionCallback, _coll); + tassert(5709600, "'_coll' should not be initialized prior to 'acquireCollection()'", !_coll); + std::tie(_coll, _collName, _catalogEpoch) = acquireCollection(_opCtx, _collUuid); } value::SlotAccessor* ScanStage::getAccessor(CompileCtx& ctx, value::SlotId slot) { @@ -189,8 +189,7 @@ void ScanStage::doRestoreState() { return; } - restoreCollection( - _opCtx, _collName, _collUuid, _catalogEpoch, _scanCallbacks.lockAcquisitionCallback, _coll); + _coll = restoreCollection(_opCtx, _collName, _collUuid, _catalogEpoch); if (_cursor) { const bool couldRestore = _cursor->restore(); @@ -229,7 +228,7 @@ void ScanStage::open(bool reOpen) { if (_open) { tassert(5071001, "reopened ScanStage but reOpen=false", reOpen); - tassert(5071002, "ScanStage is open but _coll is not held", _coll); + tassert(5071002, "ScanStage is open but _coll is not null", _coll); tassert(5071003, "ScanStage is open but don't have _cursor", _cursor); } else { tassert(5071004, "first open to ScanStage but reOpen=true", !reOpen); @@ -237,20 +236,15 @@ void ScanStage::open(bool reOpen) { // We're being opened after 'close()'. We need to re-acquire '_coll' in this case and // make some validity checks (the collection has not been dropped, renamed, etc.). tassert(5071005, "ScanStage is not open but have _cursor", !_cursor); - restoreCollection(_opCtx, - _collName, - _collUuid, - _catalogEpoch, - _scanCallbacks.lockAcquisitionCallback, - _coll); + _coll = restoreCollection(_opCtx, _collName, _collUuid, _catalogEpoch); } } if (_scanCallbacks.scanOpenCallback) { - _scanCallbacks.scanOpenCallback(_opCtx, _coll->getCollection(), reOpen); + _scanCallbacks.scanOpenCallback(_opCtx, _coll, reOpen); } - if (const auto& collection = _coll->getCollection()) { + if (_coll) { if (_seekKeyAccessor) { auto [tag, val] = _seekKeyAccessor->getViewOfValue(); const auto msgTag = tag; @@ -262,7 +256,7 @@ void ScanStage::open(bool reOpen) { } if (!_cursor || !_seekKeyAccessor) { - _cursor = collection->getCursor(_opCtx, _forward); + _cursor = _coll->getCursor(_opCtx, _forward); } } else { _cursor.reset(); @@ -309,12 +303,8 @@ PlanState ScanStage::getNext() { // Return EOF if the index key is found to be inconsistent. if (_scanCallbacks.indexKeyConsistencyCheckCallBack && - !_scanCallbacks.indexKeyConsistencyCheckCallBack(_opCtx, - _snapshotIdAccessor, - _indexIdAccessor, - _indexKeyAccessor, - _coll->getCollection(), - *nextRecord)) { + !_scanCallbacks.indexKeyConsistencyCheckCallBack( + _opCtx, _snapshotIdAccessor, _indexIdAccessor, _indexKeyAccessor, _coll, *nextRecord)) { return trackPlanState(PlanState::IS_EOF); } @@ -594,7 +584,8 @@ void ParallelScanStage::prepare(CompileCtx& ctx) { _indexKeyPatternAccessor = ctx.getAccessor(*_indexKeyPatternSlot); } - std::tie(_collName, _catalogEpoch) = acquireCollection(_opCtx, _collUuid, nullptr, _coll); + tassert(5709601, "'_coll' should not be initialized prior to 'acquireCollection()'", !_coll); + std::tie(_coll, _collName, _catalogEpoch) = acquireCollection(_opCtx, _collUuid); } value::SlotAccessor* ParallelScanStage::getAccessor(CompileCtx& ctx, value::SlotId slot) { @@ -642,7 +633,7 @@ void ParallelScanStage::doRestoreState() { return; } - restoreCollection(_opCtx, _collName, _collUuid, _catalogEpoch, nullptr, _coll); + _coll = restoreCollection(_opCtx, _collName, _collUuid, _catalogEpoch); if (_cursor) { const bool couldRestore = _cursor->restore(); @@ -675,23 +666,21 @@ void ParallelScanStage::open(bool reOpen) { // we're being opened after 'close()'. we need to re-acquire '_coll' in this case and // make some validity checks (the collection has not been dropped, renamed, etc.). tassert(5071013, "ParallelScanStage is not open but have _cursor", !_cursor); - restoreCollection(_opCtx, _collName, _collUuid, _catalogEpoch, nullptr, _coll); + _coll = restoreCollection(_opCtx, _collName, _collUuid, _catalogEpoch); } - const auto& collection = _coll->getCollection(); - - if (collection) { + if (_coll) { { stdx::unique_lock lock(_state->mutex); if (_state->ranges.empty()) { - auto ranges = collection->getRecordStore()->numRecords(_opCtx) / 10240; + auto ranges = _coll->getRecordStore()->numRecords(_opCtx) / 10240; if (ranges < 2) { _state->ranges.emplace_back(Range{RecordId{}, RecordId{}}); } else { if (ranges > 1024) { ranges = 1024; } - auto randomCursor = collection->getRecordStore()->getRandomCursor(_opCtx); + auto randomCursor = _coll->getRecordStore()->getRandomCursor(_opCtx); invariant(randomCursor); std::set<RecordId> rids; while (ranges--) { @@ -710,7 +699,7 @@ void ParallelScanStage::open(bool reOpen) { } } - _cursor = collection->getCursor(_opCtx); + _cursor = _coll->getCursor(_opCtx); } _open = true; @@ -775,7 +764,7 @@ PlanState ParallelScanStage::getNext() { _snapshotIdAccessor, _indexIdAccessor, _indexKeyAccessor, - _coll->getCollection(), + _coll, *nextRecord)) { return trackPlanState(PlanState::IS_EOF); } diff --git a/src/mongo/db/exec/sbe/stages/scan.h b/src/mongo/db/exec/sbe/stages/scan.h index dca4da1c496..3180c337af8 100644 --- a/src/mongo/db/exec/sbe/stages/scan.h +++ b/src/mongo/db/exec/sbe/stages/scan.h @@ -40,16 +40,13 @@ namespace sbe { using ScanOpenCallback = std::function<void(OperationContext*, const CollectionPtr&, bool)>; struct ScanCallbacks { - ScanCallbacks(LockAcquisitionCallback lockAcquisition, - IndexKeyCorruptionCheckCallback indexKeyCorruptionCheck = {}, + ScanCallbacks(IndexKeyCorruptionCheckCallback indexKeyCorruptionCheck = {}, IndexKeyConsistencyCheckCallback indexKeyConsistencyCheck = {}, ScanOpenCallback scanOpen = {}) - : lockAcquisitionCallback(std::move(lockAcquisition)), - indexKeyCorruptionCheckCallback(std::move(indexKeyCorruptionCheck)), + : indexKeyCorruptionCheckCallback(std::move(indexKeyCorruptionCheck)), indexKeyConsistencyCheckCallBack(std::move(indexKeyConsistencyCheck)), scanOpenCallback(std::move(scanOpen)) {} - LockAcquisitionCallback lockAcquisitionCallback; IndexKeyCorruptionCheckCallback indexKeyCorruptionCheckCallback; IndexKeyConsistencyCheckCallback indexKeyConsistencyCheckCallBack; ScanOpenCallback scanOpenCallback; @@ -112,6 +109,8 @@ private: NamespaceString _collName; uint64_t _catalogEpoch; + CollectionPtr _coll; + // If provided, used during a trial run to accumulate certain execution stats. Once the trial // run is complete, this pointer is reset to nullptr. TrialRunTracker* _tracker{nullptr}; @@ -133,7 +132,6 @@ private: bool _open{false}; std::unique_ptr<SeekableRecordCursor> _cursor; - boost::optional<AutoGetCollectionForReadMaybeLockFree> _coll; RecordId _key; bool _firstGetNext{false}; @@ -219,6 +217,8 @@ private: NamespaceString _collName; uint64_t _catalogEpoch; + CollectionPtr _coll; + std::shared_ptr<ParallelState> _state; const ScanCallbacks _scanCallbacks; @@ -239,7 +239,6 @@ private: bool _open{false}; std::unique_ptr<SeekableRecordCursor> _cursor; - boost::optional<AutoGetCollectionForReadMaybeLockFree> _coll; }; } // namespace sbe } // namespace mongo diff --git a/src/mongo/db/query/classic_stage_builder_test.cpp b/src/mongo/db/query/classic_stage_builder_test.cpp index 4e8f87140b7..407cd67e426 100644 --- a/src/mongo/db/query/classic_stage_builder_test.cpp +++ b/src/mongo/db/query/classic_stage_builder_test.cpp @@ -59,7 +59,7 @@ public: * Converts a 'QuerySolutionNode' to a 'QuerySolution'. */ std::unique_ptr<QuerySolution> makeQuerySolution(std::unique_ptr<QuerySolutionNode> root) { - auto querySoln = std::make_unique<QuerySolution>(QueryPlannerParams::Options::DEFAULT); + auto querySoln = std::make_unique<QuerySolution>(); querySoln->setRoot(std::move(root)); return querySoln; } diff --git a/src/mongo/db/query/get_executor.cpp b/src/mongo/db/query/get_executor.cpp index 0e22091419b..383a872e180 100644 --- a/src/mongo/db/query/get_executor.cpp +++ b/src/mongo/db/query/get_executor.cpp @@ -568,7 +568,7 @@ public: "namespace"_attr = _cq->ns(), "canonicalQuery"_attr = redact(_cq->toStringShort())); - auto solution = std::make_unique<QuerySolution>(_plannerOptions); + auto solution = std::make_unique<QuerySolution>(); solution->setRoot(std::make_unique<EofNode>()); auto root = buildExecutableTree(*solution); @@ -975,7 +975,7 @@ protected: } } - auto soln = std::make_unique<QuerySolution>(plannerParams->options); + auto soln = std::make_unique<QuerySolution>(); soln->setRoot(std::move(root)); auto execTree = buildExecutableTree(*soln); diff --git a/src/mongo/db/query/plan_cache_test.cpp b/src/mongo/db/query/plan_cache_test.cpp index 230e8e162aa..07f98a84967 100644 --- a/src/mongo/db/query/plan_cache_test.cpp +++ b/src/mongo/db/query/plan_cache_test.cpp @@ -316,7 +316,7 @@ std::pair<CoreIndexInfo, std::unique_ptr<WildcardProjection>> makeWildcardUpdate */ struct GenerateQuerySolution { QuerySolution* operator()() const { - unique_ptr<QuerySolution> qs(new QuerySolution(QueryPlannerParams::Options::DEFAULT)); + auto qs = std::make_unique<QuerySolution>(); qs->cacheData.reset(new SolutionCacheData()); qs->cacheData->solnType = SolutionCacheData::COLLSCAN_SOLN; qs->cacheData->tree.reset(new PlanCacheIndexTree()); @@ -379,8 +379,7 @@ void assertShouldNotCacheQuery(const char* queryStr) { } std::unique_ptr<QuerySolution> getQuerySolutionForCaching() { - std::unique_ptr<QuerySolution> qs = - std::make_unique<QuerySolution>(QueryPlannerParams::Options::DEFAULT); + std::unique_ptr<QuerySolution> qs = std::make_unique<QuerySolution>(); qs->cacheData = std::make_unique<SolutionCacheData>(); qs->cacheData->tree = std::make_unique<PlanCacheIndexTree>(); return qs; @@ -1176,7 +1175,7 @@ protected: // Create a CachedSolution the long way.. // QuerySolution -> PlanCacheEntry -> CachedSolution - QuerySolution qs{QueryPlannerParams::Options::DEFAULT}; + QuerySolution qs{}; qs.cacheData = soln.cacheData->clone(); std::vector<QuerySolution*> solutions; solutions.push_back(&qs); diff --git a/src/mongo/db/query/planner_analysis.cpp b/src/mongo/db/query/planner_analysis.cpp index 71892e12b51..dc943fd771c 100644 --- a/src/mongo/db/query/planner_analysis.cpp +++ b/src/mongo/db/query/planner_analysis.cpp @@ -913,7 +913,7 @@ std::unique_ptr<QuerySolution> QueryPlannerAnalysis::analyzeDataAccess( const CanonicalQuery& query, const QueryPlannerParams& params, std::unique_ptr<QuerySolutionNode> solnRoot) { - auto soln = std::make_unique<QuerySolution>(params.options); + auto soln = std::make_unique<QuerySolution>(); soln->indexFilterApplied = params.indexFiltersApplied; solnRoot->computeProperties(); diff --git a/src/mongo/db/query/query_planner.cpp b/src/mongo/db/query/query_planner.cpp index ab803e03254..0d13c318193 100644 --- a/src/mongo/db/query/query_planner.cpp +++ b/src/mongo/db/query/query_planner.cpp @@ -179,9 +179,6 @@ string optionString(size_t options) { case QueryPlannerParams::ENUMERATE_OR_CHILDREN_LOCKSTEP: ss << "ENUMERATE_OR_CHILDREN_LOCKSTEP "; break; - case QueryPlannerParams::OMIT_REPL_STATE_PERMITS_READS_CHECK: - ss << "OMIT_REPL_STATE_PERMITS_READS_CHECK"; - break; case QueryPlannerParams::RETURN_OWNED_DATA: ss << "RETURN_OWNED_DATA "; break; diff --git a/src/mongo/db/query/query_planner_params.h b/src/mongo/db/query/query_planner_params.h index 5278c94f8e9..deb452eacf6 100644 --- a/src/mongo/db/query/query_planner_params.h +++ b/src/mongo/db/query/query_planner_params.h @@ -120,16 +120,9 @@ struct QueryPlannerParams { // $or use the same fields and have the same indexes available, as in this example. ENUMERATE_OR_CHILDREN_LOCKSTEP = 1 << 12, - // Instructs the planner to produce a plan which will *not* check at runtime that the node's - // replica set member state allows reads. Typically, replica set members will only serve - // reads to clients if thet are in parimary or secondary state. Client reads are disallowed - // in other states, e.g. during initial sync. Internal operations, on the other hand, can - // use this flag to exempt themselves from this repl set note state requirement. - OMIT_REPL_STATE_PERMITS_READS_CHECK = 1 << 13, - // Ensure that any plan generated returns data that is "owned." That is, all BSONObjs are // in an "owned" state and are not pointing to data that belongs to the storage engine. - RETURN_OWNED_DATA = 1 << 14, + RETURN_OWNED_DATA = 1 << 13, }; // See Options enum above. diff --git a/src/mongo/db/query/query_solution.h b/src/mongo/db/query/query_solution.h index e950d34db67..9d0c8f5f9bf 100644 --- a/src/mongo/db/query/query_solution.h +++ b/src/mongo/db/query/query_solution.h @@ -326,7 +326,7 @@ struct QuerySolutionNodeWithSortSet : public QuerySolutionNode { */ class QuerySolution { public: - explicit QuerySolution(size_t plannerOptions) : plannerOptions(plannerOptions) {} + QuerySolution() = default; /** * Return true if this solution tree contains a node of the given 'type'. @@ -362,18 +362,6 @@ public: */ void setRoot(std::unique_ptr<QuerySolutionNode> root); - /** - * Returns true if the execution plan which is constructed from this QuerySolution should check - * that the node is eligible to serve reads prior to actually performing any reads. - */ - bool shouldCheckCanServeReads() const { - return !(plannerOptions & QueryPlannerParams::OMIT_REPL_STATE_PERMITS_READS_CHECK); - } - - // A bit vector of flags which clients to the QueryPlanner pass to control which plans are - // generated and their properties. - const size_t plannerOptions; - // There are two known scenarios in which a query solution might potentially block: // // Sort stage: diff --git a/src/mongo/db/query/query_solution_test.cpp b/src/mongo/db/query/query_solution_test.cpp index 71470e22c50..8763b208fcd 100644 --- a/src/mongo/db/query/query_solution_test.cpp +++ b/src/mongo/db/query/query_solution_test.cpp @@ -1061,7 +1061,7 @@ TEST(QuerySolutionTest, NodeIdsAssignedInPostOrderFashionStartingFromOne) { ASSERT_EQ(orNode->children[0]->nodeId(), 0u); ASSERT_EQ(orNode->children[1]->nodeId(), 0u); - auto querySolution = std::make_unique<QuerySolution>(QueryPlannerParams::Options::DEFAULT); + auto querySolution = std::make_unique<QuerySolution>(); querySolution->setRoot(std::move(orNode)); auto root = querySolution->root(); diff --git a/src/mongo/db/query/sbe_stage_builder.cpp b/src/mongo/db/query/sbe_stage_builder.cpp index b97d1c3a340..f2f53662346 100644 --- a/src/mongo/db/query/sbe_stage_builder.cpp +++ b/src/mongo/db/query/sbe_stage_builder.cpp @@ -457,17 +457,6 @@ const QuerySolutionNode* getLoneNodeByType(const QuerySolutionNode* root, StageT return result; } -sbe::LockAcquisitionCallback makeLockAcquisitionCallback(bool checkNodeCanServeReads) { - if (!checkNodeCanServeReads) { - return {}; - } - - return [](OperationContext* opCtx, const AutoGetCollectionForReadMaybeLockFree& coll) { - uassertStatusOK(repl::ReplicationCoordinator::get(opCtx)->checkCanServeReadsFor( - opCtx, coll.getNss(), true)); - }; -} - /** * Callback function that logs a message and uasserts if it detects a corrupt index key. An index * key is considered corrupt if it has no corresponding Record. @@ -649,7 +638,6 @@ SlotBasedStageBuilder::SlotBasedStageBuilder(OperationContext* opCtx, _yieldPolicy(yieldPolicy), _data(makeRuntimeEnvironment(_cq, _opCtx, &_slotIdGenerator)), _shardFiltererFactory(shardFiltererFactory), - _lockAcquisitionCallback(makeLockAcquisitionCallback(solution.shouldCheckCanServeReads())), _state(_opCtx, _data.env, _cq.getExpCtxRaw()->variables, @@ -708,12 +696,8 @@ std::pair<std::unique_ptr<sbe::PlanStage>, PlanStageSlots> SlotBasedStageBuilder auto csn = static_cast<const CollectionScanNode*>(root); - auto [stage, outputs] = generateCollScan(_state, - _collection, - csn, - _yieldPolicy, - reqs.getIsTailableCollScanResumeBranch(), - _lockAcquisitionCallback); + auto [stage, outputs] = generateCollScan( + _state, _collection, csn, _yieldPolicy, reqs.getIsTailableCollScanResumeBranch()); if (reqs.has(kReturnKey)) { // Assign the 'returnKeySlot' to be the empty object. @@ -825,14 +809,8 @@ std::pair<std::unique_ptr<sbe::PlanStage>, PlanStageSlots> SlotBasedStageBuilder iamMap = nullptr; } - auto [stage, outputs] = generateIndexScan(_state, - _collection, - ixn, - indexKeyBitset, - _yieldPolicy, - _lockAcquisitionCallback, - iamMap, - reqs.has(kIndexKeyPattern)); + auto [stage, outputs] = generateIndexScan( + _state, _collection, ixn, indexKeyBitset, _yieldPolicy, iamMap, reqs.has(kIndexKeyPattern)); if (reqs.has(PlanStageSlots::kReturnKey)) { std::vector<std::unique_ptr<sbe::EExpression>> mkObjArgs; @@ -888,7 +866,6 @@ SlotBasedStageBuilder::makeLoopJoinForFetch(std::unique_ptr<sbe::PlanStage> inpu using namespace std::placeholders; sbe::ScanCallbacks callbacks( - _lockAcquisitionCallback, indexKeyCorruptionCheckCallback, std::bind(indexKeyConsistencyCheckCallback, _1, std::move(iamMap), _2, _3, _4, _5, _6)); // Scan the collection in the range [seekKeySlot, Inf). diff --git a/src/mongo/db/query/sbe_stage_builder.h b/src/mongo/db/query/sbe_stage_builder.h index 49534b02f9f..81335f937e0 100644 --- a/src/mongo/db/query/sbe_stage_builder.h +++ b/src/mongo/db/query/sbe_stage_builder.h @@ -381,10 +381,6 @@ private: // A factory to construct shard filters. ShardFiltererFactoryInterface* _shardFiltererFactory; - // A callback that should be installed on "scan" and "ixscan" nodes. It will get invoked when - // these data access stages acquire their AutoGet*. - const sbe::LockAcquisitionCallback _lockAcquisitionCallback; - // Common parameters to SBE stage builder functions. StageBuilderState _state; }; diff --git a/src/mongo/db/query/sbe_stage_builder_coll_scan.cpp b/src/mongo/db/query/sbe_stage_builder_coll_scan.cpp index bd045c33801..740f5e71c36 100644 --- a/src/mongo/db/query/sbe_stage_builder_coll_scan.cpp +++ b/src/mongo/db/query/sbe_stage_builder_coll_scan.cpp @@ -141,8 +141,7 @@ std::unique_ptr<sbe::PlanStage> buildResumeFromRecordIdSubtree( std::unique_ptr<sbe::EExpression> seekRecordIdExpression, PlanYieldPolicy* yieldPolicy, bool isTailableResumeBranch, - bool resumeAfterRecordId, - sbe::LockAcquisitionCallback lockAcquisitionCallback) { + bool resumeAfterRecordId) { invariant(seekRecordIdExpression); const auto forward = csn->direction == CollectionScanParams::FORWARD; @@ -174,7 +173,7 @@ std::unique_ptr<sbe::PlanStage> buildResumeFromRecordIdSubtree( forward, yieldPolicy, csn->nodeId(), - lockAcquisitionCallback), + sbe::ScanCallbacks{}), sbe::makeSV(seekSlot), sbe::makeSV(seekSlot), nullptr, @@ -247,8 +246,7 @@ std::pair<std::unique_ptr<sbe::PlanStage>, PlanStageSlots> generateOptimizedOplo const CollectionPtr& collection, const CollectionScanNode* csn, PlanYieldPolicy* yieldPolicy, - bool isTailableResumeBranch, - sbe::LockAcquisitionCallback lockAcquisitionCallback) { + bool isTailableResumeBranch) { invariant(collection->ns().isOplog()); // We can apply oplog scan optimizations only when at least one of the following was specified. invariant(csn->resumeAfterRecordId || csn->minRecord || csn->maxRecord); @@ -293,8 +291,7 @@ std::pair<std::unique_ptr<sbe::PlanStage>, PlanStageSlots> generateOptimizedOplo auto&& [fields, slots, tsSlot] = makeOplogTimestampSlotsIfNeeded( state.env, state.slotIdGenerator, shouldTrackLatestOplogTimestamp); - sbe::ScanCallbacks callbacks( - lockAcquisitionCallback, {}, {}, makeOpenCallbackIfNeeded(collection, csn)); + sbe::ScanCallbacks callbacks({}, {}, makeOpenCallbackIfNeeded(collection, csn)); auto stage = sbe::makeS<sbe::ScanStage>(collection->uuid(), resultSlot, recordIdSlot, @@ -321,8 +318,7 @@ std::pair<std::unique_ptr<sbe::PlanStage>, PlanStageSlots> generateOptimizedOplo std::move(seekRecordIdExpression), yieldPolicy, isTailableResumeBranch, - csn->resumeAfterRecordId.has_value(), - lockAcquisitionCallback); + csn->resumeAfterRecordId.has_value()); } // Create a filter which checks the first document to ensure either that its 'ts' is less than @@ -367,7 +363,7 @@ std::pair<std::unique_ptr<sbe::PlanStage>, PlanStageSlots> generateOptimizedOplo // the expression does match, then it returns 'false', which causes the filter (and as a // result, the branch) to EOF immediately. Note that the resultSlot and recordIdSlot // arguments to the ScanStage are boost::none, as we do not need them. - sbe::ScanCallbacks branchCallbacks(lockAcquisitionCallback); + sbe::ScanCallbacks branchCallbacks{}; auto minTsBranch = sbe::makeS<sbe::FilterStage<false, true>>( sbe::makeS<sbe::ScanStage>(collection->uuid(), boost::none /* resultSlot */, @@ -511,7 +507,7 @@ std::pair<std::unique_ptr<sbe::PlanStage>, PlanStageSlots> generateOptimizedOplo true /* forward */, yieldPolicy, csn->nodeId(), - std::move(lockAcquisitionCallback)), + sbe::ScanCallbacks{}), sbe::makeSV(), sbe::makeSV(*seekRecordIdSlot), nullptr, @@ -542,8 +538,7 @@ std::pair<std::unique_ptr<sbe::PlanStage>, PlanStageSlots> generateGenericCollSc const CollectionPtr& collection, const CollectionScanNode* csn, PlanYieldPolicy* yieldPolicy, - bool isTailableResumeBranch, - sbe::LockAcquisitionCallback lockAcquisitionCallback) { + bool isTailableResumeBranch) { const auto forward = csn->direction == CollectionScanParams::FORWARD; invariant(!csn->shouldTrackLatestOplogTimestamp || collection->ns().isOplog()); @@ -569,8 +564,7 @@ std::pair<std::unique_ptr<sbe::PlanStage>, PlanStageSlots> generateGenericCollSc auto&& [fields, slots, tsSlot] = makeOplogTimestampSlotsIfNeeded( state.env, state.slotIdGenerator, csn->shouldTrackLatestOplogTimestamp); - sbe::ScanCallbacks callbacks( - lockAcquisitionCallback, {}, {}, makeOpenCallbackIfNeeded(collection, csn)); + sbe::ScanCallbacks callbacks({}, {}, makeOpenCallbackIfNeeded(collection, csn)); auto stage = sbe::makeS<sbe::ScanStage>(collection->uuid(), resultSlot, recordIdSlot, @@ -596,8 +590,7 @@ std::pair<std::unique_ptr<sbe::PlanStage>, PlanStageSlots> generateGenericCollSc std::move(seekRecordIdExpression), yieldPolicy, isTailableResumeBranch, - true, /* resumeAfterRecordId */ - lockAcquisitionCallback); + true /* resumeAfterRecordId */); } if (csn->filter) { @@ -629,22 +622,12 @@ std::pair<std::unique_ptr<sbe::PlanStage>, PlanStageSlots> generateCollScan( const CollectionPtr& collection, const CollectionScanNode* csn, PlanYieldPolicy* yieldPolicy, - bool isTailableResumeBranch, - sbe::LockAcquisitionCallback lockAcquisitionCallback) { + bool isTailableResumeBranch) { if (csn->minRecord || csn->maxRecord || csn->stopApplyingFilterAfterFirstMatch) { - return generateOptimizedOplogScan(state, - collection, - csn, - yieldPolicy, - isTailableResumeBranch, - std::move(lockAcquisitionCallback)); + return generateOptimizedOplogScan( + state, collection, csn, yieldPolicy, isTailableResumeBranch); } else { - return generateGenericCollScan(state, - collection, - csn, - yieldPolicy, - isTailableResumeBranch, - std::move(lockAcquisitionCallback)); + return generateGenericCollScan(state, collection, csn, yieldPolicy, isTailableResumeBranch); } } } // namespace mongo::stage_builder diff --git a/src/mongo/db/query/sbe_stage_builder_coll_scan.h b/src/mongo/db/query/sbe_stage_builder_coll_scan.h index 58b28a0e1f1..b204c5487a8 100644 --- a/src/mongo/db/query/sbe_stage_builder_coll_scan.h +++ b/src/mongo/db/query/sbe_stage_builder_coll_scan.h @@ -57,7 +57,6 @@ std::pair<std::unique_ptr<sbe::PlanStage>, PlanStageSlots> generateCollScan( const CollectionPtr& collection, const CollectionScanNode* csn, PlanYieldPolicy* yieldPolicy, - bool isTailableResumeBranch, - sbe::LockAcquisitionCallback lockAcquisitionCallback); + bool isTailableResumeBranch); } // namespace mongo::stage_builder diff --git a/src/mongo/db/query/sbe_stage_builder_index_scan.cpp b/src/mongo/db/query/sbe_stage_builder_index_scan.cpp index b1af7fb38e5..9eeeeab6b30 100644 --- a/src/mongo/db/query/sbe_stage_builder_index_scan.cpp +++ b/src/mongo/db/query/sbe_stage_builder_index_scan.cpp @@ -292,8 +292,7 @@ generateOptimizedMultiIntervalIndexScan( boost::optional<sbe::value::SlotId> indexKeyPatternSlot, sbe::value::SlotIdGenerator* slotIdGenerator, PlanYieldPolicy* yieldPolicy, - PlanNodeId planNodeId, - sbe::LockAcquisitionCallback lockAcquisitionCallback) { + PlanNodeId planNodeId) { using namespace std::literals; auto recordIdSlot = slotIdGenerator->generate(); @@ -376,8 +375,7 @@ generateOptimizedMultiIntervalIndexScan( lowKeySlot, highKeySlot, yieldPolicy, - planNodeId, - std::move(lockAcquisitionCallback)); + planNodeId); // Add a project on top of the index scan to remember the snapshotId of the most recent index // key returned by the IndexScan above. Otherwise, the index key's snapshot id would be @@ -451,8 +449,7 @@ makeRecursiveBranchForGenericIndexScan(const CollectionPtr& collection, boost::optional<sbe::value::SlotId> indexKeyPatternSlot, sbe::value::SlotIdGenerator* slotIdGenerator, PlanYieldPolicy* yieldPolicy, - PlanNodeId planNodeId, - sbe::LockAcquisitionCallback lockAcquisitionCallback) { + PlanNodeId planNodeId) { // The IndexScanStage in this branch will always produce a KeyString. As such, we use // 'indexKeySlot' if is defined and generate a new slot otherwise. sbe::value::SlotId resultSlot; @@ -499,8 +496,7 @@ makeRecursiveBranchForGenericIndexScan(const CollectionPtr& collection, lowKeySlot, boost::none, yieldPolicy, - planNodeId, - std::move(lockAcquisitionCallback)); + planNodeId); // Get the low key from the outer side and feed it to the inner side (ixscan). sbe::value::SlotVector outerSv = sbe::makeSV(); @@ -631,8 +627,7 @@ generateGenericMultiIntervalIndexScan(const CollectionPtr& collection, boost::optional<sbe::value::SlotId> indexKeyPatternSlot, sbe::value::SlotIdGenerator* slotIdGenerator, sbe::value::SpoolIdGenerator* spoolIdGenerator, - PlanYieldPolicy* yieldPolicy, - sbe::LockAcquisitionCallback lockAcquisitionCallback) { + PlanYieldPolicy* yieldPolicy) { using namespace std::literals; auto resultSlot = slotIdGenerator->generate(); @@ -752,8 +747,7 @@ generateGenericMultiIntervalIndexScan(const CollectionPtr& collection, savedKeyPattern, slotIdGenerator, yieldPolicy, - ixn->nodeId(), - std::move(lockAcquisitionCallback)); + ixn->nodeId()); // Construct a union stage from the two branches. auto makeSlotVector = [](sbe::value::SlotId headSlot, const sbe::value::SlotVector& varSlots) { @@ -805,8 +799,7 @@ std::pair<sbe::value::SlotId, std::unique_ptr<sbe::PlanStage>> generateSingleInt boost::optional<sbe::value::SlotId> indexKeyPatternSlot, sbe::value::SlotIdGenerator* slotIdGenerator, PlanYieldPolicy* yieldPolicy, - PlanNodeId planNodeId, - sbe::LockAcquisitionCallback lockAcquisitionCallback) { + PlanNodeId planNodeId) { auto recordIdSlot = slotIdGenerator->generate(); auto lowKeySlot = slotIdGenerator->generate(); auto highKeySlot = slotIdGenerator->generate(); @@ -860,8 +853,7 @@ std::pair<sbe::value::SlotId, std::unique_ptr<sbe::PlanStage>> generateSingleInt lowKeySlot, highKeySlot, yieldPolicy, - planNodeId, - std::move(lockAcquisitionCallback)); + planNodeId); // Add a project on top of the index scan to remember the snapshotId of the most recent index // key returned by the IndexScan above. Otherwise, the index key's snapshot id would be @@ -896,7 +888,6 @@ std::pair<std::unique_ptr<sbe::PlanStage>, PlanStageSlots> generateIndexScan( const IndexScanNode* ixn, const sbe::IndexKeysInclusionSet& originalIndexKeyBitset, PlanYieldPolicy* yieldPolicy, - sbe::LockAcquisitionCallback lockAcquisitionCallback, StringMap<const IndexAccessMethod*>* iamMap, bool needsCorruptionCheck) { @@ -970,23 +961,21 @@ std::pair<std::unique_ptr<sbe::PlanStage>, PlanStageSlots> generateIndexScan( auto&& [lowKey, highKey] = intervals[0]; sbe::value::SlotId recordIdSlot; - std::tie(recordIdSlot, stage) = - generateSingleIntervalIndexScan(collection, - indexName, - keyPattern, - ixn->direction == 1, - std::move(lowKey), - std::move(highKey), - indexKeyBitset, - indexKeySlots, - snapshotIdSlot, - indexIdSlot, - indexKeySlot, - indexKeyPatternSlot, - state.slotIdGenerator, - yieldPolicy, - ixn->nodeId(), - std::move(lockAcquisitionCallback)); + std::tie(recordIdSlot, stage) = generateSingleIntervalIndexScan(collection, + indexName, + keyPattern, + ixn->direction == 1, + std::move(lowKey), + std::move(highKey), + indexKeyBitset, + indexKeySlots, + snapshotIdSlot, + indexIdSlot, + indexKeySlot, + indexKeyPatternSlot, + state.slotIdGenerator, + yieldPolicy, + ixn->nodeId()); outputs.set(PlanStageSlots::kRecordId, recordIdSlot); } else if (intervals.size() > 1) { @@ -1007,8 +996,7 @@ std::pair<std::unique_ptr<sbe::PlanStage>, PlanStageSlots> generateIndexScan( indexKeyPatternSlot, state.slotIdGenerator, yieldPolicy, - ixn->nodeId(), - std::move(lockAcquisitionCallback)); + ixn->nodeId()); outputs.set(PlanStageSlots::kRecordId, recordIdSlot); } else { @@ -1027,8 +1015,7 @@ std::pair<std::unique_ptr<sbe::PlanStage>, PlanStageSlots> generateIndexScan( indexKeyPatternSlot, state.slotIdGenerator, state.spoolIdGenerator, - yieldPolicy, - std::move(lockAcquisitionCallback)); + yieldPolicy); outputs.set(PlanStageSlots::kRecordId, recordIdSlot); } diff --git a/src/mongo/db/query/sbe_stage_builder_index_scan.h b/src/mongo/db/query/sbe_stage_builder_index_scan.h index 71a7e0eafe6..846fa7fbbfb 100644 --- a/src/mongo/db/query/sbe_stage_builder_index_scan.h +++ b/src/mongo/db/query/sbe_stage_builder_index_scan.h @@ -57,7 +57,6 @@ std::pair<std::unique_ptr<sbe::PlanStage>, PlanStageSlots> generateIndexScan( const IndexScanNode* ixn, const sbe::IndexKeysInclusionSet& indexKeyBitset, PlanYieldPolicy* yieldPolicy, - sbe::LockAcquisitionCallback lockAcquisitionCallback, StringMap<const IndexAccessMethod*>* iamMap, bool needsCorruptionCheck); @@ -95,7 +94,6 @@ std::pair<sbe::value::SlotId, std::unique_ptr<sbe::PlanStage>> generateSingleInt boost::optional<sbe::value::SlotId> keyPatternSlot, sbe::value::SlotIdGenerator* slotIdGenerator, PlanYieldPolicy* yieldPolicy, - PlanNodeId nodeId, - sbe::LockAcquisitionCallback lockAcquisitionCallback); + PlanNodeId nodeId); } // namespace mongo::stage_builder diff --git a/src/mongo/db/query/sbe_stage_builder_test_fixture.cpp b/src/mongo/db/query/sbe_stage_builder_test_fixture.cpp index 36fb19ed215..84a471c1841 100644 --- a/src/mongo/db/query/sbe_stage_builder_test_fixture.cpp +++ b/src/mongo/db/query/sbe_stage_builder_test_fixture.cpp @@ -39,7 +39,7 @@ namespace mongo { std::unique_ptr<QuerySolution> SbeStageBuilderTestFixture::makeQuerySolution( std::unique_ptr<QuerySolutionNode> root) { - auto querySoln = std::make_unique<QuerySolution>(QueryPlannerParams::Options::DEFAULT); + auto querySoln = std::make_unique<QuerySolution>(); querySoln->setRoot(std::move(root)); return querySoln; } diff --git a/src/mongo/db/query/sbe_sub_planner.cpp b/src/mongo/db/query/sbe_sub_planner.cpp index e0d08f10a04..77b40a2121d 100644 --- a/src/mongo/db/query/sbe_sub_planner.cpp +++ b/src/mongo/db/query/sbe_sub_planner.cpp @@ -58,15 +58,15 @@ CandidatePlans SubPlanner::plan( // branch of the OR query. In this case, fail with a 'QueryPlanKilled' error. _indexExistenceChecker.check(); + // Ensure that no previous plans are registered to yield while we multi plan each branch. + _yieldPolicy->clearRegisteredPlans(); + std::vector<std::pair<std::unique_ptr<PlanStage>, stage_builder::PlanStageData>> roots; for (auto&& solution : solutions) { roots.push_back(stage_builder::buildSlotBasedExecutableTree( _opCtx, _collection, *cq, *solution, _yieldPolicy)); } - // Ensure that no previous plans are registered to yield while we multi plan each branch. - _yieldPolicy->clearRegisteredPlans(); - // Clear any plans registered to yield once multiplanning is done for this branch. We don't // want to leave dangling pointers to the execution plans used in multi planning hanging // around in the YieldPolicy. @@ -82,12 +82,13 @@ CandidatePlans SubPlanner::plan( return std::move(candidates[winnerIdx].solution); }; + auto subplanSelectStat = QueryPlanner::choosePlanForSubqueries( + _cq, _queryParams, std::move(subplanningStatus.getValue()), multiplanCallback); + // One of the indexes in '_queryParams' might have been dropped while planning the final branch // of the OR query. In this case, fail with a 'QueryPlanKilled' error. _indexExistenceChecker.check(); - auto subplanSelectStat = QueryPlanner::choosePlanForSubqueries( - _cq, _queryParams, std::move(subplanningStatus.getValue()), multiplanCallback); if (!subplanSelectStat.isOK()) { // Query planning can continue if we failed to find a solution for one of the children. // Otherwise, it cannot, as it may no longer be safe to access the collection (an index diff --git a/src/mongo/db/transaction_history_iterator.cpp b/src/mongo/db/transaction_history_iterator.cpp index bb9e33662c6..ae21a26038e 100644 --- a/src/mongo/db/transaction_history_iterator.cpp +++ b/src/mongo/db/transaction_history_iterator.cpp @@ -86,12 +86,8 @@ BSONObj findOneOplogEntry(OperationContext* opCtx, CollectionCatalog::get(opCtx)->getDatabaseProfileLevel(NamespaceString::kLocalDb), Date_t::max()); - auto exec = - uassertStatusOK(getExecutorFind(opCtx, - &oplogRead.getCollection(), - std::move(cq), - permitYield, - QueryPlannerParams::OMIT_REPL_STATE_PERMITS_READS_CHECK)); + auto exec = uassertStatusOK( + getExecutorFind(opCtx, &oplogRead.getCollection(), std::move(cq), permitYield)); PlanExecutor::ExecState getNextResult; try { diff --git a/src/mongo/dbtests/query_stage_multiplan.cpp b/src/mongo/dbtests/query_stage_multiplan.cpp index 17b40df8cee..0a89202af53 100644 --- a/src/mongo/dbtests/query_stage_multiplan.cpp +++ b/src/mongo/dbtests/query_stage_multiplan.cpp @@ -76,7 +76,7 @@ using std::vector; static const NamespaceString nss("unittests.QueryStageMultiPlan"); std::unique_ptr<QuerySolution> createQuerySolution() { - auto soln = std::make_unique<QuerySolution>(QueryPlannerParams::Options::DEFAULT); + auto soln = std::make_unique<QuerySolution>(); soln->cacheData = std::make_unique<SolutionCacheData>(); soln->cacheData->solnType = SolutionCacheData::COLLSCAN_SOLN; soln->cacheData->tree = std::make_unique<PlanCacheIndexTree>(); @@ -499,12 +499,8 @@ TEST_F(QueryStageMultiPlanTest, MPSExplainAllPlans) { std::make_unique<MultiPlanStage>(_expCtx.get(), ctx.getCollection(), cq.get()); // Put each plan into the MultiPlanStage. Takes ownership of 'firstPlan' and 'secondPlan'. - mps->addPlan(std::make_unique<QuerySolution>(QueryPlannerParams::Options::DEFAULT), - std::move(firstPlan), - ws.get()); - mps->addPlan(std::make_unique<QuerySolution>(QueryPlannerParams::Options::DEFAULT), - std::move(secondPlan), - ws.get()); + mps->addPlan(std::make_unique<QuerySolution>(), std::move(firstPlan), ws.get()); + mps->addPlan(std::make_unique<QuerySolution>(), std::move(secondPlan), ws.get()); // Making a PlanExecutor chooses the best plan. auto exec = uassertStatusOK(plan_executor_factory::make(_expCtx, |