github.com/iotexproject/iotex-core@v1.14.1-rc1/db/batch/kv_cache.go (about) 1 // Copyright (c) 2019 IoTeX Foundation 2 // This source code is provided 'as is' and no warranties are given as to title or non-infringement, merchantability 3 // or fitness for purpose and, to the extent permitted by law, all liability for your use of the code is disclaimed. 4 // This source code is governed by Apache License 2.0 that can be found in the LICENSE file. 5 6 package batch 7 8 type ( 9 // KVStoreCache is a local cache of batched <k, v> for fast query 10 KVStoreCache interface { 11 // Read retrieves a record 12 Read(*kvCacheKey) ([]byte, error) 13 // Write puts a record into cache 14 Write(*kvCacheKey, []byte) 15 // WriteIfNotExist puts a record into cache only if it doesn't exist, otherwise return ErrAlreadyExist 16 WriteIfNotExist(*kvCacheKey, []byte) error 17 // Evict deletes a record from cache 18 Evict(*kvCacheKey) 19 // Clear clear the cache 20 Clear() 21 // Append appends caches 22 Append(...KVStoreCache) error 23 } 24 25 // kvCacheKey is the key for 2D Map cache 26 kvCacheKey struct { 27 key1 string 28 key2 string 29 } 30 kvCacheValue []int 31 32 node struct { 33 value []byte 34 deleted bool 35 } 36 37 // kvCache implements KVStoreCache interface 38 kvCache struct { 39 cache map[string]map[string]*node // local cache of batched <k, v> for fast query 40 } 41 ) 42 43 func newkvCacheValue(v []int) *kvCacheValue { 44 return (*kvCacheValue)(&v) 45 } 46 47 func (kv *kvCacheValue) reset() { 48 ([]int)(*kv)[0] = 0 49 *kv = (*kv)[:1] 50 } 51 52 func (kv *kvCacheValue) pop() { 53 *kv = (*kv)[:kv.len()-1] 54 } 55 func (kv *kvCacheValue) get() []int { 56 return ([]int)(*kv) 57 } 58 59 func (kv *kvCacheValue) getAt(i int) int { 60 return ([]int)(*kv)[i] 61 } 62 63 func (kv *kvCacheValue) append(v int) { 64 *kv = append(*kv, v) 65 } 66 67 func (kv *kvCacheValue) len() int { 68 return len(*kv) 69 } 70 71 func (kv *kvCacheValue) last() int { 72 return (*kv)[len(*kv)-1] 73 } 74 75 // NewKVCache returns a KVCache 76 func NewKVCache() KVStoreCache { 77 return &kvCache{ 78 cache: make(map[string]map[string]*node), 79 } 80 } 81 82 // Read retrieves a record 83 func (c *kvCache) Read(key *kvCacheKey) ([]byte, error) { 84 if ns, ok := c.cache[key.key1]; ok { 85 if node, ok := ns[key.key2]; ok { 86 if node.deleted { 87 return nil, ErrAlreadyDeleted 88 } 89 return node.value, nil 90 } 91 } 92 return nil, ErrNotExist 93 } 94 95 // Write puts a record into cache 96 func (c *kvCache) Write(key *kvCacheKey, v []byte) { 97 if _, ok := c.cache[key.key1]; !ok { 98 c.cache[key.key1] = make(map[string]*node) 99 } 100 c.cache[key.key1][key.key2] = &node{ 101 value: v, 102 deleted: false, 103 } 104 } 105 106 // WriteIfNotExist puts a record into cache only if it doesn't exist, otherwise return ErrAlreadyExist 107 func (c *kvCache) WriteIfNotExist(key *kvCacheKey, v []byte) error { 108 if _, ok := c.cache[key.key1]; !ok { 109 c.cache[key.key1] = make(map[string]*node) 110 } 111 if node, ok := c.cache[key.key1][key.key2]; ok && !node.deleted { 112 return ErrAlreadyExist 113 } 114 c.cache[key.key1][key.key2] = &node{ 115 value: v, 116 deleted: false, 117 } 118 return nil 119 } 120 121 // Evict deletes a record from cache 122 func (c *kvCache) Evict(key *kvCacheKey) { 123 if _, ok := c.cache[key.key1]; !ok { 124 c.cache[key.key1] = make(map[string]*node) 125 } 126 c.cache[key.key1][key.key2] = &node{ 127 value: nil, 128 deleted: true, 129 } 130 } 131 132 // Clear clear the cache 133 func (c *kvCache) Clear() { 134 c.cache = make(map[string]map[string]*node) 135 } 136 137 func (c *kvCache) Append(caches ...KVStoreCache) error { 138 // c should be written in order 139 for _, cc := range caches { 140 cc, ok := cc.(*kvCache) 141 if !ok { 142 return ErrUnexpectedType 143 } 144 for key1, ns := range cc.cache { 145 if _, ok := c.cache[key1]; !ok { 146 c.cache[key1] = make(map[string]*node) 147 } 148 for key2, node := range ns { 149 c.cache[key1][key2] = node 150 } 151 } 152 } 153 return nil 154 }