github.com/fibonacci-chain/fbc@v0.0.0-20231124064014-c7636198c1e9/libs/cosmos-sdk/store/cachemulti/store.go (about) 1 package cachemulti 2 3 import ( 4 "fmt" 5 "io" 6 "sync" 7 8 dbm "github.com/fibonacci-chain/fbc/libs/tm-db" 9 10 "github.com/fibonacci-chain/fbc/libs/cosmos-sdk/store/cachekv" 11 "github.com/fibonacci-chain/fbc/libs/cosmos-sdk/store/dbadapter" 12 "github.com/fibonacci-chain/fbc/libs/cosmos-sdk/store/types" 13 ) 14 15 //---------------------------------------- 16 // Store 17 18 // Store holds many cache-wrapped stores. 19 // Implements MultiStore. 20 // NOTE: a Store (and MultiStores in general) should never expose the 21 // keys for the substores. 22 type Store struct { 23 db types.CacheKVStore 24 stores map[types.StoreKey]types.CacheWrap 25 keys map[string]types.StoreKey 26 27 traceWriter io.Writer 28 traceContext types.TraceContext 29 } 30 31 var _ types.CacheMultiStore = Store{} 32 33 // NewFromKVStore creates a new Store object from a mapping of store keys to 34 // CacheWrapper objects and a KVStore as the database. Each CacheWrapper store 35 // is cache-wrapped. 36 func NewFromKVStore( 37 store types.KVStore, stores map[types.StoreKey]types.CacheWrapper, 38 keys map[string]types.StoreKey, traceWriter io.Writer, traceContext types.TraceContext, 39 ) Store { 40 cms := Store{ 41 db: cachekv.NewStore(store), 42 stores: make(map[types.StoreKey]types.CacheWrap, len(stores)), 43 keys: keys, 44 traceWriter: traceWriter, 45 traceContext: traceContext, 46 } 47 48 for key, store := range stores { 49 if cms.TracingEnabled() { 50 cms.stores[key] = store.CacheWrapWithTrace(cms.traceWriter, cms.traceContext) 51 } else { 52 cms.stores[key] = store.CacheWrap() 53 } 54 } 55 56 return cms 57 } 58 59 // newFromKVStore creates a new Store object from a mapping of store keys to 60 // CacheWrap objects and a KVStore as the database. Each CacheWrapper store 61 // is cache-wrapped. 62 func newFromKVStore( 63 store types.KVStore, stores map[types.StoreKey]types.CacheWrap, 64 keys map[string]types.StoreKey, traceWriter io.Writer, traceContext types.TraceContext, 65 ) Store { 66 cms := Store{ 67 db: cachekv.NewStore(store), 68 stores: make(map[types.StoreKey]types.CacheWrap, len(stores)), 69 keys: keys, 70 traceWriter: traceWriter, 71 traceContext: traceContext, 72 } 73 74 for key, store := range stores { 75 if cms.TracingEnabled() { 76 cms.stores[key] = store.CacheWrapWithTrace(cms.traceWriter, cms.traceContext) 77 } else { 78 cms.stores[key] = store.CacheWrap() 79 } 80 } 81 82 return cms 83 } 84 85 // NewStore creates a new Store object from a mapping of store keys to 86 // CacheWrapper objects. Each CacheWrapper store is cache-wrapped. 87 func NewStore( 88 db dbm.DB, stores map[types.StoreKey]types.CacheWrapper, keys map[string]types.StoreKey, 89 traceWriter io.Writer, traceContext types.TraceContext, 90 ) Store { 91 92 return NewFromKVStore(dbadapter.Store{DB: db}, stores, keys, traceWriter, traceContext) 93 } 94 95 func newCacheMultiStoreFromCMS(cms Store) Store { 96 return newFromKVStore(cms.db, cms.stores, nil, cms.traceWriter, cms.traceContext) 97 } 98 99 func (cms Store) Reset(ms types.MultiStore) bool { 100 switch rms := ms.(type) { 101 case Store: 102 cms.reset(rms) 103 return true 104 default: 105 return false 106 } 107 } 108 109 var keysPool = &sync.Pool{ 110 New: func() interface{} { 111 return make(map[types.StoreKey]struct{}) 112 }, 113 } 114 115 func (cms Store) reset(ms Store) { 116 cms.db.(*cachekv.Store).Reset(ms.db) 117 cms.traceWriter = ms.traceWriter 118 cms.traceContext = ms.traceContext 119 cms.keys = ms.keys 120 121 keysMap := keysPool.Get().(map[types.StoreKey]struct{}) 122 defer keysPool.Put(keysMap) 123 124 for k := range keysMap { 125 delete(keysMap, k) 126 } 127 for k := range ms.stores { 128 keysMap[k] = struct{}{} 129 } 130 131 for k := range keysMap { 132 msstore := ms.stores[k] 133 if store, ok := cms.stores[k]; ok { 134 if cstore, ok := store.(*cachekv.Store); ok { 135 msKvstore, ok := msstore.(types.KVStore) 136 if ok { 137 cstore.Reset(msKvstore) 138 } else { 139 cms.stores[k] = msstore.CacheWrap() 140 } 141 } else { 142 cms.stores[k] = msstore.CacheWrap() 143 } 144 } else { 145 cms.stores[k] = msstore.CacheWrap() 146 } 147 } 148 149 for k := range cms.stores { 150 if _, ok := keysMap[k]; !ok { 151 delete(cms.stores, k) 152 } 153 } 154 } 155 156 // SetTracer sets the tracer for the MultiStore that the underlying 157 // stores will utilize to trace operations. A MultiStore is returned. 158 func (cms Store) SetTracer(w io.Writer) types.MultiStore { 159 cms.traceWriter = w 160 return cms 161 } 162 163 // SetTracingContext updates the tracing context for the MultiStore by merging 164 // the given context with the existing context by key. Any existing keys will 165 // be overwritten. It is implied that the caller should update the context when 166 // necessary between tracing operations. It returns a modified MultiStore. 167 func (cms Store) SetTracingContext(tc types.TraceContext) types.MultiStore { 168 if cms.traceContext != nil { 169 for k, v := range tc { 170 cms.traceContext[k] = v 171 } 172 } else { 173 cms.traceContext = tc 174 } 175 176 return cms 177 } 178 179 // TracingEnabled returns if tracing is enabled for the MultiStore. 180 func (cms Store) TracingEnabled() bool { 181 return cms.traceWriter != nil 182 } 183 184 // GetStoreType returns the type of the store. 185 func (cms Store) GetStoreType() types.StoreType { 186 return types.StoreTypeMulti 187 } 188 189 // Write calls Write on each underlying store. 190 func (cms Store) Write() { 191 cms.db.Write() 192 for _, store := range cms.stores { 193 store.Write() 194 } 195 } 196 197 func (cms Store) IteratorCache(isdirty bool, cb func(key string, value []byte, isDirty bool, isDelete bool, storeKey types.StoreKey) bool, sKey types.StoreKey) bool { 198 for key, store := range cms.stores { 199 if !store.IteratorCache(isdirty, cb, key) { 200 return false 201 } 202 } 203 return true 204 } 205 206 func (cms Store) GetRWSet(mp types.MsRWSet) { 207 for key, store := range cms.stores { 208 if _, ok := mp[key]; !ok { 209 mp[key] = types.NewCacheKvRWSet() 210 } 211 store.(*cachekv.Store).CopyRWSet(mp[key]) 212 } 213 } 214 215 // Implements CacheWrapper. 216 func (cms Store) CacheWrap() types.CacheWrap { 217 return cms.CacheMultiStore().(types.CacheWrap) 218 } 219 220 // CacheWrapWithTrace implements the CacheWrapper interface. 221 func (cms Store) CacheWrapWithTrace(_ io.Writer, _ types.TraceContext) types.CacheWrap { 222 return cms.CacheWrap() 223 } 224 225 // Implements MultiStore. 226 func (cms Store) CacheMultiStore() types.CacheMultiStore { 227 return newCacheMultiStoreFromCMS(cms) 228 } 229 230 // CacheMultiStoreWithVersion implements the MultiStore interface. It will panic 231 // as an already cached multi-store cannot load previous versions. 232 // 233 // TODO: The store implementation can possibly be modified to support this as it 234 // seems safe to load previous versions (heights). 235 func (cms Store) CacheMultiStoreWithVersion(_ int64) (types.CacheMultiStore, error) { 236 panic("cannot cache-wrap cached multi-store with a version") 237 } 238 239 // GetStore returns an underlying Store by key. 240 func (cms Store) GetStore(key types.StoreKey) types.Store { 241 s := cms.stores[key] 242 if key == nil || s == nil { 243 panic(fmt.Sprintf("kv store with key %v has not been registered in stores", key)) 244 } 245 return s.(types.Store) 246 } 247 248 // GetKVStore returns an underlying KVStore by key. 249 func (cms Store) GetKVStore(key types.StoreKey) types.KVStore { 250 store := cms.stores[key] 251 if key == nil || store == nil { 252 panic(fmt.Sprintf("kv store with key %v has not been registered in stores", key)) 253 } 254 255 return store.(types.KVStore) 256 } 257 258 func (cms Store) Clear() { 259 cms.db.Clear() 260 for _, store := range cms.stores { 261 store.Clear() 262 } 263 } 264 265 func (cms Store) DisableCacheReadList() { 266 for _, store := range cms.stores { 267 store.DisableCacheReadList() 268 } 269 }