Expand description
Per-namespace LRU eviction worker (RFC 0009).
Production-safety story: WombatKV’s block storage in S3 grows
unboundedly without a budget cap. This module periodically scans
the in-memory MetadataIndex, sums payload_bytes per namespace,
and when the sum exceeds the configured byte budget, evicts the
oldest entries (by last_access_ns) until the namespace fits
inside the budget with a 10% headroom.
§Env vars
WMBT_KV_NAMESPACE_MAX_BYTES=<N>, per-namespace byte budget.0(default) disables eviction entirely (safe default; existing deployments see no behavior change).100 GBis the suggested production setting; a single ds4 model footprint fits in well under that.WMBT_KV_DAEMON_EVICTION_INTERVAL_SECS=<N>, cycle interval, default 30 s.
§Race safety
The worker uses a compare-and-delete pattern against
InMemoryMetadataIndex::remove_if_unchanged: each eviction
candidate carries the last_access_ns snapshot taken at scoring
time. If a concurrent get_and_touch raced the worker between
snapshot and delete, the CAS fails and the worker silently skips
that entry this cycle (revisits next pass). This avoids holding a
cross-namespace tokio::sync::Mutex on the hot path: the eviction
cost is paid only by the worker thread, the request path pays
one extra BlockMeta comparison.
The CAS-failure path is observable in the per-cycle event as
skipped_changed. A persistently high count indicates either (a)
the namespace is genuinely hotter than the budget allows (raise
the budget) or (b) the eviction interval is too long and many
blocks are getting touched between scan and delete (shrink the
interval).
§What gets deleted, by tier
Per evicted entry the worker:
- Removes from
InMemoryMetadataIndex(CAS as above). - Removes from
SlateDbMetadataIndex(if opened by the caller). Best-effort: aSlateDBdelete failure logs+continues; the L0 state is already consistent. - Calls
EvictionDeleter::delete_block(namespace, key)which routes throughWombatKVKvStore::delete_kv: the object store delete + flat-tier unlink. Foyer is intentionally left to age out naturally (foyer::HybridCachedoes not expose a public single-key remove in our pinned version; the metadata index is the authoritative budget so this is correctness-safe).
Structs§
- Eviction
Cycle Outcome - Per-cycle outcome counts. Surfaced via the
[MyelonInstr]event emitted bydefault_emit. - LruConfig
- Tuning knobs for the LRU eviction worker.
- LruEviction
Worker - Owns a background thread that runs the eviction cycle.
Traits§
- Eviction
Deleter - Sync deleter surface implemented by
WombatKVKvStore<S>so the algorithm crate can call delete without depending on the embed crate’s genericS: ObjectStoreshape. Mirrors thePrefetchFetcherpattern inblock_prefetch.rs.
Functions§
- default_
emit - Default emit: a
[MyelonInstr]JSON line on stderr per cycle. - run_
cycle - Run one eviction cycle synchronously. Exposed for unit tests so the cycle can run inline (no thread orchestration).
- spawn_
worker - Spawn the eviction worker. The returned worker holds the join handle and signals stop on drop. Returns immediately; the loop runs on the spawned thread.
Type Aliases§
- Eviction
Emit - Closure-based callback for the per-cycle outcome event.