forked from cosmos/cosmos-sdk
-
Notifications
You must be signed in to change notification settings - Fork 0
/
Copy pathcache.go
132 lines (109 loc) · 3.92 KB
/
cache.go
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
package cache
import (
"fmt"
"cosmossdk.io/store/cachekv"
"cosmossdk.io/store/types"
lru "github.com/hashicorp/golang-lru"
)
var (
_ types.CommitKVStore = (*CommitKVStoreCache)(nil)
_ types.MultiStorePersistentCache = (*CommitKVStoreCacheManager)(nil)
// DefaultCommitKVStoreCacheSize defines the persistent ARC cache size for a
// CommitKVStoreCache.
DefaultCommitKVStoreCacheSize uint = 1000
)
type (
// CommitKVStoreCache implements an inter-block (persistent) cache that wraps a
// CommitKVStore. Reads first hit the internal ARC (Adaptive Replacement Cache).
// During a cache miss, the read is delegated to the underlying CommitKVStore
// and cached. Deletes and writes always happen to both the cache and the
// CommitKVStore in a write-through manner. Caching performed in the
// CommitKVStore and below is completely irrelevant to this layer.
CommitKVStoreCache struct {
types.CommitKVStore
cache *lru.ARCCache
}
// CommitKVStoreCacheManager maintains a mapping from a StoreKey to a
// CommitKVStoreCache. Each CommitKVStore, per StoreKey, is meant to be used
// in an inter-block (persistent) manner and typically provided by a
// CommitMultiStore.
CommitKVStoreCacheManager struct {
cacheSize uint
caches map[string]types.CommitKVStore
}
)
func NewCommitKVStoreCache(store types.CommitKVStore, size uint) *CommitKVStoreCache {
cache, err := lru.NewARC(int(size))
if err != nil {
panic(fmt.Errorf("failed to create KVStore cache: %s", err))
}
return &CommitKVStoreCache{
CommitKVStore: store,
cache: cache,
}
}
func NewCommitKVStoreCacheManager(size uint) *CommitKVStoreCacheManager {
return &CommitKVStoreCacheManager{
cacheSize: size,
caches: make(map[string]types.CommitKVStore),
}
}
// GetStoreCache returns a Cache from the CommitStoreCacheManager for a given
// StoreKey. If no Cache exists for the StoreKey, then one is created and set.
// The returned Cache is meant to be used in a persistent manner.
func (cmgr *CommitKVStoreCacheManager) GetStoreCache(key types.StoreKey, store types.CommitKVStore) types.CommitKVStore {
if cmgr.caches[key.Name()] == nil {
cmgr.caches[key.Name()] = NewCommitKVStoreCache(store, cmgr.cacheSize)
}
return cmgr.caches[key.Name()]
}
// Unwrap returns the underlying CommitKVStore for a given StoreKey.
func (cmgr *CommitKVStoreCacheManager) Unwrap(key types.StoreKey) types.CommitKVStore {
if ckv, ok := cmgr.caches[key.Name()]; ok {
return ckv.(*CommitKVStoreCache).CommitKVStore
}
return nil
}
// Reset resets in the internal caches.
func (cmgr *CommitKVStoreCacheManager) Reset() {
// Clear the map.
// Please note that we are purposefully using the map clearing idiom.
// See https://github.com/cosmos/cosmos-sdk/issues/6681.
for key := range cmgr.caches {
delete(cmgr.caches, key)
}
}
// CacheWrap implements the CacheWrapper interface
func (ckv *CommitKVStoreCache) CacheWrap() types.CacheWrap {
return cachekv.NewStore(ckv)
}
// Get retrieves a value by key. It will first look in the write-through cache.
// If the value doesn't exist in the write-through cache, the query is delegated
// to the underlying CommitKVStore.
func (ckv *CommitKVStoreCache) Get(key []byte) []byte {
types.AssertValidKey(key)
keyStr := string(key)
valueI, ok := ckv.cache.Get(keyStr)
if ok {
// cache hit
return valueI.([]byte)
}
// cache miss; write to cache
value := ckv.CommitKVStore.Get(key)
ckv.cache.Add(keyStr, value)
return value
}
// Set inserts a key/value pair into both the write-through cache and the
// underlying CommitKVStore.
func (ckv *CommitKVStoreCache) Set(key, value []byte) {
types.AssertValidKey(key)
types.AssertValidValue(value)
ckv.cache.Add(string(key), value)
ckv.CommitKVStore.Set(key, value)
}
// Delete removes a key/value pair from both the write-through cache and the
// underlying CommitKVStore.
func (ckv *CommitKVStoreCache) Delete(key []byte) {
ckv.cache.Remove(string(key))
ckv.CommitKVStore.Delete(key)
}