github.com/dolthub/dolt/go@v0.40.5-0.20240520175717-68db7794bea6/store/prolly/tuple_range_iter.go (about) 1 // Copyright 2021 Dolthub, Inc. 2 // 3 // Licensed under the Apache License, Version 2.0 (the "License"); 4 // you may not use this file except in compliance with the License. 5 // You may obtain a copy of the License at 6 // 7 // http://www.apache.org/licenses/LICENSE-2.0 8 // 9 // Unless required by applicable law or agreed to in writing, software 10 // distributed under the License is distributed on an "AS IS" BASIS, 11 // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 12 // See the License for the specific language governing permissions and 13 // limitations under the License. 14 15 package prolly 16 17 import ( 18 "context" 19 "io" 20 21 "github.com/dolthub/dolt/go/store/prolly/tree" 22 "github.com/dolthub/dolt/go/store/skip" 23 "github.com/dolthub/dolt/go/store/val" 24 ) 25 26 type MapIter tree.KvIter[val.Tuple, val.Tuple] 27 28 var _ MapIter = &mutableMapIter[val.Tuple, val.Tuple, val.TupleDesc]{} 29 var _ MapIter = &tree.OrderedTreeIter[val.Tuple, val.Tuple]{} 30 31 type rangeIter[K, V ~[]byte] interface { 32 Iterate(ctx context.Context) error 33 Current() (key K, value V) 34 } 35 36 var _ rangeIter[val.Tuple, val.Tuple] = &tree.OrderedTreeIter[val.Tuple, val.Tuple]{} 37 var _ rangeIter[val.Tuple, val.Tuple] = &memRangeIter{} 38 var _ rangeIter[val.Tuple, val.Tuple] = emptyIter{} 39 40 // mutableMapIter iterates over a Range of Tuples. 41 type mutableMapIter[K, V ~[]byte, O tree.Ordering[K]] struct { 42 memory rangeIter[K, V] 43 prolly *tree.OrderedTreeIter[K, V] 44 order O 45 } 46 47 // Next returns the next pair of Tuples in the Range, or io.EOF if the iter is done. 48 func (it mutableMapIter[K, V, O]) Next(ctx context.Context) (key K, value V, err error) { 49 for { 50 mk, mv := it.memory.Current() 51 pk, pv := it.prolly.Current() 52 53 if mk == nil && pk == nil { 54 // range is exhausted 55 return nil, nil, io.EOF 56 } 57 58 cmp := it.compareKeys(pk, mk) 59 switch { 60 case cmp < 0: 61 key, value = pk, pv 62 if err = it.prolly.Iterate(ctx); err != nil { 63 return nil, nil, err 64 } 65 66 case cmp > 0: 67 key, value = mk, mv 68 if err = it.memory.Iterate(ctx); err != nil { 69 return nil, nil, err 70 } 71 72 case cmp == 0: 73 // |it.memory| wins ties 74 key, value = mk, mv 75 if err = it.memory.Iterate(ctx); err != nil { 76 return nil, nil, err 77 } 78 if err = it.prolly.Iterate(ctx); err != nil { 79 return nil, nil, err 80 } 81 } 82 83 if key != nil && value == nil { 84 continue // pending delete 85 } 86 87 return key, value, nil 88 } 89 } 90 91 func (it mutableMapIter[K, V, O]) currentKeys() (memKey, proKey K) { 92 if it.memory != nil { 93 memKey, _ = it.memory.Current() 94 } 95 if it.prolly != nil { 96 proKey, _ = it.prolly.Current() 97 } 98 return 99 } 100 101 func (it mutableMapIter[K, V, O]) compareKeys(memKey, proKey K) int { 102 if memKey == nil { 103 return 1 104 } 105 if proKey == nil { 106 return -1 107 } 108 return it.order.Compare(memKey, proKey) 109 } 110 111 func memIterFromRange(list *skip.List, rng Range) *memRangeIter { 112 // use the lower bound of |rng| to construct a skip.ListIter 113 iter := list.GetIterFromSeekFn(skipSearchFromRange(rng)) 114 115 // enforce range start 116 var key val.Tuple 117 for { 118 key, _ = iter.Current() 119 if key == nil || rng.aboveStart(key) { 120 break // |i| inside |rng| 121 } 122 iter.Advance() 123 } 124 125 // enforce range end 126 if key == nil || !rng.belowStop(key) { 127 iter = nil 128 } 129 130 return &memRangeIter{ 131 iter: iter, 132 rng: rng, 133 } 134 } 135 136 // skipSearchFromRange is a skip.SeekFn used to initialize 137 // a skip.List iterator for a given Range. The skip.SearchFn 138 // returns true if the iter being initialized is not yet 139 // within the bounds of Range |rng|. 140 func skipSearchFromRange(rng Range) skip.SeekFn { 141 return func(nodeKey []byte) bool { 142 if nodeKey == nil { 143 return false 144 } 145 return !rng.aboveStart(nodeKey) 146 } 147 } 148 149 // todo(andy): generalize Range iteration and consolidate this 150 // iterator with orderedListIter[K, V] in ordered_map.go. 151 // This is not currently possible due to Range checking logic 152 // that is specific to val.Tuple. 153 type memRangeIter struct { 154 iter *skip.ListIter 155 rng Range 156 } 157 158 // Current returns the iter's current Tuple pair, or nil Tuples 159 // if the iter has exhausted its range, it will 160 func (it *memRangeIter) Current() (key, value val.Tuple) { 161 // |it.iter| is set to nil when its range is exhausted 162 if it.iter != nil { 163 key, value = it.iter.Current() 164 } 165 return 166 } 167 168 // Iterate progresses the iter inside its range. 169 func (it *memRangeIter) Iterate(context.Context) (err error) { 170 for { 171 it.iter.Advance() 172 173 k, _ := it.Current() 174 if k == nil || !it.rng.belowStop(k) { 175 it.iter = nil // range exhausted 176 } 177 178 return 179 } 180 } 181 182 type emptyIter struct{} 183 184 func (e emptyIter) Next(context.Context) (val.Tuple, val.Tuple, error) { 185 return nil, nil, io.EOF 186 } 187 188 func (e emptyIter) Iterate(ctx context.Context) (err error) { return } 189 190 func (e emptyIter) Current() (key, value val.Tuple) { return } 191 192 type filteredIter struct { 193 iter MapIter 194 rng Range 195 } 196 197 var _ MapIter = filteredIter{} 198 199 func (f filteredIter) Next(ctx context.Context) (k, v val.Tuple, err error) { 200 for { 201 k, v, err = f.iter.Next(ctx) 202 if err != nil { 203 return nil, nil, err 204 } 205 if !f.rng.Matches(k) { 206 continue 207 } 208 return 209 } 210 }