feat(mpsc): prototype bounded permits with sequenced publication - #291
Draft
tisonkun wants to merge 3 commits into
Draft
feat(mpsc): prototype bounded permits with sequenced publication#291tisonkun wants to merge 3 commits into
tisonkun wants to merge 3 commits into
Conversation
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Summary
Add
BoundedSender::reserve()andtry_reserve(), returning a borrowedPermitthat reserves capacity before a message is constructed. Rework bounded storage around separate claim and publication steps and an exclusive consumer cursor. This draft demonstrates the API and its performance tradeoffs against merged main64d7a94and ecosystem channels.Design Notes
Permit::sendreturns the unsent value if the receiver has disconnected. Capacity waiters retain the existing retry-based notification policy, including barging.fetch_add, writes the payload, and publishes a generation stamp with Release ordering. The single consumer acquires that stamp and advances its own cursor without resetting each slot's stamp. Physical storage rounds up to a power of two; the requested logical capacity remains exact.fetch_add. Pending sends keep the payload outside the capacity retry loop.AtomicWakerand its obsolete provenance entry in a separate cleanup commit. Bounded MPSC keeps its existing local receiver wake protocol.The reservation/publication split follows the Disruptor two-phase publication model, with capacity permits kept separate from short-lived physical claims to support async cancellation and receiver teardown.
Validation
cargo x test: 330 unit/integration tests and 167 doctests passed.cargo x check: the complete feature matrix passed.cargo x lint: formatting, TOML, spelling, source headers, Clippy, and rustdoc passed.MIRIFLAGS=-Zmiri-seed=0 cargo x miri: the complete workflow passed; additional bounded internals and reservation tests passed seeds 1, 2, and 3.Benchmarks
Measured on Apple M4 Max, macOS 26.6.2, rustc
1.99.0-nightly (3d6c19bb9 2026-08-11). Compare main64d7a94ddb5ab9f2e130f8f1cc8f392301e73ebewith demo82d6992028b2b25fd42b50ead4e41e08b7440491. Both were rebuilt at the same temporary build path with the same common benchmark source; the reservation-only suite is excluded from main because its API does not exist there. Flume uses its async feature with default features disabled.Five shuffled rounds, 70 invocations, 685 per-case measurements. Each cell is the median of five run medians. Bulk cases use 50 samples per run and 16,384 messages per sample with warmed, reused channels and tasks/threads. Microbenchmarks use 100 samples of 1,000 iterations. All use Divan's OS timer. Task measurements include scheduling and wakeups, with normal Tokio cooperation enabled;
Pcounts producer tasks, which share four workers except the explicitly marked current-thread cases.The prototype improves the inline 1 KiB cases, while scalar workloads show the cost of separate capacity reservation. At capacity 4096 with eight producer tasks, scalar elapsed time rises from 0.3387 ms to 0.7394 ms, although it remains below Tokio, async-channel, and Flume in that case. Capacity-one cross-worker handoff remains much slower than Flume, as it also is on main. These results support review as a feature/performance tradeoff.
Bounded scalar messages
All times are in ms; lower is better. Delta is demo time / main time − 1.
64d7a9482d6992Bounded inline 1 KiB messages
Four workers; every sample starts with an empty receive registration. Producer identity, per-producer sequence, and payload data are checked on every sample.
All times are in ms; lower is better. Delta is demo time / main time − 1.
64d7a9482d6992Bounded ready paths
All times are in ns; lower is better. Delta is demo time / main time − 1.
64d7a9482d6992Reservation API
Main has no reservation API. Compare the borrowed-permit paths with Tokio using the same reservation benchmark harness.
Reproduce the new cases with the repository benchmark workflow, narrowed to the ecosystem harness: