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