Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
23 changes: 12 additions & 11 deletions cache/disk/census.go
Original file line number Diff line number Diff line change
Expand Up @@ -425,7 +425,6 @@ func (r *censusRecorder) OnEvict(key string, value lruItem) {
if now > value.addedAt {
createdAge = now - value.addedAt
}
neverRead := value.lastAccess == value.addedAt
lastReadIdx := censusBucketIdx(lastReadAge)
createdIdx := censusBucketIdx(createdAge)

Expand All @@ -436,13 +435,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)
Expand All @@ -452,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()
}
Expand Down
22 changes: 22 additions & 0 deletions cache/disk/census_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -409,6 +409,28 @@ 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)
}
// 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)
}
}
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])
Expand Down
Loading