Skip to content

compute: walk fast-path index peeks off the serving worker - #38429

Draft
antiguru wants to merge 3 commits into
MaterializeInc:mainfrom
antiguru:mh/peek-offload
Draft

compute: walk fast-path index peeks off the serving worker#38429
antiguru wants to merge 3 commits into
MaterializeInc:mainfrom
antiguru:mh/peek-offload

Conversation

@antiguru

Copy link
Copy Markdown
Member

Status: parked, not seeking review

This exists so the experiment that decides its fate can deploy it. It is not on its way in, and it should not be reviewed toward merge. Tracked as CPU-217.

There are four candidates for one defect, and the grid is two independent axes rather than one:

run to completion yields
on the serving worker today's default #38040, cooperative yielding
off the worker this PR coherent, unmeasured, unimplemented

The decision rule, registered before the experiment runs: if yielding alone matches this on E1, E11 and E8b, this should be deleted rather than merged. If it wins on E8b alone, its case narrows to the unattributed swap-walk duration and nothing else.

One measurement already counts against it. E12 found it reproducibly worse than doing nothing when a peek queues behind a long operator activation, because dispatch happens in process_peeks after step_or_park returns and retirement costs another step. That cost is paid before the walk starts, so giving the walk yield points cannot recover it.

What it does

Takes an owned, Send snapshot of a peek's cursor and walks it on a blocking task instead of inline on the timely worker that received it, so a long scan no longer delays the peeks queued behind it.

The snapshot owns the Arc batches its cursor covers, which is what makes it Send: a worker reads its own traces through an Rc-based reader, so neither borrowing from one nor owning Rc batches would cross a thread. That dependency is satisfied by the Arc-backed production spines merged in #38396. The walk is generic over the cursor source, so any owned snapshot feeds it.

Bounded by index_peek_offload_max_inflight, since each in-flight walk retains the batches its cursor covers, a memory bound rather than a concurrency knob. mz_index_peek_walks_total{substrate} exists so that "the offload changed nothing" and "the offload never engaged" are distinguishable, which cost a round of staging measurement before it existed. An offloaded walk can also divert to the peek response stash partway through, without which the feature is unreachable in a production configuration, because production runs the stash on.

The errs scan and the ok-iterator drain move out of collect_finished_data and collect_ok_finished_data into scan_errs_for_error and drain_ok_iterator, generic over the trace so the inline walk and the offloaded walk share them.

Relation to the two-runtime work

Extracted from #38242, which carried this on top of the interactive runtime. Nothing here depends on that branch, and the interactive runtime does not need any of it: E2 showed the peek-tail win belongs to the walk substrate rather than to a second runtime. This branch is based directly on main and stacks on nothing.

The flag naming discussed on #38239 (a named substrate rather than a boolean, since placement and preemption are independent) is not implemented here. It is specified only, and deliberately not built while the mechanism itself is undecided.

Verification

cargo check --workspace --all-targets clean, bin/lint and bin/fmt clean, no new clippy warnings. cargo test -p mz-compute --lib 37/37, including offloaded_walk_matches_the_inline_walk, which asserts the offloaded walk returns exactly what the inline walk returns.

🤖 Generated with Claude Code

Takes an owned, `Send` snapshot of a peek's cursor and walks it on a blocking task
instead of inline on the timely worker that received it, so a long scan no longer
delays the peeks queued behind it. The snapshot owns the `Arc` batches its cursor
covers, which is what makes it `Send`: a worker reads its own traces through an
`Rc`-based reader, so borrowing from one, or owning `Rc` batches, would not cross a
thread. The walk is generic over the cursor source, so any owned snapshot feeds it.

Bounded by `index_peek_offload_max_inflight`, because each in-flight walk retains the
batches its cursor covers. `mz_index_peek_walks_total{substrate}` exists so that "the
offload changed nothing" and "the offload never engaged" are distinguishable, which
cost a round of staging measurement before it did. An offloaded walk can divert to the
peek response stash partway through, without which the feature is unreachable in a
production configuration, since production runs the stash on.

The errs scan and the ok-iterator drain move out of `collect_finished_data` and
`collect_ok_finished_data` into `scan_errs_for_error` and `drain_ok_iterator`, which
are generic over the trace so the inline walk and the offloaded walk share them.

PARKED. This is one of four candidates for the same defect, and the experiment that
chooses between them has not run. Cooperative peek yielding (MaterializeInc#38040) is a second, and
placement and preemption are independent axes, so an off-worker walk that yields is an
untried fourth. Measurement already found this mechanism reproducibly worse than doing
nothing when a peek queues behind a long operator activation. The decision rule is
registered in CPU-217: if yielding alone matches this on E1, E11 and E8b, this should
be deleted rather than merged.

It exists as a branch so the experiment can deploy it, not because it is on its way in.

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
@antiguru
antiguru requested review from a team as code owners August 24, 2026 13:43
@antiguru
antiguru marked this pull request as draft August 24, 2026 13:44
antiguru and others added 2 commits August 24, 2026 15:57
The walk counter had two values, so a peek that wanted to offload and ran inline
at the in-flight cap was indistinguishable from one that ran inline because the
flag was off. Those need different responses: the first is
`index_peek_offload_max_inflight` being too low for the workload, the second is
configuration. `substrate="capped"` is the third value, and the three partition
every walk.

Cap saturation is self-reinforcing, which is why it needs its own counter. Slots
return when walks finish, so a worker whose walks run long accumulates in-flight
walks, reaches the cap, and falls back to the inline walk that blocks its step
loop, which makes it accumulate faster still. The worker that most needs the
offload is the first to lose it, and without this counter that reads as the
offload simply not helping.

`WalkPlacement` replaces the `Option<InFlightOffload>` the dispatch used, so the
inline arm knows which of the two reasons put it there.

Also correct the `INDEX_PEEK_OFFLOAD_MAX_INFLIGHT` documentation, which claimed
an in-flight walk holds the trace back from compacting. It does not: the walk
owns `Arc` batches and the dispatching path drops its trace handle before the
walk starts, so the cost is retained memory and a blocking-pool thread. The doc
now also says the count is per worker, so a replica's bound is `workers * this`,
and that a walk diverting to the stash holds its slot across the persist upload
rather than just the cursor walk.

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
`TraceReader::cursor` returns its batches by value, and since the Arc-backed
production spines those batches are `Arc`s, so the pair it hands back already
owns everything it reads and is `Send` as it stands. `local_snapshot` existed to
produce a property the cursor already had.

Deleting it removes the module, its `LocalSnapshot` and `SnapshotError` types,
and the unreachable soft-panic arm that only existed to handle a snapshot
failure that `cursor` cannot report. The compaction gate the snapshot duplicated
is still applied: `snapshot_for_offload` checks the trace bundle's compaction
frontier against the peek time before taking any cursor, as the inline walk
does.

The `Send` assertion over `PeekResultIterator` moves to that type's own module,
since it is a property of the cursor rather than of any wrapper, and it is what
lets the walk leave the worker that owns the trace.

Also restore `seek_fulfillment`'s doc comment, which a merge had concatenated
onto the front of `snapshot_for_offload`.

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant