diff --git a/store/cachekv/store.go b/store/cachekv/store.go index bc14616946f..baa0f71c81d 100644 --- a/store/cachekv/store.go +++ b/store/cachekv/store.go @@ -165,6 +165,37 @@ func (store *Store) CacheWrapWithTrace(w io.Writer, tc types.TraceContext) types return NewStore(tracekv.NewStore(store, w, tc)) } +// Copy implements deep copy of CacheKVStore +// TODO(dudong2): frequent calls to deep copy are a big bottleneck for performance, so need to benchmark +func (store *Store) Copy() types.CacheKVStore { + store.mtx.Lock() + defer store.mtx.Unlock() + + // deep copy of cValue + cacheCopied := make(map[string]*cValue, len(store.cache)) + for key, val := range store.cache { + valueCopied := make([]byte, len(val.value)) + copy(valueCopied, val.value) + cacheCopied[key] = &cValue{ + value: valueCopied, + dirty: val.dirty, + } + } + + // unsortedCache only track the key + unsortedCacheCopied := make(map[string]struct{}, len(store.unsortedCache)) + for key := range store.unsortedCache { + unsortedCacheCopied[key] = struct{}{} + } + + return &Store{ + cache: cacheCopied, + unsortedCache: unsortedCacheCopied, + sortedCache: store.sortedCache.Copy(), + parent: store.parent, + } +} + //---------------------------------------- // Iteration diff --git a/store/cachemulti/store.go b/store/cachemulti/store.go index cf15b13d16d..dd97329cac3 100644 --- a/store/cachemulti/store.go +++ b/store/cachemulti/store.go @@ -163,3 +163,23 @@ func (cms Store) GetKVStore(key types.StoreKey) types.KVStore { } return store.(types.KVStore) } + +// Copy returns an deep copy of CacheMultiStore +// TODO(dudong2): frequent calls to deep copy are a big bottleneck for performance, so need to benchmark +func (cms Store) Copy() types.CacheMultiStore { + // deep copy of CacheKVStore underlying CacheMultiStore + storesCopied := make(map[types.StoreKey]types.CacheWrap, len(cms.stores)) + for key, store := range cms.stores { + if store, ok := store.(*cachekv.Store); ok { + storesCopied[key] = store.Copy() + } + } + + return Store{ + db: cms.db.Copy(), + stores: storesCopied, + keys: cms.keys, + traceWriter: cms.traceWriter, + traceContext: cms.traceContext, + } +} diff --git a/store/types/store.go b/store/types/store.go index 71ed9f2e60c..d0310fa5e19 100644 --- a/store/types/store.go +++ b/store/types/store.go @@ -134,7 +134,8 @@ type MultiStore interface { // From MultiStore.CacheMultiStore().... type CacheMultiStore interface { MultiStore - Write() // Writes operations to underlying KVStore + Write() // Writes operations to underlying KVStore + Copy() CacheMultiStore // deep copy of CacheMultiStore } // CommitMultiStore is an interface for a MultiStore without cache capabilities. @@ -244,6 +245,9 @@ type CacheKVStore interface { // Writes operations to underlying KVStore Write() + + // deep copy of CacheKVStore + Copy() CacheKVStore } // CommitKVStore is an interface for MultiStore.