-
Type:
Investigation
-
Resolution: Won't Do
-
Priority:
Major - P3
-
None
-
Affects Version/s: None
-
Component/s: None
-
None
-
Tools and Replicator
Downstream Changes Summary
Project context
---------------
$_internalSearchIdLookup is the internal stage that resolves $search/$vectorSearch result
documents by _id after the mongot remote query returns matching ids. Historically it always ran
through a per-lookup routed aggregation (local read). With featureFlagSearchOptimizedIdLookup on
and no view pipeline, the stage now uses an SBE point-read as primary (search always runs local;
sharding-filter drops orphans), falling back to the routed aggregation executor when SBE declines
(e.g. an object _id the slot binder cannot encode). A view pipeline always forces the aggregation
path. Change stream updateLookup uses the analogous primary-with-fallback chain described in
SERVER-129513/129514/129515 (SBE for collection streams, Express for database/cluster-wide
streams, aggregation fallback).
What this ticket adds
---------------------
1. A brand-new serverStatus section, metrics.search.idLookup, mirroring the updateLookup per-
engine cells for the idLookup stage:
- {sbe,aggregation}.found / notFound (counters): the lookup ran on this engine and did / did
not resolve the _id.
- {sbe,aggregation}.notHandled (counter): the engine declined; the fallback serves it. Not an
error. - {sbe,aggregation}
.latencyMicros (histogram, microseconds): wall time of a single lookup
attempt; recorded only for executed (found/notFound) lookups.
The sbe cells record only when the optimization flag is on; aggregation records in both modes.
2. New enrich-batch counters (engine-independent, one per consumer): - metrics.changeStreams.updateLookup.enrichBatchesStarted
- metrics.search.idLookup.enrichBatchesStarted
One increment per enrichment SUB-BATCH opened by BatchedEnrichmentStage - the resource-scope
window, not the client getMore/fill batch (one fill window may open several sub-batches).
Counted before beginBatch(), so failed batch openings are included. Purpose: a direct
invariance signal for the batching knobs (maxInputEvents / maxInputBytes / maxOutputBytes) -
if a knob changes, this counter must move.
All metrics are also exported through OpenTelemetry under the mongodb.serverStatus.metrics.*
prefix, appear zeroed in serverStatus from startup regardless of flag state, and are per mongod
process. No new commands, options, or wire-protocol changes; no change to lookup results.
Backported to v9.0 (BACKPORT-29761).
Description of Linked Ticket
Overview
Change-stream updateLookup and $_internalSearchIdLookup share the
SingleDocumentLookupExecutor / BatchedEnrichmentStage enrichment abstraction. This work extends
the per-engine lookup metrics to $_internalSearchIdLookup, adds per-consumer enrich-batch
counters, and broadens test coverage across the dimensions the shared module serves: _id shapes
(including fallback-handled declines), clustered collections, collation, sharding and placement
changes, concurrent DDL, batching knobs, and interrupts.
Observability
- Per-engine outcome and latency metrics for search idLookup under search.idLookup.sbe and
search.idLookup.aggregation (found, notFound, notHandled, latencyMicros),
wired in buildIdLookupExecutor(). - Per-consumer enrich-window counters changeStreams.updateLookup.enrichBatchesStarted and
search.idLookup.enrichBatchesStarted, making batching knobs directly verifiable.
Test coverage
$_internalSearchIdLookup
- Coverage reworked around a shared mock-mongot util: _id shape matrix, unsupported shapes
(regex/array) asserted to resolve cleanly through the fallback executor, mixed-shape batches
with per-engine attribution, view-pipeline fallback, DDL between getMores, killOp mid-batch. - Batching-knob invariance verified via the new enrich-batch counters.
- Sharding/DDL concurrency: shard-key strategy matrix, migration orphan filtering,
parked-cursor-across-migration, view-backed orphan case.
Change-stream updateLookup
- Engine-attribution metrics tests across clustered/collation matrices, including mixed
scalar/compound _id batches. - Batching-knob verification with engine-based eligibility.
- DDL timing: update_lookup_before_ddl.js rework plus a new noPassthrough mid-batch file using
the hangBeforeChangeStreamUpdateLookup fail point (mid-batch cached-acquisition staleness,
killOp mid-batch). - TooManyMatchingDocuments regression test for the sharded scatter-gather case.
- New shared helpers: expectedUpdateLookupEngine(), readUpdateLookupDelta(),
assertChangeStreamEventsEqUnordered() / assertChangeStreamEventsEqWithDeploymentAwareness().
Unit tests
- SbeSingleDocumentLookupExecutor: decline paths for unsupported _id shapes (non-scalar _id
support tracked asSERVER-134080), cached-plan survival across mid-sequence declines,
accept-side allow-list, shard filtering, plan invalidation, lifecycle. - Stats recorders: all factories plus cross-consumer cell independence, enrich-batch counters,
and throw-integrity for the aggregation executor.
Observations recorded for follow-up
- The view-backed local-read executor appears not to request shard filtering (orphan returned);
pinned as a KNOWN ISSUE assertion in the sharded DDL-concurrency test. - The shard filter appears stale across a parked cursor even under SBE; pinned the same way.
Related
- depends on
-
SERVER-134581 Harden updateLookup and $_internalSearchIdLookup enrichment testing with per-engine lookup metrics
-
- Closed
-