-
Type:
New Feature
-
Resolution: Won't Fix
-
Priority:
Major - P3
-
None
-
Affects Version/s: None
-
Component/s: None
-
None
-
Query Execution
-
QE 2026-07-06
-
None
-
None
-
None
-
None
-
None
-
None
-
None
Context
SERVER-129529 routes collection-level change-stream updateLookup through an SBE executor
that compiles a parameterized plan once and reuses it across getMores. That plan caches a
CollectionAcquisition inside sbe::ScanStageBase::_coll, captured once at prepare() time and
held for the plan's whole cached lifetime -- many getMores, not one.
Problem
OnDemandCollectionAcquirer's acquisition is backed by TransactionResources scoped to a single
OperationContext. Since ScanStageBase::_coll deliberately outlives that opCtx (that's the whole
point of caching the plan), the underlying TransactionResources gets torn down while a live
reference to it is still held, tripping the ~CollectionsInUse / held storage-admission-ticket
invariants (server crash: leftoverCollections == 0 or !_ticket->valid()).
Fix
Acquire the watched (updateLookup target) collection upfront, alongside the oplog, in
OplogAggCatalogState -- via a new buildChangeStreamAcquisitionRequests() helper -- so its
TransactionResources are owned by the pipeline's cursor-scoped stasher instead of any single
operation. A plan-cached reference into cursor-scoped storage is safe by construction; there's
no operation whose teardown it needs to survive.
Because the watched collection is a dynamic user collection (may be renamed, dropped, or
recreated while the stream runs), add an opt-in AcquisitionPrerequisites flag
tolerateCollectionExistenceChangeOnRestore: a kRead acquisition with this flag set is
re-acquired in its current state across yield/restore instead of killing the query with
QueryPlanKilled. Default false, so existing acquisitions are unaffected.
Scope
This ticket lands the acquisition infrastructure only:
* tolerateCollectionExistenceChangeOnRestore in shard_role.h/.cpp, transaction_resources.h
* buildChangeStreamAcquisitionRequests() (new file, commands/query_cmd/)
* Wiring into OplogAggCatalogState (aggregation_execution_state.cpp)
Consuming this via bindCatalogInfo and PreAcquiredCollectionAcquirer for the SBE
updateLookup executor is tracked in SERVER-129529.
- blocks
-
SERVER-129529 Route collection-level change-stream updateLookup through the SBE executor
-
- Closed
-
- is related to
-
SERVER-129528 Implement SbeSingleDocumentLookupExecutor for local _id point lookups
-
- Closed
-