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  }