From 5f4970cd3944d20d9d0af2766ac4c4994da45314 Mon Sep 17 00:00:00 2001 From: "shreyas@blacksmith.sh" Date: Mon, 2 Nov 2026 15:01:18 +0000 Subject: [PATCH 1/3] cache/disk: census counts an eviction as never-read from its access state, so boot-scanned entries stop inflating evicted_never_read after a restart Co-Authored-By: Devin AI <158243242+devin-ai-integration[bot]@users.noreply.github.com> --- cache/disk/census.go | 2 +- cache/disk/census_test.go | 8 ++++++++ 2 files changed, 9 insertions(+), 1 deletion(-) diff --git a/cache/disk/census.go b/cache/disk/census.go index 8ae274a..e23193e 100644 --- a/cache/disk/census.go +++ b/cache/disk/census.go @@ -425,7 +425,7 @@ func (r *censusRecorder) OnEvict(key string, value lruItem) { if now > value.addedAt { createdAge = now - value.addedAt } - neverRead := value.lastAccess == value.addedAt + neverRead := value.accessState == itemStateNew lastReadIdx := censusBucketIdx(lastReadAge) createdIdx := censusBucketIdx(createdAge) diff --git a/cache/disk/census_test.go b/cache/disk/census_test.go index 98a2e34..89b4f3d 100644 --- a/cache/disk/census_test.go +++ b/cache/disk/census_test.go @@ -409,6 +409,14 @@ func TestCensusBootScannedIsUnknownNotNeverRead(t *testing.T) { if rows[0].EvictedNeverReadBytesByClass[class] != 0 { t.Errorf("EvictedNeverReadBytesByClass = %d, want 0", rows[0].EvictedNeverReadBytesByClass[class]) } + // The scalar and its counters follow the same access state: a boot-scanned + // entry has addedAt == lastAccess, which must not read as never-read. + if rows[0].EvictedNeverReadBytes != 0 || rows[0].EvictedBytes != 50 { + t.Errorf("EvictedNeverReadBytes/EvictedBytes = %d/%d, want 0/50", rows[0].EvictedNeverReadBytes, rows[0].EvictedBytes) + } + if got := testutil.ToFloat64(rec.evictedNeverReadEntries.WithLabelValues("unknown")); got != 0 { + t.Errorf("evictedNeverReadEntries = %v, want 0", got) + } if rows[0].ResidentUnknownBytesByClass[class] != 0 || rows[0].ResidentBytesByClass[class] != 50 { t.Errorf("resident unknown/total = %d/%d, want 0/50", rows[0].ResidentUnknownBytesByClass[class], rows[0].ResidentBytesByClass[class]) From 7d9ab6ea8efdb01fdfa2d6f54d7bbb99f9d75722 Mon Sep 17 00:00:00 2001 From: "shreyas@blacksmith.sh" Date: Mon, 2 Nov 2026 15:08:11 +0000 Subject: [PATCH 2/3] cache/disk: boot-scanned evictions carry no last-read history either Co-Authored-By: Devin AI <158243242+devin-ai-integration[bot]@users.noreply.github.com> --- cache/disk/census.go | 7 +++++-- cache/disk/census_test.go | 9 +++++++++ 2 files changed, 14 insertions(+), 2 deletions(-) diff --git a/cache/disk/census.go b/cache/disk/census.go index e23193e..61b20ab 100644 --- a/cache/disk/census.go +++ b/cache/disk/census.go @@ -436,13 +436,16 @@ func (r *censusRecorder) OnEvict(key string, value lruItem) { acc.residentEntries-- acc.evictedBytes += value.sizeOnDisk acc.evictedEntries++ - if neverRead { + switch value.accessState { + case itemStateNew: acc.evictedNeverReadByes += value.sizeOnDisk - } else { + case itemStateTouched: if lastReadAge < censusLiveThreshold { acc.evictedLiveBytes += value.sizeOnDisk } acc.evictedByLastReadAge[lastReadIdx] += value.sizeOnDisk + // itemStateBootScanned: lastAccess is file atime (frozen at creation on + // noatime mounts), not a read, so the entry has no last-read history. } acc.evictedByCreatedAge[createdIdx] += value.sizeOnDisk acc.removeResident(class, value.sizeOnDisk, value.accessState) diff --git a/cache/disk/census_test.go b/cache/disk/census_test.go index 89b4f3d..cd649f4 100644 --- a/cache/disk/census_test.go +++ b/cache/disk/census_test.go @@ -417,6 +417,15 @@ func TestCensusBootScannedIsUnknownNotNeverRead(t *testing.T) { if got := testutil.ToFloat64(rec.evictedNeverReadEntries.WithLabelValues("unknown")); got != 0 { t.Errorf("evictedNeverReadEntries = %v, want 0", got) } + // Nor as read: its lastAccess is file atime, not a hit. + if rows[0].EvictedLiveBytes != 0 { + t.Errorf("EvictedLiveBytes = %d, want 0", rows[0].EvictedLiveBytes) + } + for i, v := range rows[0].EvictedByLastReadAge { + if v != 0 { + t.Errorf("EvictedByLastReadAge[%d] = %d, want 0", i, v) + } + } if rows[0].ResidentUnknownBytesByClass[class] != 0 || rows[0].ResidentBytesByClass[class] != 50 { t.Errorf("resident unknown/total = %d/%d, want 0/50", rows[0].ResidentUnknownBytesByClass[class], rows[0].ResidentBytesByClass[class]) From 181fdc4295ca70dc8abb5463fd10383861c725eb Mon Sep 17 00:00:00 2001 From: "shreyas@blacksmith.sh" Date: Mon, 2 Nov 2026 15:10:40 +0000 Subject: [PATCH 3/3] cache/disk: evicted last_read counters follow the access state too Co-Authored-By: Devin AI <158243242+devin-ai-integration[bot]@users.noreply.github.com> --- cache/disk/census.go | 16 +++++++--------- cache/disk/census_test.go | 5 +++++ 2 files changed, 12 insertions(+), 9 deletions(-) diff --git a/cache/disk/census.go b/cache/disk/census.go index 61b20ab..746605f 100644 --- a/cache/disk/census.go +++ b/cache/disk/census.go @@ -425,7 +425,6 @@ func (r *censusRecorder) OnEvict(key string, value lruItem) { if now > value.addedAt { createdAge = now - value.addedAt } - neverRead := value.accessState == itemStateNew lastReadIdx := censusBucketIdx(lastReadAge) createdIdx := censusBucketIdx(createdAge) @@ -455,16 +454,15 @@ func (r *censusRecorder) OnEvict(key string, value lruItem) { r.mu.Unlock() sz := float64(value.sizeOnDisk) - // Never-read entries have no last read: they are counted in the - // never-read counter and the created-age buckets only, so the - // last_read series stays a pure harm signal (bytes someone actually - // used, evicted anyway). This also gives thrash alerts built-in - // restart tolerance: boot-scanned entries look never-read until first - // touched, so a roll cannot fabricate still-live evictions. - if neverRead { + // Only touched entries have a last read, so the last_read series stays + // a pure harm signal (bytes someone actually used, evicted anyway) and + // a roll cannot fabricate still-live evictions out of boot-scanned + // entries; those count in the created-age buckets only. + switch value.accessState { + case itemStateNew: r.evictedNeverReadBytes.WithLabelValues(tool).Add(sz) r.evictedNeverReadEntries.WithLabelValues(tool).Inc() - } else { + case itemStateTouched: r.evictedBytesByAge.WithLabelValues("last_read", censusBucketLabels[lastReadIdx], tool).Add(sz) r.evictedEntriesByAge.WithLabelValues("last_read", censusBucketLabels[lastReadIdx], tool).Inc() } diff --git a/cache/disk/census_test.go b/cache/disk/census_test.go index cd649f4..5743507 100644 --- a/cache/disk/census_test.go +++ b/cache/disk/census_test.go @@ -426,6 +426,11 @@ func TestCensusBootScannedIsUnknownNotNeverRead(t *testing.T) { t.Errorf("EvictedByLastReadAge[%d] = %d, want 0", i, v) } } + for _, label := range censusBucketLabels { + if got := testutil.ToFloat64(rec.evictedEntriesByAge.WithLabelValues("last_read", label, "unknown")); got != 0 { + t.Errorf("evictedEntriesByAge last_read %s = %v, want 0", label, got) + } + } if rows[0].ResidentUnknownBytesByClass[class] != 0 || rows[0].ResidentBytesByClass[class] != 50 { t.Errorf("resident unknown/total = %d/%d, want 0/50", rows[0].ResidentUnknownBytesByClass[class], rows[0].ResidentBytesByClass[class])