github.com/hyperledger/burrow@v0.34.5-0.20220512172541-77f09336001d/forensics/storage/kvcache.go (about) 1 package storage 2 3 import ( 4 "bytes" 5 "sort" 6 "sync" 7 8 "github.com/hyperledger/burrow/storage" 9 ) 10 11 type KVCache struct { 12 sync.RWMutex 13 cache map[string]valueInfo 14 // Store a sortable slice of keys to avoid always hitting 15 keys byteSlices 16 } 17 18 type byteSlices [][]byte 19 20 func (bss byteSlices) Len() int { 21 return len(bss) 22 } 23 24 func (bss byteSlices) Less(i, j int) bool { 25 return bytes.Compare(bss[i], bss[j]) == -1 26 } 27 28 func (bss byteSlices) Swap(i, j int) { 29 bss[i], bss[j] = bss[j], bss[i] 30 } 31 32 type valueInfo struct { 33 value []byte 34 deleted bool 35 } 36 37 // Creates an in-memory cache wrapping a map that stores the provided tombstone value for deleted keys 38 func NewKVCache() *KVCache { 39 return &KVCache{ 40 cache: make(map[string]valueInfo), 41 } 42 } 43 44 func (kvc *KVCache) Info(key []byte) (value []byte, deleted bool) { 45 kvc.RLock() 46 defer kvc.RUnlock() 47 vi := kvc.cache[string(key)] 48 return vi.value, vi.deleted 49 } 50 51 func (kvc *KVCache) Get(key []byte) []byte { 52 kvc.RLock() 53 defer kvc.RUnlock() 54 return kvc.cache[string(key)].value 55 } 56 57 func (kvc *KVCache) Has(key []byte) bool { 58 kvc.RLock() 59 defer kvc.RUnlock() 60 vi, ok := kvc.cache[string(key)] 61 return ok && !vi.deleted 62 } 63 64 func (kvc *KVCache) Set(key, value []byte) { 65 kvc.Lock() 66 defer kvc.Unlock() 67 skey := string(key) 68 vi, ok := kvc.cache[skey] 69 if !ok { 70 // first Set/Delete 71 kvc.keys = append(kvc.keys, key) 72 // This slows down write quite a lot but does give faster repeated iterations 73 // kvc.keys = insertKey(kvc.keys, key) 74 } 75 vi.deleted = false 76 vi.value = value 77 kvc.cache[skey] = vi 78 } 79 80 func (kvc *KVCache) Delete(key []byte) { 81 kvc.Lock() 82 defer kvc.Unlock() 83 skey := string(key) 84 vi, ok := kvc.cache[skey] 85 if !ok { 86 // first Set/Delete 87 kvc.keys = append(kvc.keys, key) 88 // This slows down write quite a lot but does give faster repeated iterations 89 // kvc.keys = insertKey(kvc.keys, key) 90 } 91 vi.deleted = true 92 vi.value = nil 93 kvc.cache[skey] = vi 94 } 95 96 func (kvc *KVCache) Iterator(low, high []byte) storage.KVIterator { 97 kvc.RLock() 98 defer kvc.RUnlock() 99 low, high = storage.NormaliseDomain(low, high) 100 return kvc.newIterator(low, high, false) 101 } 102 103 func (kvc *KVCache) ReverseIterator(low, high []byte) storage.KVIterator { 104 kvc.RLock() 105 defer kvc.RUnlock() 106 low, high = storage.NormaliseDomain(low, high) 107 return kvc.newIterator(low, high, true) 108 } 109 110 // Writes contents of cache to backend without flushing the cache 111 func (kvc *KVCache) WriteTo(writer storage.KVWriter) { 112 kvc.Lock() 113 defer kvc.Unlock() 114 for k, vi := range kvc.cache { 115 kb := []byte(k) 116 if vi.deleted { 117 writer.Delete(kb) 118 } else { 119 writer.Set(kb, vi.value) 120 } 121 } 122 } 123 124 func (kvc *KVCache) Reset() { 125 kvc.Lock() 126 defer kvc.Unlock() 127 kvc.cache = make(map[string]valueInfo) 128 } 129 130 func (kvc *KVCache) sortedKeysInDomain(low, high []byte) [][]byte { 131 // Sort keys (which may be partially sorted if we have iterated before) 132 sort.Sort(kvc.keys) 133 sortedKeys := kvc.keys 134 // Attempt to seek to the first key in the range 135 startIndex := len(kvc.keys) 136 for i, key := range sortedKeys { 137 // !(key < start) => key >= start then include (inclusive start) 138 if storage.CompareKeys(key, low) != -1 { 139 startIndex = i 140 break 141 } 142 } 143 // Reslice to beginning of range or end if not found 144 sortedKeys = sortedKeys[startIndex:] 145 for i, key := range sortedKeys { 146 // !(key < end) => key >= end then exclude (exclusive end) 147 if storage.CompareKeys(key, high) != -1 { 148 sortedKeys = sortedKeys[:i] 149 break 150 } 151 } 152 return sortedKeys 153 } 154 155 func (kvc *KVCache) newIterator(start, end []byte, reverse bool) *KVCacheIterator { 156 keys := kvc.sortedKeysInDomain(start, end) 157 kvi := &KVCacheIterator{ 158 start: start, 159 end: end, 160 keys: keys, 161 cache: kvc.cache, 162 reverse: reverse, 163 } 164 return kvi 165 } 166 167 type KVCacheIterator struct { 168 cache map[string]valueInfo 169 start []byte 170 end []byte 171 keys [][]byte 172 keyIndex int 173 reverse bool 174 } 175 176 func (kvi *KVCacheIterator) Domain() ([]byte, []byte) { 177 return kvi.start, kvi.end 178 } 179 180 func (kvi *KVCacheIterator) Info() (key, value []byte, deleted bool) { 181 key = kvi.keys[kvi.sliceIndex()] 182 vi := kvi.cache[string(key)] 183 return key, vi.value, vi.deleted 184 } 185 186 func (kvi *KVCacheIterator) Key() []byte { 187 return []byte(kvi.keys[kvi.sliceIndex()]) 188 } 189 190 func (kvi *KVCacheIterator) Value() []byte { 191 return kvi.cache[string(kvi.keys[kvi.sliceIndex()])].value 192 } 193 194 func (kvi *KVCacheIterator) Next() { 195 if !kvi.Valid() { 196 panic("KVCacheIterator.Next() called on invalid iterator") 197 } 198 kvi.keyIndex++ 199 } 200 201 func (kvi *KVCacheIterator) Valid() bool { 202 return kvi.keyIndex < len(kvi.keys) 203 } 204 205 func (kvi *KVCacheIterator) Close() error { 206 return nil 207 } 208 209 func (kvi *KVCacheIterator) Error() error { return nil } 210 211 func (kvi *KVCacheIterator) sliceIndex() int { 212 if kvi.reverse { 213 //reflect 214 return len(kvi.keys) - 1 - kvi.keyIndex 215 } 216 return kvi.keyIndex 217 }