Disk cache: evict before writing, reset the disk reading when the folder changes (#2551)

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
This commit is contained in:
arnav-hiwarkar
2026-10-28 21:55:33 +05:30
co-authored by Claude Opus 5.5
parent 8af5f54c92
commit 52dda004a5
2 changed files with 16 additions and 4 deletions
@@ -119,6 +119,7 @@ impl Session {
// (no file system in the browser: the disk cache stays off there)
let Some(folder) = folder.filter(|_| d.disk_cache_enabled && !cfg!(target_arch = "wasm32")) else {
self.disk_cache = None;
self.disk_watch = Default::default();
self.layer_cache.set_disk(None);
return;
};
@@ -132,11 +133,17 @@ impl Session {
c.set_max_bytes(max);
c.clone()
}
// A new folder: the free-space reading was for the old one (a reader still running
// holds the old watcher's state, so it can't write into the new one).
_ => match DiskCache::open(&folder, max) {
Ok(c) => c,
Ok(c) => {
self.disk_watch = Default::default();
c
}
Err(e) => {
log::warn!("disk cache at {}: {e}", folder.display());
self.disk_cache = None;
self.disk_watch = Default::default();
self.layer_cache.set_disk(None);
return;
}
+8 -3
View File
@@ -547,6 +547,8 @@ impl DiskCache {
if data.len() as u64 > self.limit_bytes() {
return;
}
// Make room first, so the cache never exceeds its limit (or the free-space reserve).
self.evict_to(self.limit_bytes().saturating_sub(data.len() as u64));
let n = self.tmp_counter.fetch_add(1, Ordering::Relaxed);
let tmp = parent.join(format!("{key:032x}.tmp.{}.{n}", std::process::id()));
if let Err(e) = std::fs::write(&tmp, &data).and_then(|()| std::fs::rename(&tmp, &path)) {
@@ -558,7 +560,6 @@ impl DiskCache {
if let Ok(mut g) = self.index.lock() {
g.insert(kind, key, data.len() as u64);
}
self.evict();
}
/// Count a failed write; the first one is logged (a full disk shouldn't go unnoticed).
@@ -570,7 +571,11 @@ impl DiskCache {
/// Remove least recently used entries until the cache fits its limit.
fn evict(&self) {
let max = self.limit_bytes();
self.evict_to(self.limit_bytes());
}
/// Remove least recently used entries until the cache fits `max` bytes.
fn evict_to(&self, max: u64) {
let victims = match self.index.lock() {
Ok(mut g) => g.evict(max),
Err(_) => return,
@@ -1134,7 +1139,7 @@ mod tests {
assert_eq!((st.max_bytes, st.limit_bytes), (1 << 30, used));
dc.put_layer_now(9, &buf(9, 64, 64));
let st = dc.stats();
assert!(st.bytes <= used - used / 10 && st.evictions > 0, "{st:?}");
assert!(st.bytes <= st.limit_bytes && st.bytes <= used - used / 10 && st.evictions > 0, "{st:?}");
assert!(dc.contains(Kind::Layer, 9), "the new entry is the most recently used");
// Below the reserve the cache gives its space back, and skips writes that can't fit.
dc.set_disk_space(Some((100 << 30, 4 << 30)));