github.com/fibonacci-chain/fbc@v0.0.0-20231124064014-c7636198c1e9/libs/iavl/fast_node_cache.go (about) 1 package iavl 2 3 import ( 4 "container/list" 5 "sync" 6 7 "github.com/tendermint/go-amino" 8 ) 9 10 type FastNodeCache struct { 11 items map[string]*list.Element // items. 12 cacheSize int // cache size limit in elements. 13 cacheQueue *syncList // LRU queue of cache elements. Used for deletion. 14 cacheMutex sync.RWMutex // Mutex for node cache. 15 } 16 17 func newFastNodeCache(dbName string, cacheSize int) *FastNodeCache { 18 if dbName == "evm" { 19 return &FastNodeCache{ 20 items: makeFastNodeCacheMap(cacheSize, 1), 21 cacheSize: cacheSize, 22 cacheQueue: newSyncList(), 23 } 24 } else { 25 return &FastNodeCache{ 26 items: make(map[string]*list.Element), 27 cacheSize: cacheSize, 28 cacheQueue: newSyncList(), 29 } 30 } 31 } 32 33 func makeFastNodeCacheMap(cacheSize int, initRatio float64) map[string]*list.Element { 34 if initRatio <= 0 { 35 return make(map[string]*list.Element) 36 } 37 if initRatio >= 1 { 38 return make(map[string]*list.Element, cacheSize) 39 } 40 cacheSize = int(float64(cacheSize) * initRatio) 41 return make(map[string]*list.Element, cacheSize) 42 } 43 44 // =================================================== 45 // ======= map[string]*list.Element implementation 46 // =================================================== 47 48 func (fnc *FastNodeCache) uncache(key []byte) { 49 fnc.cacheMutex.Lock() 50 if elem, ok := fnc.items[string(key)]; ok { 51 fnc.cacheQueue.Remove(elem) 52 delete(fnc.items, string(key)) 53 } 54 fnc.cacheMutex.Unlock() 55 } 56 57 // Add a node to the cache and pop the least recently used node if we've 58 // reached the cache size limit. 59 func (fnc *FastNodeCache) cache(node *FastNode) { 60 fnc.cacheMutex.Lock() 61 62 if elem, ok := fnc.items[string(node.key)]; ok { 63 fnc.cacheQueue.MoveToBack(elem) 64 elem.Value = node 65 } else { 66 elem := fnc.cacheQueue.PushBack(node) 67 fnc.items[string(node.key)] = elem 68 69 for fnc.cacheQueue.Len() > GetFastNodeCacheSize() { 70 oldest := fnc.cacheQueue.Front() 71 key := fnc.cacheQueue.Remove(oldest).(*FastNode).key 72 delete(fnc.items, amino.BytesToStr(key)) 73 } 74 } 75 76 fnc.cacheMutex.Unlock() 77 } 78 79 func (fnc *FastNodeCache) get(key []byte, promoteRecentNode bool) (n *FastNode) { 80 // Check the cache. 81 fnc.cacheMutex.RLock() 82 elem, ok := fnc.items[string(key)] 83 if ok { 84 if promoteRecentNode { 85 // Already exists. Move to back of cacheQueue. 86 fnc.cacheQueue.MoveToBack(elem) 87 } 88 n = elem.Value.(*FastNode) 89 } 90 fnc.cacheMutex.RUnlock() 91 return 92 } 93 94 func (fnc *FastNodeCache) cacheLen() int { 95 return len(fnc.items) 96 }