github.com/m3db/m3@v1.5.0/src/dbnode/encoding/series_iterator_accumulator.go (about) 1 // Copyright (c) 2020 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 "fmt" 26 27 "github.com/m3db/m3/src/dbnode/ts" 28 "github.com/m3db/m3/src/x/ident" 29 xtime "github.com/m3db/m3/src/x/time" 30 ) 31 32 var _ SeriesIteratorAccumulator = (*seriesIteratorAccumulator)(nil) 33 34 type seriesIteratorAccumulator struct { 35 id ident.ID 36 nsID ident.ID 37 start xtime.UnixNano 38 end xtime.UnixNano 39 40 iters iterators 41 seriesIterators []SeriesIterator 42 firstAnnotationHolder annotationHolder 43 44 err error 45 firstNext bool 46 closed bool 47 } 48 49 // NewSeriesIteratorAccumulator creates a new series iterator. 50 func NewSeriesIteratorAccumulator(iter SeriesIterator) (SeriesIteratorAccumulator, error) { 51 nsID := "" 52 if iter.Namespace() != nil { 53 nsID = iter.Namespace().String() 54 } 55 it := &seriesIteratorAccumulator{ 56 // NB: clone id and nsID so that they will be accessible after underlying 57 // iterators are closed. 58 id: ident.StringID(iter.ID().String()), 59 nsID: ident.StringID(nsID), 60 seriesIterators: make([]SeriesIterator, 0, 2), 61 firstNext: true, 62 } 63 64 it.iters.reset() 65 66 err := it.Add(iter) 67 if err != nil { 68 return nil, err 69 } 70 71 return it, nil 72 } 73 74 func (it *seriesIteratorAccumulator) Add(iter SeriesIterator) error { 75 if it.err != nil { 76 return it.err 77 } 78 79 if !iter.Next() { 80 err := iter.Err() 81 return err 82 } 83 84 firstAnnotation := iter.FirstAnnotation() 85 if !it.iters.push(iter) { 86 err := iter.Err() 87 return err 88 } 89 90 iterStart := iter.Start() 91 if start := it.start; start.IsZero() || iterStart.Before(start) { 92 it.start = iterStart 93 if len(firstAnnotation) > 0 { 94 it.firstAnnotationHolder.set(firstAnnotation) 95 } 96 } 97 98 iterEnd := iter.End() 99 if end := it.end; end.IsZero() || iterEnd.After(end) { 100 it.end = iterEnd 101 } 102 103 it.seriesIterators = append(it.seriesIterators, iter) 104 return nil 105 } 106 107 func (it *seriesIteratorAccumulator) ID() ident.ID { 108 return it.id 109 } 110 111 func (it *seriesIteratorAccumulator) Namespace() ident.ID { 112 return it.nsID 113 } 114 115 func (it *seriesIteratorAccumulator) Tags() ident.TagIterator { 116 // NB: the tags for each iterator must be the same, so it's valid to return 117 // from whichever iterator is available. 118 for _, iter := range it.seriesIterators { 119 if tags := iter.Tags(); tags != nil { 120 return tags 121 } 122 } 123 124 return ident.EmptyTagIterator 125 } 126 127 func (it *seriesIteratorAccumulator) Start() xtime.UnixNano { 128 return it.start 129 } 130 131 func (it *seriesIteratorAccumulator) End() xtime.UnixNano { 132 return it.end 133 } 134 135 func (it *seriesIteratorAccumulator) Next() bool { 136 if !it.firstNext { 137 if !it.hasNext() { 138 return false 139 } 140 141 it.moveToNext() 142 } 143 144 it.firstNext = false 145 return it.hasNext() 146 } 147 148 func (it *seriesIteratorAccumulator) Current() (ts.Datapoint, xtime.Unit, ts.Annotation) { 149 return it.iters.current() 150 } 151 152 func (it *seriesIteratorAccumulator) Err() error { 153 if it.err != nil { 154 return it.err 155 } 156 157 for _, iter := range it.seriesIterators { 158 if err := iter.Err(); err != nil { 159 it.err = err 160 return err 161 } 162 } 163 164 return nil 165 } 166 167 func (it *seriesIteratorAccumulator) FirstAnnotation() ts.Annotation { 168 return it.firstAnnotationHolder.get() 169 } 170 171 func (it *seriesIteratorAccumulator) Close() { 172 if it.isClosed() { 173 return 174 } 175 it.closed = true 176 if it.id != nil { 177 it.id.Finalize() 178 it.id = nil 179 } 180 if it.nsID != nil { 181 it.nsID.Finalize() 182 it.nsID = nil 183 } 184 it.iters.reset() 185 it.firstAnnotationHolder.reset() 186 it.firstNext = true 187 } 188 189 func (it *seriesIteratorAccumulator) Replicas() ([]MultiReaderIterator, error) { 190 if l := len(it.seriesIterators); l != 1 { 191 return nil, fmt.Errorf("cannot get replicas for accumulated series "+ 192 "iterators: need 1 iterator, have %d", l) 193 } 194 return it.seriesIterators[0].Replicas() 195 } 196 197 func (it *seriesIteratorAccumulator) Reset(SeriesIteratorOptions) { 198 if it.err == nil { 199 it.err = errors.New("cannot reset a series accumulator") 200 } 201 } 202 203 func (it *seriesIteratorAccumulator) IterateEqualTimestampStrategy() IterateEqualTimestampStrategy { 204 return it.iters.equalTimesStrategy 205 } 206 207 func (it *seriesIteratorAccumulator) SetIterateEqualTimestampStrategy( 208 strategy IterateEqualTimestampStrategy, 209 ) { 210 it.iters.equalTimesStrategy = strategy 211 for _, iter := range it.seriesIterators { 212 iter.SetIterateEqualTimestampStrategy(strategy) 213 } 214 } 215 216 func (it *seriesIteratorAccumulator) hasError() bool { 217 return it.err != nil 218 } 219 220 func (it *seriesIteratorAccumulator) isClosed() bool { 221 return it.closed 222 } 223 224 func (it *seriesIteratorAccumulator) hasMore() bool { 225 return it.iters.len() > 0 226 } 227 228 func (it *seriesIteratorAccumulator) hasNext() bool { 229 return !it.hasError() && !it.isClosed() && it.hasMore() 230 } 231 232 func (it *seriesIteratorAccumulator) moveToNext() { 233 for { 234 prev := it.iters.at() 235 next, err := it.iters.moveToValidNext() 236 if err != nil { 237 it.err = err 238 return 239 } 240 if !next { 241 return 242 } 243 244 curr := it.iters.at() 245 if curr != prev { 246 return 247 } 248 249 // Dedupe by continuing 250 } 251 } 252 253 func (it *seriesIteratorAccumulator) Stats() (SeriesIteratorStats, error) { 254 approx := 0 255 for _, iter := range it.seriesIterators { 256 stats, err := iter.Stats() 257 if err != nil { 258 return SeriesIteratorStats{}, err 259 } 260 approx += stats.ApproximateSizeInBytes 261 } 262 return SeriesIteratorStats{ApproximateSizeInBytes: approx}, nil 263 }