Spill sink for eviction/demotion (write-behind, 2026-07-06).
spillOwned (preferred, NON-BLOCKING): the cache hands the sink an
entry it OWNS — zero-copy CLONES of the caches (made via the same
injectable cloner take() uses, BEFORE the donor is disposed; entries
are immutable so the clones stay consistent forever) plus a copy of
the tokens. The sink must dispose entry.caches when done, on BOTH
fulfill and reject paths (the server chains storeAsync -> dispose on
ssdWriteChain). A sink that throws SYNCHRONOUSLY has not taken
ownership — the cache disposes the clones and the spill degrades to
a no-op; eviction/demotion never unwinds.
spillSync (fallback): called with the LIVE entry about to be
disposed; must finish reading before returning. This is the old
contract — a full synchronous serialize+write under the generation
lock — kept for tests and simple embedders.
Spill sink for eviction/demotion (write-behind, 2026-07-06).
spillOwned(preferred, NON-BLOCKING): the cache hands the sink an entry it OWNS — zero-copy CLONES of the caches (made via the same injectable cloner take() uses, BEFORE the donor is disposed; entries are immutable so the clones stay consistent forever) plus a copy of the tokens. The sink must dispose entry.caches when done, on BOTH fulfill and reject paths (the server chains storeAsync -> dispose on ssdWriteChain). A sink that throws SYNCHRONOUSLY has not taken ownership — the cache disposes the clones and the spill degrades to a no-op; eviction/demotion never unwinds.spillSync(fallback): called with the LIVE entry about to be disposed; must finish reading before returning. This is the old contract — a full synchronous serialize+write under the generation lock — kept for tests and simple embedders.