feat(core): add HTTP/2 flow-controlled bodies

This commit is contained in:
Zakaria El Orche
2026-08-13 19:00:19 +00:00
parent c96d51f7ea
commit 8d5340a0b4
21 changed files with 1679 additions and 101 deletions
+30
View File
@@ -951,3 +951,33 @@ the lifecycle benchmark remains at the allocation noise floor.
advertised limit or reader size from measurements; do not add a sleep-based dispatch delay.
---
## DEC-28 — Align the receive window with a coalescing bounded DATA pool
**Context.** The demultiplexer cannot block waiting for an application handler, but delaying
WINDOW_UPDATE only provides backpressure after the peer has spent the window it already owns. A
pool smaller than that outstanding credit can be exhausted legitimately. Allocating one buffer per
DATA frame is also unsafe because many tiny or heavily padded frames can consume little payload
storage while exhausting an object-per-frame pool.
**Decision.** Advertise 1 MiB at both the connection and stream receive levels and back the
connection with exactly 64 reusable 16 KiB buffers (also 1 MiB). Adjacent DATA payloads coalesce
into available tail space; padding contributes to flow credit but not storage. WINDOW_UPDATE is
sent at half-window consumption, never merely on receipt. Bodies at or below 64 KiB with a known
length use one reusable contiguous stream buffer and dispatch at END_STREAM; all other bodies
dispatch immediately onto the same protocol-neutral `RequestBody` over a blocking pooled source.
Response DATA uses the same serialized writer with a progress cursor. A stream object itself is
the executor task for initial handling and resumptions, so no per-resume closure is created.
WINDOW_UPDATE only schedules work; it never reads an application `InputStream` on the demux thread.
**Consequence.** Outstanding peer credit and worst-case pooled payload storage match exactly,
small frames do not multiply objects, slow consumers withhold credit naturally, and streaming
responses resume without recursive writer completion or demux blocking. The 100 MiB bidirectional
integration test remains bounded, while JMH measures the streaming request and response paths at
the allocation noise floor.
**Revisit when.** Production memory/throughput measurements justify a different window. Change the
window and pool byte capacity together; never raise credit independently of bounded storage.
---