compute: serve fast-path peeks on the interactive runtime - #38392
compute: serve fast-path peeks on the interactive runtime#38392antiguru wants to merge 1 commit into
Conversation
cf82e1f to
77e275a
Compare
| pub(crate) fn role(&self) -> ComputeRuntimeRole { | ||
| self.role | ||
| } | ||
|
|
There was a problem hiding this comment.
Function moved for no particular reason.
There was a problem hiding this comment.
Agreed, no reason. Moved back to where #38389 introduced it, right after new(). This was churn imported by taking compute_state.rs wholesale from the original branch. (Posted by Claude Code.)
6984b18 to
f359f28
Compare
f359f28 to
f45dc4c
Compare
f45dc4c to
40e6744
Compare
40e6744 to
0ba0d59
Compare
0ba0d59 to
2db1bb4
Compare
2db1bb4 to
76b96ab
Compare
76b96ab to
b288248
Compare
b288248 to
f29b660
Compare
f29b660 to
bb7c5fc
Compare
| || (dataflow.is_transient() | ||
| && !dataflow.until.is_empty() | ||
| && dataflow.subscribe_ids().next().is_none() | ||
| && dataflow.copy_to_ids().next().is_none()), |
There was a problem hiding this comment.
I wonder if this should be a function on the dataflow description. We're repeating the condition from the multiplexer.
There was a problem hiding this comment.
Agreed, and it is now DataflowDescription::is_peek_dataflow() in mz-compute-types, next to is_single_time(). #38388's router and this tripwire ask the same method of the same description, so the assert can finally check what it claims to: previously a drift between the two spellings was exactly what it was meant to catch, and it was written as a second copy of the thing that might drift.
The predicate also got stricter on the way: is_single_time() in place of !until.is_empty(), per the discussion on the router. Details in the reply on #38388.
Posted by Claude Code.
| /// | ||
| /// `fuel` bounds how far the walk may go on this worker, exactly as it bounds a walk over a | ||
| /// maintained trace. | ||
| fn seek_fulfillment( |
There was a problem hiding this comment.
This looks like duplication with the regular index peek logic, is that right? The peek offload work aimed at reducing duplication, and canonicalizing all peek structure (which it not has done completely, but that's a different story.) So my ask here would be to check if we can combine the walk, maybe by making them generic over the type of index they're walking.
There was a problem hiding this comment.
Right that it was duplicated, though not in the walk. The walk was already shared: both build a PeekScan and hand it to the generic walk_scan, which is what the peek-offload canonicalisation bought. What was copied is the ~25 lines of frontier gating in front of it, and the only differences were cosmetic: where (oks, errs) come from, and TraceBundle::compaction_frontier() versus an explicit antichain_join of the same two frontiers, which is literally what that method computes.
Extracted as gate_peek, generic over both traces via the existing PeekOksTrace/PeekErrsTrace markers, returning a PeekGate of Open/NotReady/Compacted. That required pinning Time = Timestamp on the two marker traits, which they should have carried anyway: both only ever describe traces over mz_repr::Timestamp, and only the cursor GATs were constrained before.
IndexPeek::collect_finished_data is deliberately left alone. It is main's method with main's tests in index_peek_tests.rs, which call it to exercise the walk while bypassing the gate, so folding it in would have churned code this stack has no business touching.
Posted by Claude Code.
| // One is per collection and carries no dataflow identity, so it cannot go stale across a | ||
| // reconnection, and it only ever rises. Clearing it would drop the hold back to the | ||
| // minimum time until the replayed compactions raised it again. See | ||
| // `doc/developer/design/20260720_two_runtime_compute/design.md`. |
There was a problem hiding this comment.
Is the design still part of the stack?
There was a problem hiding this comment.
It never was in this stack. design.md lives in #38239, which is open and design-only, and whose description says it lands first so the implementation PRs can cite it rather than restate the argument. So the reference resolves iff #38239 merges ahead of this stack, and today it points at a file on no landed branch.
That ordering was tracked nowhere, which is why it could go unnoticed. Filed as CPU-239 on the Interactive read isolation project, naming this call site as the reason: the standing-hold argument is written down only there.
Left the reference as it is. Inlining the argument here would duplicate the design rather than cite it, which is the thing the design PR exists to avoid.
Posted by Claude Code.
bb7c5fc to
911e0ce
Compare
152df60 to
7baf4dc
Compare
QA LLM Review1. MEDIUM --
|
7baf4dc to
861a6db
Compare
The interactive runtime holds no local traces, so an index peek there resolves against the sharing registry instead. `PeekScan` and the error walk beneath it become generic over the traces they read, and an interactive peek opens its scan over the registry's `SharedOksHandle` and `SharedErrsHandle`. Both flavours of index peek then spend one budget, report one set of metrics, and reach the peek stash through the one offload driver. A shared peek whose arrangement is not yet published, or whose upper has not sealed the peek timestamp, waits in `pending_work` keyed by a `WorkId` and indexed by the id it waits on. A publication or seal marks that id dirty and wakes the worker, which gives a turn to exactly the items indexed under the ids that changed, so wakeups scale with what changed rather than with total pending work. Past that gate a shared peek is an ordinary index peek: it queues for a turn like any other, and a walk that outruns the activation's fuel or fills a batch bound for the stash leaves for a driver. The sweep still runs on every step, because a persist read and an offloaded walk each wake the worker through a channel of their own rather than through the dirty set, but nothing waiting on a publication or a seal is ever swept. Interactive dataflows build immediately in command arrival order rather than deferring until their dependency is published. An import over an unadopted placeholder produces no data and holds its output frontier at the minimum until a publisher adopts the same slot, so late binding replaces the deferral. The interactive runtime reports only its transient collections' frontiers. It shares the identity of every non-transient collection with maintenance, which owns and reports the real frontiers, and the controller keeps one frontier stream per collection, so reporting the shared ones would race the owner and regress it. For the same reason its logging is forced off: it serves introspection peeks from maintenance's published copies, and its own empty copies would clobber them. The consequence is that nothing the interactive runtime does appears in introspection, tracked as CPU-222. Reconciliation drops `pending_work` and `dep_index`, whose peeks belong to the reconciled-away connection. The standing holds in the registry deliberately survive: one is per collection, carries no dataflow identity, and only rises, so clearing it would drop the arrangement's bound to the minimum until replayed compactions raised it again. Reachable only on a runtime holding the `Interactive` role, which requires the dyncfg that is still off everywhere. Tests are out of line in `compute_state/tests.rs`, per the convention in `src/compute/AGENTS.md`. Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
861a6db to
a4480c6
Compare
Seventh of eight PRs splitting #37770. Stacks on #38391. Tracked by CPU-216.
The interactive runtime holds no local traces, so an index peek there resolves against the sharing registry.
IndexPeekgains anIndexTracessource:Localpins aTraceBundlefor the peek's life,Sharedresolves handles from the registry on every attempt and holds nothing in between. Both hand the scan the same enum trace types, so oneIndexPeek, oneIndexPeekScan, and onePendingPeek::Indexserve both runtimes and the walk, gate, offload, and cancel paths are written once.A shared peek that is not ready lives in
pending_work, keyed by the index it waits on, not inqueued_peeks. A publication or seal marks that id dirty and wakes the worker, which re-examines exactly the peeks parked under the changed ids, so wakeups scale with what changed rather than with total pending work. Fast-path persist peeks still land inpending_peekson every runtime, because their persist-read task wakes the worker with no dirty signal.Interactive dataflows build immediately in command arrival order rather than deferring until their dependency is published. An import over an unbacked publication point produces no data and holds its output frontier at the minimum until a publisher adopts the same slot, so late binding replaces the deferral.
The interactive runtime reports only its transient collections' frontiers, since it shares the identity of every non-transient collection with maintenance and the controller keeps one frontier stream per collection. For the same reason its logging is forced off: it serves introspection peeks from maintenance's published copies. The consequence is that nothing the interactive runtime does appears in introspection, tracked as CPU-222. That wants resolving before the flag is turned on anywhere it would hide real work.
Reconciliation drops
pending_work. The standing holds in the registry deliberately survive: one is per collection, carries no dataflow identity, and only rises, so clearing it would drop the arrangement's bound to the minimum until replayed compactions raised it again.Reachable only on a runtime holding the
Interactiverole, which requires the dyncfg that is still off everywhere.