Bounded background write queue for the L2 (OPFS) tier.
The OPFS write (OPFSStore.set → createWritable/write/close, an atomic
temp-file swap per chunk) costs tens of ms and — measured on a true-cold
timelapse load — dominates the per-timepoint fetch critical path (~6× the
network fetch). OPFSStore.set already serializes writes per key, but has
no global cross-key cap, so firing every network miss's write inline (awaited)
blocks decode on disk, and firing them all un-awaited stampedes the single
OPFS backend (each write balloons under contention) and piles up unbounded.
This queue moves the write off the fetch critical path while keeping it
bounded: the caller enqueue()s and returns immediately; the queue drains
tasks at a fixed concurrency, coalesces repeat writes of the same key
(keeping the latest), and past maxDepth or maxBytes drops the ARRIVAL —
the entry that just overflowed — not the oldest pending one (L2 is a
best-effort persistence tier — L1 still serves the current session and the
next session simply re-fetches a dropped chunk).
Dropping the arrival rather than the oldest matters for what the next session
finds on disk. pump() takes from the same oldest end the drop loop used to
evict from, so drop-oldest kept discarding the entry the pump was about to
run and left a scattered remnant — chunks from all over the store, of which
no contiguous region is complete. Dropping the arrival lets the oldest end
drain in enqueue order, so what lands on disk is CONTIGUOUS RUNS from that
end (one prefix only while nothing drains; with the pump running, a run per
burst) — which is what a warm revisit can actually serve from. The tradeoff
is locality, not drop count: uniform-size writes drop equally under either
policy, while mixed sizes can favour either one. A large arrival no longer
displaces several small pending writes, but a large pending write can now
hold off several smaller arrivals.
Correctness is the caller's (MultiLevelCachingStore) responsibility: the
enqueued task must re-check staleness (disposed / dataAbort / epoch) at drain
time, because clear/dispose can now interleave between enqueue and drain.
Bounded background write queue for the L2 (OPFS) tier.
The OPFS write (
OPFSStore.set→createWritable/write/close, an atomic temp-file swap per chunk) costs tens of ms and — measured on a true-cold timelapse load — dominates the per-timepoint fetch critical path (~6× the network fetch).OPFSStore.setalready serializes writes per key, but has no global cross-key cap, so firing every network miss's write inline (awaited) blocks decode on disk, and firing them all un-awaited stampedes the single OPFS backend (each write balloons under contention) and piles up unbounded.This queue moves the write off the fetch critical path while keeping it bounded: the caller
enqueue()s and returns immediately; the queue drains tasks at a fixedconcurrency, coalesces repeat writes of the same key (keeping the latest), and pastmaxDepthormaxBytesdrops the ARRIVAL — the entry that just overflowed — not the oldest pending one (L2 is a best-effort persistence tier — L1 still serves the current session and the next session simply re-fetches a dropped chunk).Dropping the arrival rather than the oldest matters for what the next session finds on disk.
pump()takes from the same oldest end the drop loop used to evict from, so drop-oldest kept discarding the entry the pump was about to run and left a scattered remnant — chunks from all over the store, of which no contiguous region is complete. Dropping the arrival lets the oldest end drain in enqueue order, so what lands on disk is CONTIGUOUS RUNS from that end (one prefix only while nothing drains; with the pump running, a run per burst) — which is what a warm revisit can actually serve from. The tradeoff is locality, not drop count: uniform-size writes drop equally under either policy, while mixed sizes can favour either one. A large arrival no longer displaces several small pending writes, but a large pending write can now hold off several smaller arrivals.Correctness is the caller's (MultiLevelCachingStore) responsibility: the enqueued task must re-check staleness (disposed / dataAbort / epoch) at drain time, because clear/dispose can now interleave between enqueue and drain.