github.com/m3db/m3@v1.5.1-0.20231129193456-75a402aa583b/src/dbnode/client/reader_slice_of_slices_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 client 22 23 import ( 24 "time" 25 26 "github.com/m3db/m3/src/dbnode/generated/thrift/rpc" 27 "github.com/m3db/m3/src/dbnode/ts" 28 "github.com/m3db/m3/src/dbnode/x/xio" 29 "github.com/m3db/m3/src/x/checked" 30 xtime "github.com/m3db/m3/src/x/time" 31 ) 32 33 var timeZero = xtime.UnixNano(0) 34 35 type readerSliceOfSlicesIterator struct { 36 segments []*rpc.Segments 37 blockReaders []xio.BlockReader 38 idx int 39 closed bool 40 pool *readerSliceOfSlicesIteratorPool 41 } 42 43 // NewReaderSliceOfSlicesIterator returns new reader slice of slices iterator. 44 func NewReaderSliceOfSlicesIterator( 45 segments []*rpc.Segments, 46 pool *readerSliceOfSlicesIteratorPool, 47 ) *readerSliceOfSlicesIterator { 48 it := &readerSliceOfSlicesIterator{pool: pool} 49 it.Reset(segments) 50 return it 51 } 52 53 func (it *readerSliceOfSlicesIterator) Next() bool { 54 if !(it.idx+1 < len(it.segments)) { 55 return false 56 } 57 it.idx++ 58 59 // Extend block readers if not enough available 60 currLen, start, blockSize := it.CurrentReaders() 61 if len(it.blockReaders) < currLen { 62 diff := currLen - len(it.blockReaders) 63 for i := 0; i < diff; i++ { 64 seg := ts.NewSegment(nil, nil, 0, ts.FinalizeNone) 65 sr := xio.NewSegmentReader(seg) 66 br := xio.BlockReader{ 67 SegmentReader: sr, 68 Start: start, 69 BlockSize: blockSize, 70 } 71 it.blockReaders = append(it.blockReaders, br) 72 } 73 } 74 75 // Set the segment readers to reader from current segment pieces 76 segment := it.segments[it.idx] 77 if segment.Merged != nil { 78 it.resetReader(it.blockReaders[0], segment.Merged) 79 } else { 80 for i := 0; i < currLen; i++ { 81 it.resetReader(it.blockReaders[i], segment.Unmerged[i]) 82 } 83 } 84 85 return true 86 } 87 88 func (it *readerSliceOfSlicesIterator) resetReader( 89 r xio.BlockReader, 90 seg *rpc.Segment, 91 ) { 92 rseg, err := r.Segment() 93 _, start, end := it.CurrentReaders() 94 95 if err != nil { 96 r.ResetWindowed(ts.Segment{}, start, end) 97 return 98 } 99 100 var ( 101 head = rseg.Head 102 tail = rseg.Tail 103 ) 104 if head == nil { 105 head = checked.NewBytes(seg.Head, nil) 106 head.IncRef() 107 } else { 108 head.Reset(seg.Head) 109 } 110 if tail == nil { 111 tail = checked.NewBytes(seg.Tail, nil) 112 tail.IncRef() 113 } else { 114 tail.Reset(seg.Tail) 115 } 116 117 var checksum uint32 118 if seg.Checksum != nil { 119 checksum = uint32(*seg.Checksum) 120 } 121 122 newSeg := ts.NewSegment(head, tail, checksum, ts.FinalizeNone) 123 r.ResetWindowed(newSeg, start, end) 124 } 125 126 func (it *readerSliceOfSlicesIterator) currentLen() int { 127 if it.segments[it.idx].Merged != nil { 128 return 1 129 } 130 return len(it.segments[it.idx].Unmerged) 131 } 132 133 func (it *readerSliceOfSlicesIterator) CurrentReaders() (int, xtime.UnixNano, time.Duration) { 134 segments := it.segments[it.idx] 135 if segments.Merged != nil { 136 return 1, timeConvert(segments.Merged.StartTime), durationConvert(segments.Merged.BlockSize) 137 } 138 unmerged := it.currentLen() 139 if unmerged == 0 { 140 return 0, timeZero, 0 141 } 142 return unmerged, timeConvert(segments.Unmerged[0].StartTime), durationConvert(segments.Unmerged[0].BlockSize) 143 } 144 145 func timeConvert(ticks *int64) xtime.UnixNano { 146 if ticks == nil { 147 return timeZero 148 } 149 150 return xtime.UnixNano(*ticks) 151 } 152 153 func durationConvert(duration *int64) time.Duration { 154 if duration == nil { 155 return 0 156 } 157 return xtime.FromNormalizedDuration(*duration, time.Nanosecond) 158 } 159 160 func (it *readerSliceOfSlicesIterator) CurrentReaderAt(idx int) xio.BlockReader { 161 if idx >= it.currentLen() { 162 return xio.EmptyBlockReader 163 } 164 return it.blockReaders[idx] 165 } 166 167 func (it *readerSliceOfSlicesIterator) Close() { 168 if it.closed { 169 return 170 } 171 it.closed = true 172 // Release any refs to segments 173 it.segments = nil 174 // Release any refs to segment byte slices 175 for i := range it.blockReaders { 176 seg, err := it.blockReaders[i].Segment() 177 if err != nil { 178 continue 179 } 180 if seg.Head != nil { 181 seg.Head.Reset(nil) 182 } 183 if seg.Tail != nil { 184 seg.Tail.Reset(nil) 185 } 186 } 187 if pool := it.pool; pool != nil { 188 pool.Put(it) 189 } 190 } 191 192 func (it *readerSliceOfSlicesIterator) Reset(segments []*rpc.Segments) { 193 it.segments = segments 194 it.resetIndex() 195 it.closed = false 196 } 197 198 func (it *readerSliceOfSlicesIterator) Size() (int, error) { 199 size := 0 200 for _, reader := range it.blockReaders { 201 seg, err := reader.Segment() 202 if err != nil { 203 return 0, err 204 } 205 size += seg.Len() 206 } 207 return size, nil 208 } 209 210 func (it *readerSliceOfSlicesIterator) RewindToIndex(idx int) { 211 it.idx = idx 212 } 213 214 func (it *readerSliceOfSlicesIterator) Index() int { 215 return it.idx 216 } 217 218 func (it *readerSliceOfSlicesIterator) resetIndex() { 219 it.idx = -1 220 }