github.com/MetalBlockchain/metalgo@v1.11.9/cache/unique_cache.go (about) 1 // Copyright (C) 2019-2024, Ava Labs, Inc. All rights reserved. 2 // See the file LICENSE for licensing terms. 3 4 package cache 5 6 import ( 7 "sync" 8 9 "github.com/MetalBlockchain/metalgo/utils/linked" 10 ) 11 12 var _ Deduplicator[struct{}, Evictable[struct{}]] = (*EvictableLRU[struct{}, Evictable[struct{}]])(nil) 13 14 // EvictableLRU is an LRU cache that notifies the objects when they are evicted. 15 type EvictableLRU[K comparable, V Evictable[K]] struct { 16 lock sync.Mutex 17 entryMap map[K]*linked.ListElement[V] 18 entryList *linked.List[V] 19 Size int 20 } 21 22 func (c *EvictableLRU[_, V]) Deduplicate(value V) V { 23 c.lock.Lock() 24 defer c.lock.Unlock() 25 26 return c.deduplicate(value) 27 } 28 29 func (c *EvictableLRU[_, _]) Flush() { 30 c.lock.Lock() 31 defer c.lock.Unlock() 32 33 c.flush() 34 } 35 36 func (c *EvictableLRU[K, V]) init() { 37 if c.entryMap == nil { 38 c.entryMap = make(map[K]*linked.ListElement[V]) 39 } 40 if c.entryList == nil { 41 c.entryList = linked.NewList[V]() 42 } 43 if c.Size <= 0 { 44 c.Size = 1 45 } 46 } 47 48 func (c *EvictableLRU[_, V]) resize() { 49 for c.entryList.Len() > c.Size { 50 e := c.entryList.Front() 51 c.entryList.Remove(e) 52 53 delete(c.entryMap, e.Value.Key()) 54 e.Value.Evict() 55 } 56 } 57 58 func (c *EvictableLRU[_, V]) deduplicate(value V) V { 59 c.init() 60 c.resize() 61 62 key := value.Key() 63 if e, ok := c.entryMap[key]; !ok { 64 if c.entryList.Len() >= c.Size { 65 e = c.entryList.Front() 66 c.entryList.MoveToBack(e) 67 68 delete(c.entryMap, e.Value.Key()) 69 e.Value.Evict() 70 71 e.Value = value 72 } else { 73 e = &linked.ListElement[V]{ 74 Value: value, 75 } 76 c.entryList.PushBack(e) 77 } 78 c.entryMap[key] = e 79 } else { 80 c.entryList.MoveToBack(e) 81 82 value = e.Value 83 } 84 return value 85 } 86 87 func (c *EvictableLRU[_, _]) flush() { 88 c.init() 89 90 size := c.Size 91 c.Size = 0 92 c.resize() 93 c.Size = size 94 }