Expand description
Bounded Blob Cache sweeper — admin maintenance for L1 expirations and L2 orphan-chain reclamation.
§Issue #148 — Blob Cache admin maintenance
This module provides the bounded sweeper primitives that admin endpoints, the runtime maintenance scheduler, and the backup hook will call into. The actual HTTP wiring, runtime schedule, and backup integration are tracked as follow-up orchestrator-batch edits (see “FLAGGED HOOKUPS” at the bottom of this file).
§Public surface
BlobCacheSweeper::sweep_expired— bounded sweep of expired L1 entries.BlobCacheSweeper::reclaim_orphans— bounded reclamation of L2 blob chains left behind by an interrupted write (process killed between blob bytes flush and metadata commit — seedocs/perf/blob-cache-l2-spike.md§“crash-recovery”).BlobCacheSweeper::flush_namespace— foreground-fast namespace flush. O(1): bumps the per-namespace generation counter; physical reclamation happens lazily on next access or viaBlobCacheSweeper::sweep_expired.
§Bounding
All three operations are bounded by SweepLimit:
Entries(N)— hard cap on the number of entries scanned.Millis(N)— hard cap on wall-clock time. Checked at every iteration so the cap is honored within a few microseconds of overrun.Either { entries, millis }— first cap to fire wins.
When a sweep terminates because it hit a limit (instead of running to
completion) the report’s truncated_due_to_limit flag is set so admin
callers can decide whether to schedule a follow-up sweep.
§Concurrency contract
All three operations are safe to call while concurrent readers
(BlobCache::get, BlobCache::exists) and writers
(BlobCache::put) are in flight:
- The sweeper only uses
BlobCache’s public,&selfAPI (invalidate_key,invalidate_namespace,stats). Those methods take shard-level locks for the briefest possible critical sections; readers touching other shards are never blocked. flush_namespaceonly bumps a generation counter under a brief write-lock. Concurrent reads against the same namespace either see the old generation (returning a hit if the entry is still alive) or the new generation (treating any cached entry as stale). Either is correct.sweep_expiredandreclaim_orphanscooperate with normal traffic by bounding their per-call work and yielding back to the caller. They never hold a global lock across the entire sweep.
The concurrent_reads_never_block_during_sweep property test below
verifies the contract empirically: 8 reader threads + 1 sweeper thread,
readers must complete within a tight time budget.
§FLAGGED HOOKUPS (orchestrator-batch — not landed by this file)
Marked // FLAG: throughout; collected here for the orchestrator:
-
mod.rsregistration —pub mod sweeper;line incrates/reddb-server/src/storage/cache/mod.rs, plus apub use sweeper::{BlobCacheSweeper, SweepLimit, SweepReport, OrphanReport, NamespaceFlushReport, NamespaceSweepStats};re-export so callers can reach the type without the long path. -
BlobCacheaccessor extensions — to walk L1 entries and L2 records the sweeper needs read-only iterators onBlobCache. Today neither surface exists, sosweep_expiredandreclaim_orphansare bounded scaffolding that report zero work until those accessors land. Required additions (incache/blob/cache.rs):ⓘpub fn for_each_l1_entry<F>(&self, visit: F) where F: FnMut(&str /*namespace*/, &str /*key*/, L1EntryView<'_>); pub fn for_each_l2_record<F>(&self, visit: F) where F: FnMut(L2RecordView<'_>); pub fn l2_orphan_chains(&self) -> impl Iterator<Item = u32 /*root_page*/>;The
L1EntryViewprojection should exposeexpires_at_unix_ms,namespace_generation, andsize. TheL2RecordViewshould exposenamespace,key,root_page,byte_len. With those, the bodies ofsweep_expiredandreclaim_orphansbecome straightforward (sketches inline below). -
Backup integration —
runtime/backup.rs(or the equivalent backup-orchestrator module) needs aninclude_blob_cache: boolflag and matching dump/restore round-trip for the L2 metadata B+ tree and blob chains. The sweeper plays no part in backup itself, but the spec indocs/adr/0006-tiered-blob-cache.mdties them together: a backup triggered while a sweep is in flight must observe a consistent L2 snapshot. -
Admin HTTP handler —
POST /admin/blob_cache/sweepandPOST /admin/blob_cache/flush_namespaceendpoints (likely undercrates/reddb-server/src/http/admin/), parsing a JSON body matchingSweepLimit/ namespace name and returning the report struct as JSON. Both stay flagged for follow-up per the issue. -
Runtime config knob — default
SweepLimitfor background-scheduled sweeps + asweep_on_startup: booloption in the server config struct. The runtime scheduler then callsBlobCacheSweeper::sweep_expiredperiodically.
Structs§
- Blob
Cache Sweeper - Stateless namespace for sweeper operations against a
BlobCache. - Namespace
Flush Report - Outcome of
BlobCacheSweeper::flush_namespace. - Namespace
Sweep Stats - Per-namespace breakdown of a
SweepReport. - Orphan
Report - Outcome of
BlobCacheSweeper::reclaim_orphans. - Sweep
Report - Outcome of
BlobCacheSweeper::sweep_expired.
Enums§
- Sweep
Limit - Bound for a single sweeper invocation.