Skip to main content

Module pool

Module pool 

Source
Available on Unix and crate feature 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§

ChunkHandle
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 the resident_bytes gauge the budget enforcer trusts; without it, freed slots would hold warm pages the enforcer cannot see.
ChunkHints
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.
PoolStats
Snapshot of pool counters.

Traits§

ExtentCodec
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, encode when backing a chunk (on a spill thread, or inline under overload) and decode when 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::encode may produce for a body_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).