pool only.Expand description
Prototype buffer pool for dataflow state. See
doc/developer/design/20260610_buffer_managed_state.md.
The pool is the cache: size-class anonymous virtual-memory regions whose
slots hold resident chunks. Slots are scoped to residency — eviction
returns a chunk’s slot to the free list along with its physical pages —
so slot demand tracks the resident set (bounded by the budget), not the
potentially unbounded live backlog. Reads are copy-out
(ChunkHandle::read_into): a resident slot is copied and an evicted
extent decompressed straight into the caller’s buffer, all under the
chunk’s state lock, so no reference into pool memory escapes the pool and
a read leaves residency untouched. The backing is the swap-backed extent
store of the design’s Layer 1: a slot in a pool-owned anonymous-memory
extent arena holding the chunk’s lz4-compressed bytes.
Memory descends a ladder of tiers, each with its own ceiling and each cheaper to vacate than the one above:
- Slots (uncompressed, free reads) — bounded by the budget; crossing it compresses the oldest chunks into extents and releases their slots.
- Warm free slots (pages kept for fault-free reuse) — bounded by the warm cap.
- Compressed-resident extents (reads decompress, no device) — bounded
by the headroom the RSS target leaves above the first two; crossing it
pushes the oldest extents to the swap device with
MADV_PAGEOUT. - The swap device — overflow; reads fault and decompress.
The identity total pool RSS <= budget + warm cap + compressed cap,
where compressed cap = max(0, rss_target - budget - warm cap), makes
every resident byte’s ceiling nameable. A zero RSS target (or one below
the budget plus warm cap) collapses the compressed tier and extents page
out as soon as they are written. Heap-backed chunks (oversize payloads
and class-exhaustion fallbacks) sit outside the identity: they can never
be evicted, so the budget is enforced against evictable bytes only.
Slots never reach the swap device: only compressed extents are offered
to it. Pageout is observed rather than assumed: an extent counts against
the compressed tier until the page table shows its whole range unmapped,
so reclaim the kernel declines surfaces as extent_pageout_incomplete
(and a tier settled above its capacity) instead of as RSS the ledger
cannot see.
Residency is a state, not a type. It descends through eviction and
ascends through exactly one transition: an admitting read
(ChunkHandle::read_into_admit) lifts an evicted chunk back to
BackedResident when a slot is free within the budget or stealable from
a clean backed victim of the same class, never by evicting or
compressing anything. Plain reads (ChunkHandle::read_into) leave
residency untouched. Eviction I/O runs on spill threads when enabled —
WriteInFlight marks a chunk whose compression a spill thread owns — and
inline on the evicting caller otherwise. Chunks are immutable after
Pool::insert_with, which is what makes a BackedResident slot always
identical to its extent and its eviction free of I/O.
Freeing an UnbackedResident chunk is a pure memory operation — the
design’s “never write dead data” win, surfaced as writes_elided in
PoolStats. Budget pressure evicts cold chunks via second-chance
FIFOs banded by the caller-supplied generational depth (ChunkHints):
eviction and eager backing both visit deeper (colder) bands first, so
the youngest data keeps its die-before-write chance longest. Within a
band the FIFO is the design’s backstop policy, and unannotated chunks
(depth 0) get exactly that.
Structs§
- Chunk
Handle - Handle to one immutable chunk in a
Pool. Dropping the handle frees the chunk: the slot (if resident) returns to the region free list with its physical pages released, and the extent (if any) is deallocated, discarding any swapped copy for free. Releasing the pages keeps RSS aligned with theresident_bytesgauge the budget enforcer trusts; without it, freed slots would hold warm pages the enforcer cannot see. - Chunk
Hints - Advisory placement hints for a chunk, supplied at insert and immutable thereafter (merges mint new chunks, so a chunk’s generation never changes). Hints steer policy — eviction order and write-behind candidacy — never correctness: a mislabeled chunk performs worse, while the budget and residency invariants hold regardless.
- Pool
- A buffer pool over swap-backed extents. Cheap to clone; all clones share one budget and one backing store.
- Pool
Stats - Snapshot of pool counters.
Traits§
- Extent
Codec - A chunk-provided transform between a chunk’s body bytes and the stored
bytes its extent holds. The pool owns scheduling: spill threads, the
residency state machine, cancellation, and the ledger. It invokes the
codec on opaque bytes at the extent boundary,
encodewhen backing a chunk (on a spill thread, or inline under overload) anddecodewhen reading an evicted one, under the chunk’s state lock. The pool itself has no opinion on the stored form: framing, compression, and validation all belong to the codec.
Functions§
- max_
stored_ len - The largest stored form
ExtentCodec::encodemay produce for abody_len-byte body: an incompressible-input expansion matching lz4’s worst case plus a four-byte length prefix. The extent store’s size-class ladder is provisioned to this bound, so a codec that exceeds it can strand payloads with no class to hold them (they degrade to unpageable heap fallbacks).