NewLRU returns a new thread-safe cache with expirable entries. Size parameter set to 0 makes cache of unlimited size, e.g. turns LRU mechanism off. Providing 0 TTL turns expiring off. Delete expired entries every 1/100th of ttl value. Goroutine which deletes expired entries runs indefinitely.
(size int, onEvict EvictCallback[K, V], ttl time.Duration)
| 50 | // |
| 51 | // Delete expired entries every 1/100th of ttl value. Goroutine which deletes expired entries runs indefinitely. |
| 52 | func NewLRU[K comparable, V any](size int, onEvict EvictCallback[K, V], ttl time.Duration) *LRU[K, V] { |
| 53 | if size < 0 { |
| 54 | size = 0 |
| 55 | } |
| 56 | if ttl <= 0 { |
| 57 | ttl = noEvictionTTL |
| 58 | } |
| 59 | |
| 60 | res := LRU[K, V]{ |
| 61 | ttl: ttl, |
| 62 | size: size, |
| 63 | evictList: NewList[K, V](), |
| 64 | items: make(map[K]*Entry[K, V]), |
| 65 | onEvict: onEvict, |
| 66 | done: make(chan struct{}), |
| 67 | } |
| 68 | |
| 69 | // initialize the buckets |
| 70 | res.buckets = make([]bucket[K, V], numBuckets) |
| 71 | for i := 0; i < numBuckets; i++ { |
| 72 | res.buckets[i] = bucket[K, V]{entries: make(map[K]*Entry[K, V])} |
| 73 | } |
| 74 | |
| 75 | // enable deleteExpired() running in separate goroutine for cache with non-zero TTL |
| 76 | // |
| 77 | // Important: done channel is never closed, so deleteExpired() goroutine will never exit, |
| 78 | // it's decided to add functionality to close it in the version later than v2. |
| 79 | if res.ttl != noEvictionTTL { |
| 80 | go func(done <-chan struct{}) { |
| 81 | ticker := time.NewTicker(res.ttl / numBuckets) |
| 82 | defer ticker.Stop() |
| 83 | for { |
| 84 | select { |
| 85 | case <-done: |
| 86 | return |
| 87 | case <-ticker.C: |
| 88 | res.deleteExpired() |
| 89 | } |
| 90 | } |
| 91 | }(res.done) |
| 92 | } |
| 93 | return &res |
| 94 | } |
| 95 | |
| 96 | // Purge clears the cache completely. |
| 97 | // onEvict is called for each evicted key. |