perf(oci): single debounced background evictor instead of one spawned task per blob (PSA-39) #7
Loading…
Add table
Add a link
Reference in a new issue
No description provided.
Delete branch "feat/psa-39-single-debounced-evictor"
Deleting a branch is permanent. Although the deleted branch may continue to exist for a short time before it actually gets removed, it CANNOT be undone in most cases. Continue?
Problem
dunite-oci's blob cache spawned a detached LRU eviction task on every blob store (
tokio::spawn(evict_if_over_cap)). Under adocker pull(one store per blob, several blobs concurrent) this fired N eviction tasks in seconds, each needing its own DB connection. Against a bounded pool the tasks lost the acquire race and failed with PoolTimedOut, so the byte cap stopped being enforced while pulls were active (root-caused in bunyip BUNYIP-41; bunyip mitigated consumer-side with a dedicated pool, but the per-blob spawn pattern is the structural cause and belongs here).Change
One long-lived background evictor task, spawned by
BlobCache::new. It owns at most one connection and is poked through a capacity-1mpscchannel: a burst of concurrent stores collapses to one pending notification (extra pokes dropped viatry_send), so the cap is enforced with one eviction pass per burst rather than one task (one connection) per blob. The task holds only the eviction essentials (store, cache_dir, max_bytes), never a sender, so it exits cleanly once everyBlobCacheclone drops and the channel closes. The eviction loop moved to a freeevict_over_capfn shared by the task and the publicevict_if_over_capmethod (kept for blocking/startup passes).newmust now run inside a Tokio runtime (ittokio::spawns the evictor); documented onnewand the module.Why convergence still holds
A poke is dropped only while another poke is already queued, and that queued poke is consumed after the current store committed, so at least one eviction pass always observes the full post-burst total. Totals only grow until eviction runs, so the final pass drives the cache under the cap.
Acceptance criteria
Tests
burst_of_concurrent_stores_coalesces_into_few_eviction_passes_and_converges: fires N=8 concurrent stores over a cap of 250, asserts the cache converges under the cap AND that eviction passes (counted via the test store'stotal_size_bytescalls) is well under N. fmt + clippy -D warnings clean; fullcargo test -p dunite-ocigreen; burst test verified non-flaky across 20 runs.Follow-up (not in this PR)
dunite-download's
download_cachehas the same per-storetokio::spawn(evict_if_over_cap)pattern. Not exercised by a fan-out pull the way OCI is, but worth the same treatment for cross-vertical consistency, ideally as a shared dunite-core debounced-evictor primitive. Suggest a separate issue.#PSA-39