-
Type: Bug
-
Resolution: Won't Fix
-
Priority: Major - P3
-
None
-
Affects Version/s: None
-
Component/s: None
-
None
-
ALL
-
The CollectionScan::work() method returns NEED_TIME when it is scanning a clustered collection and it is unable to seekNear() close enough to the target record. As a result, PlanExecutorImpl::_getNextImpl() will continue to the next iteration in the loop, resulting in another check for yielding.
In the case of jstests/noPassthrough/read_concern_snapshot_yielding.js, the test sets internalQueryExecYieldIterations to 2 and the internalQueryExecYieldPeriodMS to 24 hours. The effect of this is that the setInterruptOnlyPlansCheckForInterruptHang failpoint will be entered whenever the loop in PlanExecutorImpl::_getNextImpl() reaches its second iteration. So, if the collection being scanned is clustered, in this case config.transactions, and if the scan is unable to reach to the interior of the scan boundary, the failpoint will be entered before the first document is made available.
My changes to make config.transactions clustered in SERVER-80862 results in this test nondeterministically failing because the failpoint is reached too early in this way. The patch below provides a solution likely unfit for production, but which demonstrates the problem:
diff --git a/src/mongo/db/exec/collection_scan.cpp b/src/mongo/db/exec/collection_scan.cpp index 4e88a1cc4fb..69362d2cc9f 100644 --- a/src/mongo/db/exec/collection_scan.cpp +++ b/src/mongo/db/exec/collection_scan.cpp @@ -156,6 +156,7 @@ CollectionScan::CollectionScan(ExpressionContext* expCtx, } PlanStage::StageState CollectionScan::doWork(WorkingSetID* out) { + _needTimeDueToClusteredCollection = false; if (_commonStats.isEOF) { _priority.reset(); return PlanStage::IS_EOF; @@ -474,6 +475,8 @@ PlanStage::StageState CollectionScan::returnIfMatches(WorkingSetMember* member, // mark their position for resuming the tailable scan later on. if (beforeStartOfRange(_params, *member)) { _workingSet->free(memberID); + LOGV2(8086240, "setting PlanStage::NEED_TIME bc clustered collection didn't seekNear close enough"); + _needTimeDueToClusteredCollection = true; return PlanStage::NEED_TIME; } diff --git a/src/mongo/db/exec/plan_stage.h b/src/mongo/db/exec/plan_stage.h index bdf48637c72..4a2ae06c4a0 100644 --- a/src/mongo/db/exec/plan_stage.h +++ b/src/mongo/db/exec/plan_stage.h @@ -363,6 +363,11 @@ public: _commonStats.executionTime.emplace(0); } + bool needTimeDueToClusteredCollection() const { + return _needTimeDueToClusteredCollection; + } + bool _needTimeDueToClusteredCollection{false}; + protected: /** * Performs one unit of work. See comment at work() above. diff --git a/src/mongo/db/query/plan_executor_impl.cpp b/src/mongo/db/query/plan_executor_impl.cpp index 0828f77067c..c68d29388c2 100644 --- a/src/mongo/db/query/plan_executor_impl.cpp +++ b/src/mongo/db/query/plan_executor_impl.cpp @@ -415,7 +415,7 @@ PlanExecutor::ExecState PlanExecutorImpl::_getNextImpl(Snapshotted<Document>* ob } }; - if (_yieldPolicy->shouldYieldOrInterrupt(_opCtx)) { + if (!_root->needTimeDueToClusteredCollection() && _yieldPolicy->shouldYieldOrInterrupt(_opCtx)) { uassertStatusOK(_yieldPolicy->yieldOrInterrupt(_opCtx, whileYieldingFn)); }
With this patch, the failure is no longer reproducible. I suspect that this is a bona fide bug in the query code, since it seems wrong to me that yielding would occur more often because a collection is clustered (note that the issue never occurs when the collection is nonclustered).
- is related to
-
SERVER-80862 Make config.transactions a clustered collection
- Closed