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