lib/lrucache: sizeBytes should also include key length (#10679)

There are cases then the key sizeBytes is much greater than the value
sizeBytes. Therefore it is important to include the key sizeBytes into
the total.

Also fix some code comments.

Signed-off-by: Artem Fetishev <rtm@victoriametrics.com>
This commit is contained in:
Artem Fetishev
2026-03-24 12:54:31 +01:00
committed by GitHub
parent d21d9e8382
commit 95175e00b4
2 changed files with 16 additions and 9 deletions

View File

@@ -15,6 +15,10 @@ import (
// Cache caches Entry entries.
//
// If the cache is full the least recently used entries are evicted to make room
// for new entries. Additionally, entries are evicted if not retrieved within
// the last three minutes.
//
// Call NewCache() for creating new Cache.
type Cache struct {
resets atomic.Uint64
@@ -276,7 +280,7 @@ func (c *cache) PutEntry(k string, e Entry) {
}
heap.Push(&c.lah, ce)
c.m[k] = ce
c.updateSizeBytes(e.SizeBytes())
c.updateSizeBytes(uint64(len(k)) + e.SizeBytes())
maxSizeBytes := c.getMaxSizeBytes()
for c.SizeBytes() > maxSizeBytes && len(c.lah) > 0 {
c.removeLeastRecentlyAccessedItem()
@@ -285,7 +289,7 @@ func (c *cache) PutEntry(k string, e Entry) {
func (c *cache) removeLeastRecentlyAccessedItem() {
ce := c.lah[0]
c.updateSizeBytes(-ce.e.SizeBytes())
c.updateSizeBytes(-(uint64(len(ce.k)) + ce.e.SizeBytes()))
delete(c.m, ce.k)
heap.Pop(&c.lah)
}
@@ -341,7 +345,8 @@ func (lah *lastAccessHeap) Pop() any {
h := *lah
e := h[len(h)-1]
// Remove the reference to deleted entry, so Go GC could free up memory occupied by the deleted entry.
// Remove the reference to deleted entry, so Go GC could free up memory
// occupied by the deleted entry.
h[len(h)-1] = nil
*lah = h[:len(h)-1]

View File

@@ -31,14 +31,16 @@ func TestCache(t *testing.T) {
}
k := "foobar"
var e testEntry
keySize := uint64(len(k))
entrySize := e.SizeBytes()
keyEntrySize := keySize + entrySize
// Put a single entry into cache
c.PutEntry(k, &e)
if n := c.Len(); n != 1 {
t.Fatalf("unexpected number of items in the cache; got %d; want %d", n, 1)
}
if n := c.SizeBytes(); n != entrySize {
t.Fatalf("unexpected SizeBytes(); got %d; want %d", n, entrySize)
if n := c.SizeBytes(); n != keyEntrySize {
t.Fatalf("unexpected SizeBytes(); got %d; want %d", n, keyEntrySize)
}
if n := c.Requests(); n != 0 {
t.Fatalf("unexpected number of requests; got %d; want %d", n, 0)
@@ -77,8 +79,8 @@ func TestCache(t *testing.T) {
}
// Store the entry again.
c.PutEntry(k, &e)
if n := c.SizeBytes(); n != entrySize {
t.Fatalf("unexpected SizeBytes(); got %d; want %d", n, entrySize)
if n := c.SizeBytes(); n != keyEntrySize {
t.Fatalf("unexpected SizeBytes(); got %d; want %d", n, keyEntrySize)
}
if e1 := c.GetEntry(k); e1 != &e {
t.Fatalf("unexpected entry obtained; got %v; want %v", e1, &e)
@@ -95,8 +97,8 @@ func TestCache(t *testing.T) {
// Manually clean the cache. The entry shouldn't be deleted because it was recently accessed.
c.cleanByTimeout()
if n := c.SizeBytes(); n != entrySize {
t.Fatalf("unexpected SizeBytes(); got %d; want %d", n, entrySize)
if n := c.SizeBytes(); n != keyEntrySize {
t.Fatalf("unexpected SizeBytes(); got %d; want %d", n, keyEntrySize)
}
// Reset cache.