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