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  }