github.com/fibonacci-chain/fbc@v0.0.0-20231124064014-c7636198c1e9/libs/cosmos-sdk/store/cachekv/store.go (about)

     1  package cachekv
     2  
     3  import (
     4  	"bytes"
     5  	"io"
     6  	"reflect"
     7  	"sort"
     8  	"sync"
     9  	"unsafe"
    10  
    11  	"github.com/fibonacci-chain/fbc/libs/iavl"
    12  	"github.com/fibonacci-chain/fbc/libs/system/trace"
    13  	dbm "github.com/fibonacci-chain/fbc/libs/tm-db"
    14  	"github.com/tendermint/go-amino"
    15  
    16  	"github.com/fibonacci-chain/fbc/libs/cosmos-sdk/store/tracekv"
    17  	"github.com/fibonacci-chain/fbc/libs/cosmos-sdk/store/types"
    18  	kv "github.com/fibonacci-chain/fbc/libs/cosmos-sdk/types/kv"
    19  )
    20  
    21  // If value is nil but deleted is false, it means the parent doesn't have the
    22  // key.  (No need to delete upon Write())
    23  type cValue struct {
    24  	value   []byte
    25  	deleted bool
    26  }
    27  
    28  type PreChangesHandler func(keys []string, setOrDel []byte)
    29  
    30  // Store wraps an in-memory cache around an underlying types.KVStore.
    31  type Store struct {
    32  	mtx           sync.Mutex
    33  	dirty         map[string]cValue
    34  	readList      map[string][]byte
    35  	unsortedCache map[string]struct{}
    36  	sortedCache   *kv.List // always ascending sorted
    37  	parent        types.KVStore
    38  
    39  	preChangesHandler    PreChangesHandler
    40  	disableCacheReadList bool // not cache readList for group-paralleled-tx
    41  	trace.StatisticsCell
    42  }
    43  
    44  var _ types.CacheKVStore = (*Store)(nil)
    45  
    46  func NewStore(parent types.KVStore) *Store {
    47  	return &Store{
    48  		dirty:         make(map[string]cValue),
    49  		readList:      make(map[string][]byte),
    50  		unsortedCache: make(map[string]struct{}),
    51  		sortedCache:   kv.NewList(),
    52  		parent:        parent,
    53  	}
    54  }
    55  
    56  func NewStoreWithPreChangeHandler(parent types.KVStore, preChangesHandler PreChangesHandler) *Store {
    57  	s := NewStore(parent)
    58  	s.preChangesHandler = preChangesHandler
    59  	return s
    60  }
    61  
    62  // Implements Store.
    63  func (store *Store) GetStoreType() types.StoreType {
    64  	return store.parent.GetStoreType()
    65  }
    66  
    67  // Implements types.KVStore.
    68  func (store *Store) Get(key []byte) (value []byte) {
    69  	store.mtx.Lock()
    70  	defer store.mtx.Unlock()
    71  
    72  	types.AssertValidKey(key)
    73  
    74  	cacheValue, ok := store.dirty[string(key)]
    75  	if !ok {
    76  		if c, ok := store.readList[string(key)]; ok {
    77  			value = c
    78  		} else {
    79  			value = store.parent.Get(key)
    80  			if !store.disableCacheReadList {
    81  				store.setCacheValue(key, value, false, false)
    82  			}
    83  		}
    84  	} else {
    85  		value = cacheValue.value
    86  	}
    87  
    88  	return value
    89  }
    90  
    91  func (store *Store) GetRWSet(mp types.MsRWSet) {
    92  	panic("implement me")
    93  }
    94  
    95  func (store *Store) IteratorCache(isdirty bool, cb func(key string, value []byte, isDirty bool, isDelete bool, sKey types.StoreKey) bool, sKey types.StoreKey) bool {
    96  	if cb == nil {
    97  		return true
    98  	}
    99  	store.mtx.Lock()
   100  	defer store.mtx.Unlock()
   101  
   102  	if isdirty {
   103  		for key, v := range store.dirty {
   104  			if !cb(key, v.value, true, v.deleted, sKey) {
   105  				return false
   106  			}
   107  		}
   108  	} else {
   109  		for key, v := range store.readList {
   110  			if !cb(key, v, false, false, sKey) {
   111  				return false
   112  			}
   113  		}
   114  	}
   115  
   116  	return true
   117  }
   118  
   119  // Implements types.KVStore.
   120  func (store *Store) Set(key []byte, value []byte) {
   121  	store.mtx.Lock()
   122  	defer store.mtx.Unlock()
   123  
   124  	types.AssertValidKey(key)
   125  	types.AssertValidValue(value)
   126  
   127  	store.setCacheValue(key, value, false, true)
   128  }
   129  
   130  // Implements types.KVStore.
   131  func (store *Store) Has(key []byte) bool {
   132  	value := store.Get(key)
   133  	return value != nil
   134  }
   135  
   136  // Implements types.KVStore.
   137  func (store *Store) Delete(key []byte) {
   138  	store.mtx.Lock()
   139  	defer store.mtx.Unlock()
   140  
   141  	types.AssertValidKey(key)
   142  
   143  	store.setCacheValue(key, nil, true, true)
   144  }
   145  
   146  // Implements Cachetypes.KVStore.
   147  func (store *Store) Write() {
   148  	// if parent is cachekv.Store, we can write kv more efficiently
   149  	if pStore, ok := store.parent.(*Store); ok {
   150  		store.writeToCacheKv(pStore)
   151  		return
   152  	}
   153  
   154  	store.mtx.Lock()
   155  	defer store.mtx.Unlock()
   156  
   157  	// We need a copy of all of the keys.
   158  	// Not the best, but probably not a bottleneck depending.
   159  	keys := make([]string, len(store.dirty))
   160  	index := 0
   161  	for key, _ := range store.dirty {
   162  		keys[index] = key
   163  		index++
   164  
   165  	}
   166  
   167  	sort.Strings(keys)
   168  	store.preWrite(keys)
   169  
   170  	store.StartTiming()
   171  
   172  	// TODO: Consider allowing usage of Batch, which would allow the write to
   173  	// at least happen atomically.
   174  	for _, key := range keys {
   175  		cacheValue := store.dirty[key]
   176  		switch {
   177  		case cacheValue.deleted:
   178  			store.parent.Delete([]byte(key))
   179  		case cacheValue.value == nil:
   180  			// Skip, it already doesn't exist in parent.
   181  		default:
   182  			store.parent.Set([]byte(key), cacheValue.value)
   183  		}
   184  	}
   185  
   186  	// Clear the cache
   187  	store.clearCache()
   188  	store.EndTiming(trace.FlushCache)
   189  }
   190  
   191  func (store *Store) preWrite(keys []string) {
   192  	if store.preChangesHandler == nil || len(keys) < 4 {
   193  		return
   194  	}
   195  
   196  	setOrDel := make([]byte, 0, len(keys))
   197  
   198  	for _, key := range keys {
   199  		cacheValue := store.dirty[key]
   200  		switch {
   201  		case cacheValue.deleted:
   202  			setOrDel = append(setOrDel, iavl.PreChangeOpDelete)
   203  		case cacheValue.value == nil:
   204  			// Skip, it already doesn't exist in parent.
   205  			setOrDel = append(setOrDel, iavl.PreChangeNop)
   206  		default:
   207  			setOrDel = append(setOrDel, iavl.PreChangeOpSet)
   208  		}
   209  	}
   210  
   211  	store.preChangesHandler(keys, setOrDel)
   212  }
   213  
   214  // writeToCacheKv will write cached kv to the parent Store, then clear the cache.
   215  func (store *Store) writeToCacheKv(parent *Store) {
   216  	store.mtx.Lock()
   217  	defer store.mtx.Unlock()
   218  
   219  	// TODO: Consider allowing usage of Batch, which would allow the write to
   220  	// at least happen atomically.
   221  	for key, cacheValue := range store.dirty {
   222  		switch {
   223  		case cacheValue.deleted:
   224  			parent.Delete(amino.StrToBytes(key))
   225  		case cacheValue.value == nil:
   226  			// Skip, it already doesn't exist in parent.
   227  		default:
   228  			parent.Set(amino.StrToBytes(key), cacheValue.value)
   229  		}
   230  	}
   231  
   232  	// Clear the cache
   233  	store.clearCache()
   234  }
   235  
   236  func (store *Store) clearCache() {
   237  	// https://github.com/golang/go/issues/20138
   238  	for key := range store.dirty {
   239  		delete(store.dirty, key)
   240  	}
   241  
   242  	for Key := range store.readList {
   243  		delete(store.readList, Key)
   244  	}
   245  	for key := range store.unsortedCache {
   246  		delete(store.unsortedCache, key)
   247  	}
   248  	store.disableCacheReadList = false
   249  	store.sortedCache.Init()
   250  }
   251  
   252  //----------------------------------------
   253  // To cache-wrap this Store further.
   254  
   255  // Implements CacheWrapper.
   256  func (store *Store) CacheWrap() types.CacheWrap {
   257  	return NewStore(store)
   258  }
   259  
   260  // CacheWrapWithTrace implements the CacheWrapper interface.
   261  func (store *Store) CacheWrapWithTrace(w io.Writer, tc types.TraceContext) types.CacheWrap {
   262  	return NewStore(tracekv.NewStore(store, w, tc))
   263  }
   264  
   265  //----------------------------------------
   266  // Iteration
   267  
   268  // Implements types.KVStore.
   269  func (store *Store) Iterator(start, end []byte) types.Iterator {
   270  	return store.iterator(start, end, true)
   271  }
   272  
   273  // Implements types.KVStore.
   274  func (store *Store) ReverseIterator(start, end []byte) types.Iterator {
   275  	return store.iterator(start, end, false)
   276  }
   277  
   278  func (store *Store) iterator(start, end []byte, ascending bool) types.Iterator {
   279  	store.mtx.Lock()
   280  	defer store.mtx.Unlock()
   281  
   282  	var parent, cache types.Iterator
   283  
   284  	if ascending {
   285  		parent = store.parent.Iterator(start, end)
   286  	} else {
   287  		parent = store.parent.ReverseIterator(start, end)
   288  	}
   289  
   290  	store.dirtyItems(start, end)
   291  	cache = newMemIterator(start, end, store.sortedCache, ascending)
   292  
   293  	return newCacheMergeIterator(parent, cache, ascending)
   294  }
   295  
   296  // strToByte is meant to make a zero allocation conversion
   297  // from string -> []byte to speed up operations, it is not meant
   298  // to be used generally, but for a specific pattern to check for available
   299  // keys within a domain.
   300  func strToByte(s string) []byte {
   301  	var b []byte
   302  	hdr := (*reflect.SliceHeader)(unsafe.Pointer(&b))
   303  	hdr.Cap = len(s)
   304  	hdr.Len = len(s)
   305  	hdr.Data = (*reflect.StringHeader)(unsafe.Pointer(&s)).Data
   306  	return b
   307  }
   308  
   309  // byteSliceToStr is meant to make a zero allocation conversion
   310  // from []byte -> string to speed up operations, it is not meant
   311  // to be used generally, but for a specific pattern to delete keys
   312  // from a map.
   313  func byteSliceToStr(b []byte) string {
   314  	hdr := (*reflect.StringHeader)(unsafe.Pointer(&b))
   315  	return *(*string)(unsafe.Pointer(hdr))
   316  }
   317  
   318  // Constructs a slice of dirty items, to use w/ memIterator.
   319  func (store *Store) dirtyItems(start, end []byte) {
   320  	unsorted := make([]*kv.Pair, 0)
   321  
   322  	n := len(store.unsortedCache)
   323  	for key := range store.unsortedCache {
   324  		if dbm.IsKeyInDomain(strToByte(key), start, end) {
   325  			cacheValue := store.dirty[key]
   326  			unsorted = append(unsorted, &kv.Pair{Key: []byte(key), Value: cacheValue.value})
   327  		}
   328  	}
   329  
   330  	if len(unsorted) == n { // This pattern allows the Go compiler to emit the map clearing idiom for the entire map.
   331  		for key := range store.unsortedCache {
   332  			delete(store.unsortedCache, key)
   333  		}
   334  	} else { // Otherwise, normally delete the unsorted keys from the map.
   335  		for _, kv := range unsorted {
   336  			delete(store.unsortedCache, byteSliceToStr(kv.Key))
   337  		}
   338  	}
   339  
   340  	sort.Slice(unsorted, func(i, j int) bool {
   341  		return bytes.Compare(unsorted[i].Key, unsorted[j].Key) < 0
   342  	})
   343  
   344  	for e := store.sortedCache.Front(); e != nil && len(unsorted) != 0; {
   345  		uitem := unsorted[0]
   346  		sitem := e.Value
   347  		comp := bytes.Compare(uitem.Key, sitem.Key)
   348  		switch comp {
   349  		case -1:
   350  			unsorted = unsorted[1:]
   351  			store.sortedCache.InsertBefore(uitem, e)
   352  		case 1:
   353  			e = e.Next()
   354  		case 0:
   355  			unsorted = unsorted[1:]
   356  			e.Value = uitem
   357  			e = e.Next()
   358  		}
   359  	}
   360  
   361  	for _, kvp := range unsorted {
   362  		store.sortedCache.PushBack(kvp)
   363  	}
   364  
   365  }
   366  
   367  //----------------------------------------
   368  // etc
   369  
   370  // Only entrypoint to mutate store.cache.
   371  func (store *Store) setCacheValue(key, value []byte, deleted bool, dirty bool) {
   372  	keyStr := string(key)
   373  	if !dirty {
   374  		store.readList[keyStr] = value
   375  		return
   376  	}
   377  
   378  	store.dirty[keyStr] = cValue{
   379  		value:   value,
   380  		deleted: deleted,
   381  	}
   382  	if dirty {
   383  		store.unsortedCache[keyStr] = struct{}{}
   384  	}
   385  }
   386  
   387  // Reset will clear all internal data without writing to the parent and set the new parent.
   388  func (store *Store) Reset(parent types.KVStore) {
   389  	store.mtx.Lock()
   390  
   391  	store.preChangesHandler = nil
   392  	store.parent = parent
   393  	store.StatisticsCell = nil
   394  	store.clearCache()
   395  
   396  	store.mtx.Unlock()
   397  }
   398  
   399  // Clear will clear all internal data without writing to the parent.
   400  func (store *Store) Clear() {
   401  	store.mtx.Lock()
   402  	store.clearCache()
   403  	store.mtx.Unlock()
   404  }
   405  
   406  func (store *Store) DisableCacheReadList() {
   407  	store.mtx.Lock()
   408  	store.disableCacheReadList = true
   409  	store.mtx.Unlock()
   410  }
   411  
   412  func (store *Store) StartTiming() {
   413  	if store.StatisticsCell != nil {
   414  		store.StatisticsCell.StartTiming()
   415  	}
   416  }
   417  
   418  func (store *Store) EndTiming(tag string) {
   419  	if store.StatisticsCell != nil {
   420  		store.StatisticsCell.EndTiming(tag)
   421  	}
   422  }
   423  
   424  func (store *Store) CopyRWSet(rw types.CacheKVRWSet) {
   425  	store.mtx.Lock()
   426  	defer store.mtx.Unlock()
   427  
   428  	for k, v := range store.readList {
   429  		rw.Read[k] = v
   430  	}
   431  
   432  	for k, v := range store.dirty {
   433  		rw.Write[k] = types.DirtyValue{
   434  			Deleted: v.deleted,
   435  			Value:   v.value,
   436  		}
   437  	}
   438  }