Skip to content

Commit 9de7a63

Browse files
committed
refactor(vfs): single-pass LRU eviction in OverlayVfsRegistry
Replace the snapshot-Vec + two-filter approach with a single `min_by_key` pass. Tuple-sort `(non_idle_flag, ts)` so idle entries come first, with the smallest `ts` winning within each group — same "prefer oldest idle, fall back to globally oldest" semantics, no per-eviction allocation. (Addresses Gemini review suggestion.)
1 parent a4ad8fd commit 9de7a63

1 file changed

Lines changed: 9 additions & 13 deletions

File tree

crates/astrid-vfs/src/overlay_registry.rs

Lines changed: 9 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -266,21 +266,17 @@ impl OverlayVfsRegistry {
266266
let now_ms = self.now_ms();
267267
let idle_cutoff_ms = u64::try_from(self.idle_eviction.as_millis()).unwrap_or(u64::MAX);
268268
let cutoff_ms = now_ms.saturating_sub(idle_cutoff_ms);
269-
let snapshot: Vec<(PrincipalId, u64)> = guard
270-
.iter()
271-
.map(|(p, e)| (p.clone(), e.last_used_ms.load(Ordering::Relaxed)))
272-
.collect();
273-
let idle = snapshot
269+
270+
// Single pass. Tuple-sort `(non_idle_flag, ts)` so idle entries
271+
// (`ts <= cutoff_ms` → `false`) sort before non-idle ones, and
272+
// within each group the smallest `ts` wins — i.e. the oldest idle
273+
// entry is preferred, and if none are idle the globally oldest is
274+
// picked. Avoids the per-eviction snapshot `Vec` allocation.
275+
let victim = guard
274276
.iter()
275-
.filter(|(_, ts)| *ts <= cutoff_ms)
276-
.min_by_key(|(_, ts)| *ts)
277+
.map(|(p, e)| (p, e.last_used_ms.load(Ordering::Relaxed)))
278+
.min_by_key(|&(_, ts)| (ts > cutoff_ms, ts))
277279
.map(|(p, _)| p.clone());
278-
let victim = idle.or_else(|| {
279-
snapshot
280-
.iter()
281-
.min_by_key(|(_, ts)| *ts)
282-
.map(|(p, _)| p.clone())
283-
});
284280
if let Some(p) = victim {
285281
tracing::info!(principal = %p, "overlay registry at cap, evicting idle entry");
286282
guard.remove(&p);

0 commit comments

Comments
 (0)