github.com/m3db/m3@v1.5.0/src/query/storage/m3/encoded_series_iterator.go (about) 1 // Copyright (c) 2018 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 m3 22 23 import ( 24 "fmt" 25 "time" 26 27 "github.com/m3db/m3/src/dbnode/encoding" 28 "github.com/m3db/m3/src/query/block" 29 "github.com/m3db/m3/src/query/ts" 30 "github.com/m3db/m3/src/query/util" 31 ) 32 33 // NewEncodedSeriesIter creates a new encoded series iterator. 34 func NewEncodedSeriesIter( 35 meta block.Metadata, 36 seriesMetas []block.SeriesMeta, 37 seriesIters []encoding.SeriesIterator, 38 instrumented bool, 39 ) block.SeriesIter { 40 return &encodedSeriesIter{ 41 idx: -1, 42 meta: meta, 43 seriesMeta: seriesMetas, 44 seriesIters: seriesIters, 45 instrumented: instrumented, 46 } 47 } 48 49 type encodedSeriesIter struct { 50 idx int 51 err error 52 meta block.Metadata 53 datapoints ts.Datapoints 54 series block.UnconsolidatedSeries 55 seriesMeta []block.SeriesMeta 56 seriesIters []encoding.SeriesIterator 57 instrumented bool 58 } 59 60 func (it *encodedSeriesIter) Current() block.UnconsolidatedSeries { 61 return it.series 62 } 63 64 func (it *encodedSeriesIter) Err() error { 65 return it.err 66 } 67 68 func (it *encodedSeriesIter) Next() bool { 69 if it.err != nil { 70 return false 71 } 72 73 it.idx++ 74 next := it.idx < len(it.seriesIters) 75 if !next { 76 return false 77 } 78 79 iter := it.seriesIters[it.idx] 80 if it.datapoints == nil { 81 it.datapoints = make(ts.Datapoints, 0, initBlockReplicaLength) 82 } else { 83 it.datapoints = it.datapoints[:0] 84 } 85 86 var ( 87 decodeDuration time.Duration 88 decodeStart time.Time 89 ) 90 if it.instrumented { 91 decodeStart = time.Now() 92 } 93 94 for iter.Next() { 95 dp, _, _ := iter.Current() 96 it.datapoints = append(it.datapoints, 97 ts.Datapoint{ 98 Timestamp: dp.TimestampNanos, 99 Value: dp.Value, 100 }) 101 } 102 103 if it.instrumented { 104 decodeDuration = time.Since(decodeStart) 105 } 106 107 if it.err = iter.Err(); it.err != nil { 108 return false 109 } 110 111 it.series = block.NewUnconsolidatedSeries( 112 it.datapoints, 113 it.seriesMeta[it.idx], 114 block.UnconsolidatedSeriesStats{ 115 Enabled: it.instrumented, 116 DecodeDuration: decodeDuration, 117 }) 118 119 return next 120 } 121 122 func (it *encodedSeriesIter) SeriesCount() int { 123 return len(it.seriesIters) 124 } 125 126 func (it *encodedSeriesIter) SeriesMeta() []block.SeriesMeta { 127 return it.seriesMeta 128 } 129 130 func (it *encodedSeriesIter) Close() { 131 // noop, as the resources at the step may still be in use; 132 // instead call Close() on the encodedBlock that generated this 133 } 134 135 // MultiSeriesIter returns batched series iterators for the block based on 136 // given concurrency. 137 func (b *encodedBlock) MultiSeriesIter( 138 concurrency int, 139 ) ([]block.SeriesIterBatch, error) { 140 fn := iteratorBatchingFn 141 if b.options != nil && b.options.IteratorBatchingFn() != nil { 142 fn = b.options.IteratorBatchingFn() 143 } 144 145 return fn( 146 concurrency, 147 b.seriesBlockIterators, 148 b.seriesMetas, 149 b.meta, 150 b.options, 151 ) 152 } 153 154 func iteratorBatchingFn( 155 concurrency int, 156 seriesBlockIterators []encoding.SeriesIterator, 157 seriesMetas []block.SeriesMeta, 158 meta block.Metadata, 159 opts Options, 160 ) ([]block.SeriesIterBatch, error) { 161 if concurrency < 1 { 162 return nil, fmt.Errorf("batch size %d must be greater than 0", concurrency) 163 } 164 165 var ( 166 iterCount = len(seriesBlockIterators) 167 iters = make([]block.SeriesIterBatch, 0, concurrency) 168 chunkSize = iterCount / concurrency 169 remainder = iterCount % concurrency 170 chunkSizes = make([]int, concurrency) 171 ) 172 173 util.MemsetInt(chunkSizes, chunkSize) 174 for i := 0; i < remainder; i++ { 175 chunkSizes[i] = chunkSizes[i] + 1 176 } 177 178 start := 0 179 for _, chunkSize := range chunkSizes { 180 end := start + chunkSize 181 182 if end > iterCount { 183 end = iterCount 184 } 185 186 iter := NewEncodedSeriesIter( 187 meta, seriesMetas[start:end], seriesBlockIterators[start:end], 188 opts.Instrumented(), 189 ) 190 191 iters = append(iters, block.SeriesIterBatch{ 192 Iter: iter, 193 Size: end - start, 194 }) 195 196 start = end 197 } 198 199 return iters, nil 200 } 201 202 // BlockSeriesProcessor processes blocks. 203 type BlockSeriesProcessor interface { 204 Process(bl block.Block, opts Options, fn BlockSeriesProcessorFn) error 205 } 206 207 // BlockSeriesProcessorFn processes an individual series iterator. 208 type BlockSeriesProcessorFn func( 209 iter block.SeriesIter, 210 ) error 211 212 // NewBlockSeriesProcessor creates a standard block processor. 213 func NewBlockSeriesProcessor() BlockSeriesProcessor { 214 return seriesBlockProcessor{} 215 } 216 217 type seriesBlockProcessor struct { 218 } 219 220 func (p seriesBlockProcessor) Process( 221 bl block.Block, 222 opts Options, 223 fn BlockSeriesProcessorFn, 224 ) error { 225 iter, err := bl.SeriesIter() 226 if err != nil { 227 return err 228 } 229 return fn(iter) 230 }