github.com/m3db/m3@v1.5.1-0.20231129193456-75a402aa583b/src/dbnode/encoding/multi_reader_iterator.go (about) 1 // Copyright (c) 2016 Uber Technologies, Inc. 2 // 3 // Permission is hereby granted, free of charge, to any person obtaining a copy 4 // of this software and associated documentation files (the "Software"), to deal 5 // in the Software without restriction, including without limitation the rights 6 // to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 7 // copies of the Software, and to permit persons to whom the Software is 8 // furnished to do so, subject to the following conditions: 9 // 10 // The above copyright notice and this permission notice shall be included in 11 // all copies or substantial portions of the Software. 12 // 13 // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 14 // IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 15 // FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 16 // AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 17 // LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 18 // OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN 19 // THE SOFTWARE. 20 21 package encoding 22 23 import ( 24 "errors" 25 "time" 26 27 "github.com/m3db/m3/src/dbnode/namespace" 28 "github.com/m3db/m3/src/dbnode/ts" 29 "github.com/m3db/m3/src/dbnode/x/xio" 30 xtime "github.com/m3db/m3/src/x/time" 31 ) 32 33 var ( 34 errOutOfOrderIterator = errors.New("values are out of order from inner iterator") 35 ) 36 37 // multiReaderIterator is an iterator that iterates in order over a list of sets of 38 // internally ordered but not collectively in order readers, it also deduplicates datapoints. 39 type multiReaderIterator struct { 40 schemaDesc namespace.SchemaDescr 41 iters iterators 42 slicesIter xio.ReaderSliceOfSlicesIterator 43 iteratorAlloc ReaderIteratorAllocate 44 singleSlicesIter singleSlicesOfSlicesIterator 45 pool MultiReaderIteratorPool 46 err error 47 firstNext bool 48 closed bool 49 } 50 51 // NewMultiReaderIterator creates a new multi-reader iterator. 52 func NewMultiReaderIterator( 53 iteratorAlloc ReaderIteratorAllocate, 54 pool MultiReaderIteratorPool, 55 ) MultiReaderIterator { 56 it := &multiReaderIterator{pool: pool, iteratorAlloc: iteratorAlloc} 57 it.iters.closeIters = true 58 it.Reset(nil, 0, 0, nil) 59 return it 60 } 61 62 func (it *multiReaderIterator) Next() bool { 63 if !it.firstNext { 64 // When firstNext do not progress the first time 65 if !it.hasNext() { 66 return false 67 } 68 it.moveToNext() 69 } 70 it.firstNext = false 71 return it.hasNext() 72 } 73 74 func (it *multiReaderIterator) Current() (ts.Datapoint, xtime.Unit, ts.Annotation) { 75 return it.iters.current() 76 } 77 78 func (it *multiReaderIterator) hasError() bool { 79 return it.err != nil 80 } 81 82 func (it *multiReaderIterator) isClosed() bool { 83 return it.closed 84 } 85 86 func (it *multiReaderIterator) hasMore() bool { 87 return it.iters.len() > 0 || it.slicesIter != nil 88 } 89 90 func (it *multiReaderIterator) hasNext() bool { 91 return !it.hasError() && !it.isClosed() && it.hasMore() 92 } 93 94 func (it *multiReaderIterator) moveToNext() { 95 if it.iters.len() > 0 { 96 it.moveIteratorsToNext() 97 } 98 if it.iters.len() > 0 || it.hasError() { 99 // Still have valid iters or has error 100 return 101 } 102 103 // Move forward through slices of readers 104 if !it.slicesIter.Next() { 105 // No more readers, nil out so that hasMore reflects correctly 106 it.slicesIter.Close() 107 it.slicesIter = nil 108 return 109 } 110 111 // Add all readers to current iterators heap 112 currentLen, _, _ := it.slicesIter.CurrentReaders() 113 for i := 0; i < currentLen; i++ { 114 var ( 115 reader = it.slicesIter.CurrentReaderAt(i) 116 iter = it.iteratorAlloc(reader, it.schemaDesc) 117 ) 118 if iter.Next() { 119 // Only insert it if it has values 120 it.iters.push(iter) 121 } else { 122 err := iter.Err() 123 iter.Close() 124 if it.err == nil && err != nil { 125 it.err = err 126 } 127 } 128 } 129 130 if it.iters.len() == 0 && !it.hasError() { 131 // No iterators were added, move to next 132 it.moveToNext() 133 } 134 } 135 136 func (it *multiReaderIterator) moveIteratorsToNext() { 137 for { 138 prev := it.iters.at() 139 next, err := it.iters.moveToValidNext() 140 if it.err == nil && err != nil { 141 it.err = err 142 return 143 } 144 if err != nil || !next { 145 return 146 } 147 148 curr := it.iters.at() 149 if curr != prev { 150 return 151 } 152 153 // Dedupe by continuing 154 } 155 } 156 157 func (it *multiReaderIterator) Err() error { 158 return it.err 159 } 160 161 func (it *multiReaderIterator) Readers() xio.ReaderSliceOfSlicesIterator { 162 return it.slicesIter 163 } 164 165 func (it *multiReaderIterator) Reset( 166 blocks []xio.SegmentReader, 167 start xtime.UnixNano, 168 blockSize time.Duration, 169 descr namespace.SchemaDescr, 170 ) { 171 it.singleSlicesIter.readers = blocks 172 it.singleSlicesIter.firstNext = true 173 it.singleSlicesIter.closed = false 174 it.singleSlicesIter.start = start 175 it.singleSlicesIter.blockSize = blockSize 176 it.ResetSliceOfSlices(&it.singleSlicesIter, descr) 177 } 178 179 func (it *multiReaderIterator) ResetSliceOfSlices(slicesIter xio.ReaderSliceOfSlicesIterator, descr namespace.SchemaDescr) { 180 it.schemaDesc = descr 181 it.iters.reset() 182 it.slicesIter = slicesIter 183 it.err = nil 184 it.firstNext = true 185 it.closed = false 186 // Try moveToNext to load values for calls to Current before Next 187 it.moveToNext() 188 } 189 190 func (it *multiReaderIterator) Schema() namespace.SchemaDescr { 191 return it.schemaDesc 192 } 193 194 func (it *multiReaderIterator) Close() { 195 if it.isClosed() { 196 return 197 } 198 it.closed = true 199 it.iters.reset() 200 if it.slicesIter != nil { 201 it.slicesIter.Close() 202 } 203 it.slicesIter = nil 204 if it.pool != nil { 205 it.pool.Put(it) 206 } 207 } 208 209 type singleSlicesOfSlicesIterator struct { 210 readers []xio.SegmentReader 211 firstNext bool 212 closed bool 213 start xtime.UnixNano 214 blockSize time.Duration 215 } 216 217 func (it *singleSlicesOfSlicesIterator) Next() bool { 218 if !it.firstNext || it.closed { 219 return false 220 } 221 it.firstNext = false 222 return true 223 } 224 225 func (it *singleSlicesOfSlicesIterator) CurrentReaders() (int, xtime.UnixNano, time.Duration) { 226 return len(it.readers), it.start, it.blockSize 227 } 228 229 func (it *singleSlicesOfSlicesIterator) CurrentReaderAt(idx int) xio.BlockReader { 230 return xio.BlockReader{ 231 SegmentReader: it.readers[idx], 232 Start: it.start, 233 BlockSize: it.blockSize, 234 } 235 } 236 237 func (it *singleSlicesOfSlicesIterator) Close() { 238 if it.closed { 239 return 240 } 241 it.closed = true 242 } 243 244 func (it *singleSlicesOfSlicesIterator) Size() (int, error) { 245 size := 0 246 for _, reader := range it.readers { 247 seg, err := reader.Segment() 248 if err != nil { 249 return 0, err 250 } 251 size += seg.Len() 252 } 253 return size, nil 254 } 255 256 func (it *singleSlicesOfSlicesIterator) RewindToIndex(idx int) { 257 it.firstNext = idx <= 0 258 } 259 260 func (it *singleSlicesOfSlicesIterator) Index() int { 261 if it.firstNext { 262 return 0 263 } 264 return 1 265 }