github.com/Finschia/finschia-sdk@v0.48.1/store/cachemulti/store.go (about) 1 package cachemulti 2 3 import ( 4 "fmt" 5 "io" 6 7 dbm "github.com/tendermint/tm-db" 8 9 "github.com/Finschia/finschia-sdk/store/cachekv" 10 "github.com/Finschia/finschia-sdk/store/dbadapter" 11 "github.com/Finschia/finschia-sdk/store/listenkv" 12 "github.com/Finschia/finschia-sdk/store/tracekv" 13 "github.com/Finschia/finschia-sdk/store/types" 14 ) 15 16 //---------------------------------------- 17 // Store 18 19 // Store holds many branched stores. 20 // Implements MultiStore. 21 // NOTE: a Store (and MultiStores in general) should never expose the 22 // keys for the substores. 23 type Store struct { 24 db types.CacheKVStore 25 stores map[types.StoreKey]types.CacheWrap 26 keys map[string]types.StoreKey 27 28 traceWriter io.Writer 29 traceContext types.TraceContext 30 31 listeners map[types.StoreKey][]types.WriteListener 32 } 33 34 var _ types.CacheMultiStore = Store{} 35 36 // NewFromKVStore creates a new Store object from a mapping of store keys to 37 // CacheWrapper objects and a KVStore as the database. Each CacheWrapper store 38 // is a branched store. 39 func NewFromKVStore( 40 store types.KVStore, stores map[types.StoreKey]types.CacheWrapper, 41 keys map[string]types.StoreKey, traceWriter io.Writer, traceContext types.TraceContext, 42 listeners map[types.StoreKey][]types.WriteListener, 43 ) Store { 44 cms := Store{ 45 db: cachekv.NewStore(store), 46 stores: make(map[types.StoreKey]types.CacheWrap, len(stores)), 47 keys: keys, 48 traceWriter: traceWriter, 49 traceContext: traceContext, 50 listeners: listeners, 51 } 52 53 for key, store := range stores { 54 if cms.TracingEnabled() { 55 store = tracekv.NewStore(store.(types.KVStore), cms.traceWriter, cms.traceContext) 56 } 57 if cms.ListeningEnabled(key) { 58 store = listenkv.NewStore(store.(types.KVStore), key, listeners[key]) 59 } 60 cms.stores[key] = cachekv.NewStore(store.(types.KVStore)) 61 } 62 63 return cms 64 } 65 66 // NewStore creates a new Store object from a mapping of store keys to 67 // CacheWrapper objects. Each CacheWrapper store is a branched store. 68 func NewStore( 69 db dbm.DB, stores map[types.StoreKey]types.CacheWrapper, keys map[string]types.StoreKey, 70 traceWriter io.Writer, traceContext types.TraceContext, listeners map[types.StoreKey][]types.WriteListener, 71 ) Store { 72 return NewFromKVStore(dbadapter.Store{DB: db}, stores, keys, traceWriter, traceContext, listeners) 73 } 74 75 func newCacheMultiStoreFromCMS(cms Store) Store { 76 stores := make(map[types.StoreKey]types.CacheWrapper) 77 for k, v := range cms.stores { 78 stores[k] = v 79 } 80 81 return NewFromKVStore(cms.db, stores, nil, cms.traceWriter, cms.traceContext, cms.listeners) 82 } 83 84 // SetTracer sets the tracer for the MultiStore that the underlying 85 // stores will utilize to trace operations. A MultiStore is returned. 86 func (cms Store) SetTracer(w io.Writer) types.MultiStore { 87 cms.traceWriter = w 88 return cms 89 } 90 91 // SetTracingContext updates the tracing context for the MultiStore by merging 92 // the given context with the existing context by key. Any existing keys will 93 // be overwritten. It is implied that the caller should update the context when 94 // necessary between tracing operations. It returns a modified MultiStore. 95 func (cms Store) SetTracingContext(tc types.TraceContext) types.MultiStore { 96 if cms.traceContext != nil { 97 for k, v := range tc { 98 cms.traceContext[k] = v 99 } 100 } else { 101 cms.traceContext = tc 102 } 103 104 return cms 105 } 106 107 // TracingEnabled returns if tracing is enabled for the MultiStore. 108 func (cms Store) TracingEnabled() bool { 109 return cms.traceWriter != nil 110 } 111 112 // AddListeners adds listeners for a specific KVStore 113 func (cms Store) AddListeners(key types.StoreKey, listeners []types.WriteListener) { 114 if ls, ok := cms.listeners[key]; ok { 115 cms.listeners[key] = append(ls, listeners...) 116 } else { 117 cms.listeners[key] = listeners 118 } 119 } 120 121 // ListeningEnabled returns if listening is enabled for a specific KVStore 122 func (cms Store) ListeningEnabled(key types.StoreKey) bool { 123 if ls, ok := cms.listeners[key]; ok { 124 return len(ls) != 0 125 } 126 return false 127 } 128 129 // GetStoreType returns the type of the store. 130 func (cms Store) GetStoreType() types.StoreType { 131 return types.StoreTypeMulti 132 } 133 134 // Write calls Write on each underlying store. 135 func (cms Store) Write() { 136 cms.db.Write() 137 for _, store := range cms.stores { 138 store.Write() 139 } 140 } 141 142 // Implements CacheWrapper. 143 func (cms Store) CacheWrap() types.CacheWrap { 144 return cms.CacheMultiStore().(types.CacheWrap) 145 } 146 147 // CacheWrapWithTrace implements the CacheWrapper interface. 148 func (cms Store) CacheWrapWithTrace(_ io.Writer, _ types.TraceContext) types.CacheWrap { 149 return cms.CacheWrap() 150 } 151 152 // CacheWrapWithListeners implements the CacheWrapper interface. 153 func (cms Store) CacheWrapWithListeners(_ types.StoreKey, _ []types.WriteListener) types.CacheWrap { 154 return cms.CacheWrap() 155 } 156 157 // Implements MultiStore. 158 func (cms Store) CacheMultiStore() types.CacheMultiStore { 159 return newCacheMultiStoreFromCMS(cms) 160 } 161 162 // CacheMultiStoreWithVersion implements the MultiStore interface. It will panic 163 // as an already cached multi-store cannot load previous versions. 164 // 165 // TODO: The store implementation can possibly be modified to support this as it 166 // seems safe to load previous versions (heights). 167 func (cms Store) CacheMultiStoreWithVersion(_ int64) (types.CacheMultiStore, error) { 168 panic("cannot branch cached multi-store with a version") 169 } 170 171 // GetStore returns an underlying Store by key. 172 func (cms Store) GetStore(key types.StoreKey) types.Store { 173 s := cms.stores[key] 174 if key == nil || s == nil { 175 panic(fmt.Sprintf("kv store with key %v has not been registered in stores", key)) 176 } 177 return s.(types.Store) 178 } 179 180 // GetKVStore returns an underlying KVStore by key. 181 func (cms Store) GetKVStore(key types.StoreKey) types.KVStore { 182 store := cms.stores[key] 183 if key == nil || store == nil { 184 panic(fmt.Sprintf("kv store with key %v has not been registered in stores", key)) 185 } 186 return store.(types.KVStore) 187 }