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  }