lru.go
⎇
Raw
1package service
2
3import (
4 "container/list"
5 "sync"
6)
7
8// lru is a fixed-size map keyed by path, dropping the least recently used entry
9// when it is full.
10//
11// Only use it for values that are safe to lose: an eviction means the work is
12// redone, never that correctness changes.
13type lru[V any] struct {
14 mu sync.Mutex
15 maxSize int
16 order *list.List // front is most recently used
17 entries map[string]*list.Element
18}
19
20type lruEntry[V any] struct {
21 key string
22 val V
23}
24
25func newLRU[V any](maxSize int) *lru[V] {
26 // A size below 1 would evict each entry as it is stored, turning the cache
27 // into a silent miss on every lookup.
28 return &lru[V]{
29 maxSize: max(maxSize, 1),
30 order: list.New(),
31 entries: make(map[string]*list.Element),
32 }
33}
34
35func (c *lru[V]) Get(key string) (V, bool) {
36 c.mu.Lock()
37 defer c.mu.Unlock()
38
39 el, ok := c.entries[key]
40 if !ok {
41 var zero V
42 return zero, false
43 }
44 c.order.MoveToFront(el)
45 return el.Value.(*lruEntry[V]).val, true
46}
47
48func (c *lru[V]) Put(key string, val V) {
49 c.mu.Lock()
50 defer c.mu.Unlock()
51
52 if el, ok := c.entries[key]; ok {
53 el.Value.(*lruEntry[V]).val = val
54 c.order.MoveToFront(el)
55 return
56 }
57
58 c.entries[key] = c.order.PushFront(&lruEntry[V]{key: key, val: val})
59
60 if c.order.Len() > c.maxSize {
61 oldest := c.order.Back()
62 c.order.Remove(oldest)
63 delete(c.entries, oldest.Value.(*lruEntry[V]).key)
64 }
65}
66
67func (c *lru[V]) Delete(key string) {
68 c.mu.Lock()
69 defer c.mu.Unlock()
70
71 if el, ok := c.entries[key]; ok {
72 c.order.Remove(el)
73 delete(c.entries, key)
74 }
75}
76