Skip to content

Spilling MergeQueue#789

Merged
frankmcsherry merged 1 commit intoTimelyDataflow:masterfrom
frankmcsherry:byte_slab_spill
Apr 17, 2026
Merged

Spilling MergeQueue#789
frankmcsherry merged 1 commit intoTimelyDataflow:masterfrom
frankmcsherry:byte_slab_spill

Conversation

@frankmcsherry
Copy link
Copy Markdown
Member

@frankmcsherry frankmcsherry commented Apr 15, 2026

Summary by Claude:

Three traits in zero_copy::spill:

  • SpillPolicy — fn apply(&mut self, queue: &mut VecDeque). Rewrites queue
    entries in place. Used on both sides: the writer's policy pages data out (Bytes →
    Paged), the reader's policy pages data back in (Paged → Bytes).
  • BytesSpill — fn spill(&mut self, chunks: &mut Vec, handles: &mut Vec<Box>). Drains from chunks, pushes to handles. May stop partway on failure; both
    vecs are left in a consistent state.
  • BytesFetch — fn fetch(self: Box) -> Result<Vec, Box>.
    Consumes the handle; returns data or returns itself for retry.

One type alias:

  • SpillPolicyFn — Arc<dyn Fn() -> (Box, Box) + Send +
    Sync>. Factory producing matched (writer, reader) policy pairs, one per MergeQueue.

Two shipped policies:

  • Threshold (writer) — spills entries past a head reserve when resident bytes exceed
    head_reserve_bytes + threshold_bytes.
  • PrefetchPolicy (reader) — materializes Paged entries near the front up to a byte
    budget.

MergeQueue changes:

  • new_pair(buzzer, writer_policy, reader_policy) -> (MergeQueue, MergeQueue) —
    constructs a matched writer/reader pair. Each carries its own policy. Replaces
    new_spilling and build_reader.
  • extend runs the writer's policy after pushing.
  • drain_into runs the reader's policy before draining. Only pops Bytes entries; Paged
    entries stay for the next call. Buzzes if it returns empty with data still queued,
    preventing consumer stalls.
  • QueueEntry — Bytes(Bytes) | Paged(Box). Internal to the queue;
    drain_into still yields Vec to callers.
  • Not Clone. new + new_pair are the constructors.

Configuration via Hooks:

  • Hooks { refill, spill, log_fn } — bundles comm knobs previously passed as positional
    args. Config::try_build_with(hooks) consumes them. try_build() uses Hooks::default() (no
    spill). The spill field is Option, threaded to every MergeQueue
    construction site (send-side, recv-side, intra-process).

No new runtime dependencies (tempfile is dev-only). The file-backed strategy lives in
the spill_stress example as a reference implementation.

Comment thread communication/src/allocator/zero_copy/bytes_exchange.rs Outdated
@frankmcsherry frankmcsherry force-pushed the byte_slab_spill branch 8 times, most recently from 4dbc97d to b71b052 Compare April 15, 2026 19:57
@frankmcsherry frankmcsherry marked this pull request as ready for review April 15, 2026 20:13
@frankmcsherry frankmcsherry requested a review from antiguru April 15, 2026 20:15
@frankmcsherry
Copy link
Copy Markdown
Member Author

Caveat: I haven't read spill.rs other than the traits, and the "starter implementations" may be bonkers. Potentially right in spirit, but the main goal is the abstraction that allows one to rock up with their own implementation. I'll try and sort them out more tomorrow.

@frankmcsherry frankmcsherry force-pushed the byte_slab_spill branch 5 times, most recently from 916ca37 to 4696b12 Compare April 17, 2026 11:04
@frankmcsherry frankmcsherry changed the title V0 spilling MergeQueue Spilling MergeQueue Apr 17, 2026
@frankmcsherry frankmcsherry merged commit b4e5ef9 into TimelyDataflow:master Apr 17, 2026
9 checks passed
@frankmcsherry frankmcsherry deleted the byte_slab_spill branch April 17, 2026 12:06
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