github.com/Finschia/finschia-sdk@v0.48.1/store/cache/cache.go (about) 1 package cache 2 3 import ( 4 "sync" 5 "time" 6 7 "github.com/VictoriaMetrics/fastcache" 8 9 "github.com/Finschia/finschia-sdk/store/cachekv" 10 "github.com/Finschia/finschia-sdk/store/types" 11 ) 12 13 const ( 14 DefaultCommitKVStoreCacheSize = 1024 * 1024 * 100 // 100 MB 15 ) 16 17 var ( 18 _ types.CommitKVStore = (*CommitKVStoreCache)(nil) 19 _ types.MultiStorePersistentCache = (*CommitKVStoreCacheManager)(nil) 20 ) 21 22 type ( 23 // CommitKVStoreCache implements an inter-block (persistent) cache that wraps a 24 // CommitKVStore. Reads first hit the internal ARC (Adaptive Replacement Cache). 25 // During a cache miss, the read is delegated to the underlying CommitKVStore 26 // and cached. Deletes and writes always happen to both the cache and the 27 // CommitKVStore in a write-through manner. Caching performed in the 28 // CommitKVStore and below is completely irrelevant to this layer. 29 CommitKVStoreCache struct { 30 types.CommitKVStore 31 cache *fastcache.Cache 32 prefix []byte 33 metrics *Metrics 34 } 35 36 // CommitKVStoreCacheManager maintains a mapping from a StoreKey to a 37 // CommitKVStoreCache. Each CommitKVStore, per StoreKey, is meant to be used 38 // in an inter-block (persistent) manner and typically provided by a 39 // CommitMultiStore. 40 CommitKVStoreCacheManager struct { 41 mutex sync.Mutex 42 cache *fastcache.Cache 43 caches map[string]types.CommitKVStore 44 metrics *Metrics 45 46 // All cache stores use the unique prefix that has one byte length 47 // Contract: The number of all cache stores cannot exceed 127(max byte) 48 prefixMap map[string][]byte 49 prefixOrder byte 50 } 51 ) 52 53 func NewCommitKVStoreCache(store types.CommitKVStore, prefix []byte, cache *fastcache.Cache, 54 metrics *Metrics) *CommitKVStoreCache { 55 return &CommitKVStoreCache{ 56 CommitKVStore: store, 57 prefix: prefix, 58 cache: cache, 59 metrics: metrics, 60 } 61 } 62 63 func NewCommitKVStoreCacheManager(cacheSize int, provider MetricsProvider) *CommitKVStoreCacheManager { 64 if cacheSize <= 0 { 65 // This function was called because it intended to use the inter block cache, creating a cache of minimal size. 66 cacheSize = DefaultCommitKVStoreCacheSize 67 } 68 cm := &CommitKVStoreCacheManager{ 69 cache: fastcache.New(cacheSize), 70 caches: make(map[string]types.CommitKVStore), 71 metrics: provider(), 72 prefixMap: make(map[string][]byte), 73 prefixOrder: 0, 74 } 75 startCacheMetricUpdator(cm.cache, cm.metrics) 76 return cm 77 } 78 79 func startCacheMetricUpdator(cache *fastcache.Cache, metrics *Metrics) { 80 // Execution time of `fastcache.UpdateStats()` can increase linearly as cache entries grows 81 // So we update the metrics with a separate go route. 82 go func() { 83 for { 84 stats := fastcache.Stats{} 85 cache.UpdateStats(&stats) 86 metrics.InterBlockCacheEntries.Set(float64(stats.EntriesCount)) 87 metrics.InterBlockCacheBytes.Set(float64(stats.BytesSize)) 88 time.Sleep(1 * time.Minute) 89 } 90 }() 91 } 92 93 // GetStoreCache returns a Cache from the CommitStoreCacheManager for a given 94 // StoreKey. If no Cache exists for the StoreKey, then one is created and set. 95 // The returned Cache is meant to be used in a persistent manner. 96 func (cmgr *CommitKVStoreCacheManager) GetStoreCache(key types.StoreKey, store types.CommitKVStore) types.CommitKVStore { 97 if cmgr.caches[key.Name()] == nil { 98 // After concurrent checkTx, delieverTx becomes to be possible, this should be protected by a mutex 99 cmgr.mutex.Lock() 100 if cmgr.caches[key.Name()] == nil { // recheck after acquiring lock 101 cmgr.prefixMap[key.Name()] = []byte{cmgr.prefixOrder} 102 cmgr.prefixOrder++ 103 if cmgr.prefixOrder <= 0 { 104 panic("The number of cache stores exceed the maximum(127)") 105 } 106 cmgr.caches[key.Name()] = NewCommitKVStoreCache(store, cmgr.prefixMap[key.Name()], cmgr.cache, cmgr.metrics) 107 } 108 cmgr.mutex.Unlock() 109 } 110 111 return cmgr.caches[key.Name()] 112 } 113 114 // Unwrap returns the underlying CommitKVStore for a given StoreKey. 115 func (cmgr *CommitKVStoreCacheManager) Unwrap(key types.StoreKey) types.CommitKVStore { 116 if ckv, ok := cmgr.caches[key.Name()]; ok { 117 return ckv.(*CommitKVStoreCache).CommitKVStore 118 } 119 120 return nil 121 } 122 123 // Reset resets in the internal caches. 124 func (cmgr *CommitKVStoreCacheManager) Reset() { 125 // Clear the map. 126 // Please note that we are purposefully using the map clearing idiom. 127 // See https://github.com/cosmos/cosmos-sdk/issues/6681. 128 for key := range cmgr.caches { 129 delete(cmgr.caches, key) 130 } 131 } 132 133 // CacheWrap implements the CacheWrapper interface 134 func (ckv *CommitKVStoreCache) CacheWrap() types.CacheWrap { 135 return cachekv.NewStore(ckv) 136 } 137 138 // Get retrieves a value by key. It will first look in the write-through cache. 139 // If the value doesn't exist in the write-through cache, the query is delegated 140 // to the underlying CommitKVStore. 141 func (ckv *CommitKVStoreCache) Get(key []byte) []byte { 142 types.AssertValidKey(key) 143 prefixedKey := append(ckv.prefix, key...) 144 145 valueI := ckv.cache.Get(nil, prefixedKey) 146 if valueI != nil { 147 // cache hit 148 ckv.metrics.InterBlockCacheHits.Add(1) 149 return valueI 150 } 151 152 // cache miss; write to cache 153 ckv.metrics.InterBlockCacheMisses.Add(1) 154 value := ckv.CommitKVStore.Get(key) 155 ckv.cache.Set(prefixedKey, value) 156 return value 157 } 158 159 // Set inserts a key/value pair into both the write-through cache and the 160 // underlying CommitKVStore. 161 func (ckv *CommitKVStoreCache) Set(key, value []byte) { 162 types.AssertValidKey(key) 163 types.AssertValidValue(value) 164 165 prefixedKey := append(ckv.prefix, key...) 166 ckv.cache.Set(prefixedKey, value) 167 ckv.CommitKVStore.Set(key, value) 168 } 169 170 // Delete removes a key/value pair from both the write-through cache and the 171 // underlying CommitKVStore. 172 func (ckv *CommitKVStoreCache) Delete(key []byte) { 173 prefixedKey := append(ckv.prefix, key...) 174 ckv.cache.Del(prefixedKey) 175 ckv.CommitKVStore.Delete(key) 176 }