Expand description
Where the mux core gets memory, and the one way it is allowed to fail.
The core does not allocate for itself and does not name
crate::pool::Pool. Every buffer it needs — a connection’s stream-0
landing zone, a stream’s request/response pair, the HPACK scratch — comes
from a caller-supplied BufferSource, which the caller implements and
which may refuse. That is the whole contract, and both halves matter:
- Caller-supplied is what lets something other than the real pool stand behind it. A deterministic simulator that wants to drive the core into memory pressure has somewhere to stand, instead of having to arrange the pressure through a global allocator it does not control.
- May refuse is what keeps the existing behaviour expressible. Refusal
is not an error condition here. A source that answers
Nonemid-request is reporting a transient shortage, and the caller’s obligation is to degrade the smallest unit it can: one stream is refused withRST_STREAM(REFUSED_STREAM)and the connection carries on, because the streams already running will hand their buffers back. Escalating a shortage to a connection error would convert it into the loss of every in-flight request that would have survived it.
Neither half is new behaviour. Both checkout sites were already
Option-fallible with a REFUSED_STREAM-shaped fallback; what was missing
was a name for the thing being called, so the core reached for a concrete
Weak<RefCell<Pool>> instead. This module supplies the name and
PoolBufferSource supplies the one implementation the proxy itself uses,
which does exactly what the direct reach did.
§What is under the contract, and what is not
Under it: the connection’s own zero buffer, a stream’s request/response
buffer pair, and the HPACK codec pair together with the three reusable
scratch buffers beside them (see HpackState, hpack_state.rs).
Not under it, deliberately:
- Growth of the HPACK codec’s own buffers. The dynamic tables of the
crate::protocol::mux::hpackpair and the decoder’s Huffman scratch buffer start empty and grow to a high-water mark bounded by the RFC 7541 §4.2 table-size settings and the longest decoded string. They are brought under the contract at acquisition — the pair is built inside a fallibleHpackState::new— and their growth after acquisition reaches the global allocator, like a scratch buffer’s below. - Growth of an already-acquired scratch buffer.
scratchhands over an emptyVecthat the core then grows and reclaims on its own schedule. Pre-sizing one and refusing to grow it is a behaviour change — it needs an answer for what a header block larger than the reservation does — and is not made here. H2Scheduler’s pass-order buffer (h2_scheduler.rs). It holds stream ids rather than octets, and it is already bounded by the concurrent-stream admission gate that decides how many ids can exist.
Structs§
- Pool
Buffer Source - The
BufferSourcethe proxy itself runs on: the worker’s sharedPool, reached through the same weak handle the core used to hold directly.
Traits§
- Buffer
Source - The caller-supplied origin of every buffer the mux core uses.