Migrated from Method backlog
This issue was created from a legacy filesystem backlog card. GitHub Issues are now the live work tracker; repository docs remain Method evidence.
Source backlog: docs/method/backlog/cool-ideas/PLATFORM_deep-storage-gc-sweep-eviction.md
Original lane: cool-ideas
Original legend: PLATFORM
Original backlog card
Milestone: Deep Storage | Priority: P2
Status: active cool idea. crates/echo-cas currently has synchronous
BlobStore and in-memory MemoryTier only; no DiskTier, TieredStore,
listing/metadata API, deletion path, GcSweep, EvictionPolicy, or
GcRunner exists yet. This remains operational as the GC follow-up after
disk tier and enumeration support land.
GC Sweep & Eviction
Pin/unpin lifecycle management with mark-sweep reachability and eviction policies for managing blob lifetime.
T-5-2-1: Mark-sweep reachability analysis
User Story: As a developer, I want the CAS to identify unreachable blobs so that disk space can be reclaimed.
Requirements:
- R1:
GcSweep::mark(roots: &[BlobHash]) traverses from pinned roots and marks all reachable blobs.
- R2: Reachability follows blob references embedded in a configurable
RefExtractor trait: fn extract_refs(blob: &[u8]) -> Vec<BlobHash>.
- R3:
GcSweep::sweep() returns the set of hashes that are stored but not marked (garbage).
- R4: Sweep does NOT delete -- it returns candidates. Deletion is a separate explicit step.
Acceptance Criteria:
Definition of Done:
Scope: Mark-sweep algorithm, RefExtractor trait, sweep candidate collection.
Out of Scope: Actual deletion/eviction (T-5-2-2). Incremental/generational GC. Concurrent marking.
Test Plan:
- Goldens: N/A (set-based output, order-independent).
- Failures: RefExtractor returns a hash that does not exist in the store (treated as already collected, not an error).
- Edges: Cycle: A -> B -> A (both reachable if either is pinned). Blob that references itself. 0-ref blob that is pinned (reachable).
- Fuzz/Stress: Property test: for any random DAG of blobs, sweep set + reachable set = full store set.
Blocked By: T-5-1-1
Blocking: T-5-2-2
Est. Hours: 5h
Expected Complexity: ~200 LoC
T-5-2-2: Eviction policy and background sweep task
User Story: As an operator, I want the CAS to automatically evict cold unpinned blobs so that memory and disk usage stay bounded.
Requirements:
- R1:
EvictionPolicy enum: Lru, SizeBased(max_bytes), AgeBased(max_age).
- R2:
GcRunner struct accepts a TieredStore + EvictionPolicy + RefExtractor.
- R3:
GcRunner::run_sweep() performs mark, sweep, then evicts candidates according to the policy (demote from memory, or delete from disk for AgeBased/SizeBased).
- R4:
GcRunner can be driven manually (run_sweep()) or spawned as a background tokio::task with a configurable interval.
- R5: Eviction never removes pinned blobs regardless of policy.
Acceptance Criteria:
Definition of Done:
Scope: Eviction policies, GcRunner, background sweep, metrics.
Out of Scope: Distributed GC coordination. Multi-process locking on DiskTier. Custom policy plugins.
Test Plan:
- Goldens: N/A (behavioral).
- Failures: Sweep with no garbage (returns zero evictions). Sweep when all blobs are pinned (zero evictions).
- Edges: Exactly at budget boundary. Single blob store. Policy switch between sweeps.
- Fuzz/Stress: Concurrent puts during sweep (sweep must not cause data races or double-free).
Blocked By: T-5-2-1, T-5-1-2
Blocking: none
Est. Hours: 6h
Expected Complexity: ~300 LoC
Migrated from Method backlog
This issue was created from a legacy filesystem backlog card. GitHub Issues are now the live work tracker; repository docs remain Method evidence.
Source backlog:
docs/method/backlog/cool-ideas/PLATFORM_deep-storage-gc-sweep-eviction.mdOriginal lane:
cool-ideasOriginal legend:
PLATFORMOriginal backlog card
GC Sweep & Eviction
Pin/unpin lifecycle management with mark-sweep reachability and eviction policies for managing blob lifetime.
T-5-2-1: Mark-sweep reachability analysis
User Story: As a developer, I want the CAS to identify unreachable blobs so that disk space can be reclaimed.
Requirements:
GcSweep::mark(roots: &[BlobHash])traverses from pinned roots and marks all reachable blobs.RefExtractortrait:fn extract_refs(blob: &[u8]) -> Vec<BlobHash>.GcSweep::sweep()returns the set of hashes that are stored but not marked (garbage).Acceptance Criteria:
sweep()on an empty store returns an empty set.Definition of Done:
Scope: Mark-sweep algorithm, RefExtractor trait, sweep candidate collection.
Out of Scope: Actual deletion/eviction (T-5-2-2). Incremental/generational GC. Concurrent marking.
Test Plan:
Blocked By: T-5-1-1
Blocking: T-5-2-2
Est. Hours: 5h
Expected Complexity: ~200 LoC
T-5-2-2: Eviction policy and background sweep task
User Story: As an operator, I want the CAS to automatically evict cold unpinned blobs so that memory and disk usage stay bounded.
Requirements:
EvictionPolicyenum:Lru,SizeBased(max_bytes),AgeBased(max_age).GcRunnerstruct accepts aTieredStore+EvictionPolicy+RefExtractor.GcRunner::run_sweep()performs mark, sweep, then evicts candidates according to the policy (demote from memory, or delete from disk forAgeBased/SizeBased).GcRunnercan be driven manually (run_sweep()) or spawned as a backgroundtokio::taskwith a configurable interval.Acceptance Criteria:
run_sweep()withSizeBased(1024), total stored bytes are at or below 1024 (unpinned blobs evicted by LRU within the size policy).Definition of Done:
Scope: Eviction policies, GcRunner, background sweep, metrics.
Out of Scope: Distributed GC coordination. Multi-process locking on DiskTier. Custom policy plugins.
Test Plan:
Blocked By: T-5-2-1, T-5-1-2
Blocking: none
Est. Hours: 6h
Expected Complexity: ~300 LoC