common/lru: remove callbacks

It's best to avoid callbacks, especially in the locked variant of the LRU, since it
can lead to weird bugs.
This commit is contained in:
Felix Lange 2025-05-12 19:16:26 +02:00 committed by lightclient
parent 2e99333809
commit f65f948b43
No known key found for this signature in database
GPG key ID: 657913021EF45A6A
2 changed files with 14 additions and 42 deletions

View file

@ -22,11 +22,9 @@ package lru
// This type is not safe for concurrent use. // This type is not safe for concurrent use.
// The zero value is not valid, instances must be created using NewCache. // The zero value is not valid, instances must be created using NewCache.
type BasicLRU[K comparable, V any] struct { type BasicLRU[K comparable, V any] struct {
list *list[K] list *list[K]
items map[K]cacheItem[K, V] items map[K]cacheItem[K, V]
cap int cap int
onEvicted func(key K, value V)
onReplaced func(key K, value V)
} }
type cacheItem[K any, V any] struct { type cacheItem[K any, V any] struct {
@ -49,27 +47,27 @@ func NewBasicLRU[K comparable, V any](capacity int) BasicLRU[K, V] {
// Add adds a value to the cache. Returns true if an item was evicted to store the new item. // Add adds a value to the cache. Returns true if an item was evicted to store the new item.
func (c *BasicLRU[K, V]) Add(key K, value V) (evicted bool) { func (c *BasicLRU[K, V]) Add(key K, value V) (evicted bool) {
_, _, evicted = c.Add3(key, value)
return evicted
}
// Add3 adds a value to the cache. If an item was evicted to store the new one, it returns the evicted item.
func (c *BasicLRU[K, V]) Add3(key K, value V) (evKey K, evItem V, evicted bool) {
item, ok := c.items[key] item, ok := c.items[key]
if ok { if ok {
// Already exists in cache.
if c.onReplaced != nil {
c.onReplaced(key, item.value)
}
item.value = value item.value = value
c.items[key] = item c.items[key] = item
c.list.moveToFront(item.elem) c.list.moveToFront(item.elem)
return false return evKey, evItem, false
} }
var elem *listElem[K] var elem *listElem[K]
if c.Len() >= c.cap { if c.Len() >= c.cap {
elem = c.list.removeLast() elem = c.list.removeLast()
if c.onEvicted != nil {
v := c.items[elem.v]
c.onEvicted(elem.v, v.value)
}
delete(c.items, elem.v)
evicted = true evicted = true
evKey = elem.v
evItem = c.items[evKey].value
delete(c.items, evKey)
} else { } else {
elem = new(listElem[K]) elem = new(listElem[K])
} }
@ -79,7 +77,7 @@ func (c *BasicLRU[K, V]) Add(key K, value V) (evicted bool) {
elem.v = key elem.v = key
c.items[key] = cacheItem[K, V]{elem, value} c.items[key] = cacheItem[K, V]{elem, value}
c.list.pushElem(elem) c.list.pushElem(elem)
return evicted return evKey, evItem, evicted
} }
// Contains reports whether the given key exists in the cache. // Contains reports whether the given key exists in the cache.
@ -151,16 +149,6 @@ func (c *BasicLRU[K, V]) RemoveOldest() (key K, value V, ok bool) {
return key, item.value, true return key, item.value, true
} }
// OnEvicted sets a callback function to be called when an item is evicted from the cache.
func (c *BasicLRU[K, V]) OnEvicted(fn func(k K, v V)) {
c.onEvicted = fn
}
// OnReplaced sets a callback function to be called when an item is replaced in the cache.
func (c *BasicLRU[K, V]) OnReplaced(fn func(k K, v V)) {
c.onReplaced = fn
}
// Keys returns all keys in the cache. // Keys returns all keys in the cache.
func (c *BasicLRU[K, V]) Keys() []K { func (c *BasicLRU[K, V]) Keys() []K {
keys := make([]K, 0, len(c.items)) keys := make([]K, 0, len(c.items))

View file

@ -93,19 +93,3 @@ func (c *Cache[K, V]) Keys() []K {
return c.cache.Keys() return c.cache.Keys()
} }
// OnEvicted sets a callback function to be called when an item is evicted from the cache.
func (c *Cache[K, V]) OnEvicted(fn func(key K, value V)) {
c.mu.Lock()
defer c.mu.Unlock()
c.cache.OnEvicted(fn)
}
// OnReplaced sets a callback function to be called when an item is replaced in the cache.
func (c *Cache[K, V]) OnReplaced(fn func(key K, value V)) {
c.mu.Lock()
defer c.mu.Unlock()
c.cache.OnReplaced(fn)
}