github.com/fibonacci-chain/fbc@v0.0.0-20231124064014-c7636198c1e9/libs/cosmos-sdk/store/cachekv/mergeiterator.go (about) 1 package cachekv 2 3 import ( 4 "bytes" 5 "errors" 6 7 "github.com/fibonacci-chain/fbc/libs/cosmos-sdk/store/types" 8 ) 9 10 // cacheMergeIterator merges a parent Iterator and a cache Iterator. 11 // The cache iterator may return nil keys to signal that an item 12 // had been deleted (but not deleted in the parent). 13 // If the cache iterator has the same key as the parent, the 14 // cache shadows (overrides) the parent. 15 // 16 // TODO: Optimize by memoizing. 17 type cacheMergeIterator struct { 18 parent types.Iterator 19 cache types.Iterator 20 ascending bool 21 } 22 23 var _ types.Iterator = (*cacheMergeIterator)(nil) 24 25 func newCacheMergeIterator(parent, cache types.Iterator, ascending bool) *cacheMergeIterator { 26 iter := &cacheMergeIterator{ 27 parent: parent, 28 cache: cache, 29 ascending: ascending, 30 } 31 return iter 32 } 33 34 // Domain implements Iterator. 35 // If the domains are different, returns the union. 36 func (iter *cacheMergeIterator) Domain() (start, end []byte) { 37 startP, endP := iter.parent.Domain() 38 startC, endC := iter.cache.Domain() 39 if iter.compare(startP, startC) < 0 { 40 start = startP 41 } else { 42 start = startC 43 } 44 if iter.compare(endP, endC) < 0 { 45 end = endC 46 } else { 47 end = endP 48 } 49 return start, end 50 } 51 52 // Valid implements Iterator. 53 func (iter *cacheMergeIterator) Valid() bool { 54 return iter.skipUntilExistsOrInvalid() 55 } 56 57 // Next implements Iterator 58 func (iter *cacheMergeIterator) Next() { 59 iter.skipUntilExistsOrInvalid() 60 iter.assertValid() 61 62 // If parent is invalid, get the next cache item. 63 if !iter.parent.Valid() { 64 iter.cache.Next() 65 return 66 } 67 68 // If cache is invalid, get the next parent item. 69 if !iter.cache.Valid() { 70 iter.parent.Next() 71 return 72 } 73 74 // Both are valid. Compare keys. 75 keyP, keyC := iter.parent.Key(), iter.cache.Key() 76 switch iter.compare(keyP, keyC) { 77 case -1: // parent < cache 78 iter.parent.Next() 79 case 0: // parent == cache 80 iter.parent.Next() 81 iter.cache.Next() 82 case 1: // parent > cache 83 iter.cache.Next() 84 } 85 } 86 87 // Key implements Iterator 88 func (iter *cacheMergeIterator) Key() []byte { 89 iter.skipUntilExistsOrInvalid() 90 iter.assertValid() 91 92 // If parent is invalid, get the cache key. 93 if !iter.parent.Valid() { 94 return iter.cache.Key() 95 } 96 97 // If cache is invalid, get the parent key. 98 if !iter.cache.Valid() { 99 return iter.parent.Key() 100 } 101 102 // Both are valid. Compare keys. 103 keyP, keyC := iter.parent.Key(), iter.cache.Key() 104 cmp := iter.compare(keyP, keyC) 105 switch cmp { 106 case -1: // parent < cache 107 return keyP 108 case 0: // parent == cache 109 return keyP 110 case 1: // parent > cache 111 return keyC 112 default: 113 panic("invalid compare result") 114 } 115 } 116 117 // Value implements Iterator 118 func (iter *cacheMergeIterator) Value() []byte { 119 iter.skipUntilExistsOrInvalid() 120 iter.assertValid() 121 122 // If parent is invalid, get the cache value. 123 if !iter.parent.Valid() { 124 return iter.cache.Value() 125 } 126 127 // If cache is invalid, get the parent value. 128 if !iter.cache.Valid() { 129 return iter.parent.Value() 130 } 131 132 // Both are valid. Compare keys. 133 keyP, keyC := iter.parent.Key(), iter.cache.Key() 134 cmp := iter.compare(keyP, keyC) 135 switch cmp { 136 case -1: // parent < cache 137 return iter.parent.Value() 138 case 0: // parent == cache 139 return iter.cache.Value() 140 case 1: // parent > cache 141 return iter.cache.Value() 142 default: 143 panic("invalid comparison result") 144 } 145 } 146 147 // Close implements Iterator 148 func (iter *cacheMergeIterator) Close() { 149 iter.parent.Close() 150 iter.cache.Close() 151 } 152 153 // Error returns an error if the cacheMergeIterator is invalid defined by the 154 // Valid method. 155 func (iter *cacheMergeIterator) Error() error { 156 if !iter.Valid() { 157 return errors.New("invalid cacheMergeIterator") 158 } 159 160 return nil 161 } 162 163 // If not valid, panics. 164 // NOTE: May have side-effect of iterating over cache. 165 func (iter *cacheMergeIterator) assertValid() { 166 if err := iter.Error(); err != nil { 167 panic(err) 168 } 169 } 170 171 // Like bytes.Compare but opposite if not ascending. 172 func (iter *cacheMergeIterator) compare(a, b []byte) int { 173 if iter.ascending { 174 return bytes.Compare(a, b) 175 } 176 return bytes.Compare(a, b) * -1 177 } 178 179 // Skip all delete-items from the cache w/ `key < until`. After this function, 180 // current cache item is a non-delete-item, or `until <= key`. 181 // If the current cache item is not a delete item, does nothing. 182 // If `until` is nil, there is no limit, and cache may end up invalid. 183 // CONTRACT: cache is valid. 184 func (iter *cacheMergeIterator) skipCacheDeletes(until []byte) { 185 for iter.cache.Valid() && 186 iter.cache.Value() == nil && 187 (until == nil || iter.compare(iter.cache.Key(), until) < 0) { 188 189 iter.cache.Next() 190 } 191 } 192 193 // Fast forwards cache (or parent+cache in case of deleted items) until current 194 // item exists, or until iterator becomes invalid. 195 // Returns whether the iterator is valid. 196 func (iter *cacheMergeIterator) skipUntilExistsOrInvalid() bool { 197 for { 198 // If parent is invalid, fast-forward cache. 199 if !iter.parent.Valid() { 200 iter.skipCacheDeletes(nil) 201 return iter.cache.Valid() 202 } 203 // Parent is valid. 204 205 if !iter.cache.Valid() { 206 return true 207 } 208 // Parent is valid, cache is valid. 209 210 // Compare parent and cache. 211 keyP := iter.parent.Key() 212 keyC := iter.cache.Key() 213 switch iter.compare(keyP, keyC) { 214 215 case -1: // parent < cache. 216 return true 217 218 case 0: // parent == cache. 219 220 // Skip over if cache item is a delete. 221 valueC := iter.cache.Value() 222 if valueC == nil { 223 iter.parent.Next() 224 iter.cache.Next() 225 continue 226 } 227 // Cache is not a delete. 228 229 return true // cache exists. 230 231 case 1: // cache < parent 232 233 // Skip over if cache item is a delete. 234 valueC := iter.cache.Value() 235 if valueC == nil { 236 iter.skipCacheDeletes(keyP) 237 continue 238 } 239 // Cache is not a delete. 240 241 return true // cache exists. 242 } 243 } 244 }