github.com/m3db/m3@v1.5.0/src/dbnode/encoding/m3tsz/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 m3tsz 22 23 import ( 24 "errors" 25 "math" 26 27 "github.com/m3db/m3/src/dbnode/encoding" 28 "github.com/m3db/m3/src/dbnode/namespace" 29 "github.com/m3db/m3/src/dbnode/ts" 30 "github.com/m3db/m3/src/dbnode/x/xio" 31 xtime "github.com/m3db/m3/src/x/time" 32 ) 33 34 var errClosed = errors.New("iterator is closed") 35 36 // DefaultReaderIteratorAllocFn returns a function for allocating NewReaderIterator. 37 func DefaultReaderIteratorAllocFn( 38 opts encoding.Options, 39 ) func(r xio.Reader64, _ namespace.SchemaDescr) encoding.ReaderIterator { 40 return func(r xio.Reader64, _ namespace.SchemaDescr) encoding.ReaderIterator { 41 return NewReaderIterator(r, DefaultIntOptimizationEnabled, opts) 42 } 43 } 44 45 // readerIterator provides an interface for clients to incrementally 46 // read datapoints off of an encoded stream. 47 type readerIterator struct { 48 is *encoding.IStream 49 opts encoding.Options 50 51 err error // current error 52 intVal float64 // current int value 53 tsIterator TimestampIterator 54 floatIter FloatEncoderAndIterator 55 56 mult uint8 // current int multiplier 57 sig uint8 // current number of significant bits for int diff 58 59 curr ts.Datapoint 60 intOptimized bool // whether encoding scheme is optimized for ints 61 isFloat bool // whether encoding is in int or float 62 63 closed bool 64 } 65 66 // NewReaderIterator returns a new iterator for a given reader 67 func NewReaderIterator( 68 reader xio.Reader64, 69 intOptimized bool, 70 opts encoding.Options, 71 ) encoding.ReaderIterator { 72 return &readerIterator{ 73 is: encoding.NewIStream(reader), 74 opts: opts, 75 tsIterator: NewTimestampIterator(opts, false), 76 intOptimized: intOptimized, 77 } 78 } 79 80 // Next moves to the next item 81 func (it *readerIterator) Next() bool { 82 if !it.hasNext() { 83 return false 84 } 85 86 first, done, err := it.tsIterator.ReadTimestamp(it.is) 87 if err != nil || done { 88 it.err = err 89 return false 90 } 91 92 if !first { 93 it.readNextValue() 94 } else { 95 it.readFirstValue() 96 } 97 98 it.curr.TimestampNanos = it.tsIterator.PrevTime 99 if !it.intOptimized || it.isFloat { 100 it.curr.Value = math.Float64frombits(it.floatIter.PrevFloatBits) 101 } else { 102 it.curr.Value = convertFromIntFloat(it.intVal, it.mult) 103 } 104 105 return it.hasNext() 106 } 107 108 func (it *readerIterator) readFirstValue() { 109 if !it.intOptimized { 110 if err := it.floatIter.readFullFloat(it.is); err != nil { 111 it.err = err 112 } 113 return 114 } 115 116 if it.readBits(1) == opcodeFloatMode { 117 if err := it.floatIter.readFullFloat(it.is); err != nil { 118 it.err = err 119 } 120 it.isFloat = true 121 return 122 } 123 124 it.readIntSigMult() 125 it.readIntValDiff() 126 } 127 128 func (it *readerIterator) readNextValue() { 129 if !it.intOptimized { 130 if err := it.floatIter.readNextFloat(it.is); err != nil { 131 it.err = err 132 } 133 return 134 } 135 136 if it.readBits(1) == opcodeUpdate { 137 if it.readBits(1) == opcodeRepeat { 138 return 139 } 140 141 if it.readBits(1) == opcodeFloatMode { 142 // Change to floatVal 143 if err := it.floatIter.readFullFloat(it.is); err != nil { 144 it.err = err 145 } 146 it.isFloat = true 147 return 148 } 149 150 it.readIntSigMult() 151 it.readIntValDiff() 152 it.isFloat = false 153 return 154 } 155 156 if it.isFloat { 157 if err := it.floatIter.readNextFloat(it.is); err != nil { 158 it.err = err 159 } 160 return 161 } 162 163 // inlined readIntValDiff() 164 if it.sig == 64 { 165 it.readIntValDiffSlow() 166 return 167 } 168 bits := it.readBits(it.sig + 1) 169 sign := -1.0 170 if (bits >> it.sig) == opcodeNegative { 171 sign = 1.0 172 // clear the opcode bit 173 bits ^= uint64(1 << it.sig) 174 } 175 it.intVal += sign * float64(bits) 176 } 177 178 func (it *readerIterator) readIntSigMult() { 179 if it.readBits(1) == opcodeUpdateSig { 180 if it.readBits(1) == OpcodeZeroSig { 181 it.sig = 0 182 } else { 183 it.sig = uint8(it.readBits(NumSigBits)) + 1 184 } 185 } 186 187 if it.readBits(1) == opcodeUpdateMult { 188 it.mult = uint8(it.readBits(numMultBits)) 189 if it.mult > maxMult { 190 it.err = errInvalidMultiplier 191 } 192 } 193 } 194 195 func (it *readerIterator) readIntValDiff() { 196 // check if we can read both sign bit and digits in one read 197 if it.sig == 64 { 198 it.readIntValDiffSlow() 199 return 200 } 201 // read both sign bit and digits in one read 202 bits := it.readBits(it.sig + 1) 203 sign := -1.0 204 if (bits >> it.sig) == opcodeNegative { 205 sign = 1.0 206 // clear the opcode bit 207 bits ^= uint64(1 << it.sig) 208 } 209 it.intVal += sign * float64(bits) 210 } 211 212 func (it *readerIterator) readIntValDiffSlow() { 213 sign := -1.0 214 if it.readBits(1) == opcodeNegative { 215 sign = 1.0 216 } 217 218 it.intVal += sign * float64(it.readBits(it.sig)) 219 } 220 221 func (it *readerIterator) readBits(numBits uint8) (res uint64) { 222 res, it.err = it.is.ReadBits(numBits) 223 return 224 } 225 226 // Current returns the value as well as the annotation associated with the current datapoint. 227 // Users should not hold on to the returned Annotation object as it may get invalidated when 228 // the iterator calls Next(). 229 func (it *readerIterator) Current() (ts.Datapoint, xtime.Unit, ts.Annotation) { 230 return it.curr, it.tsIterator.TimeUnit, it.tsIterator.PrevAnt 231 } 232 233 // Err returns the error encountered 234 func (it *readerIterator) Err() error { 235 return it.err 236 } 237 238 func (it *readerIterator) hasError() bool { 239 return it.err != nil 240 } 241 242 func (it *readerIterator) isDone() bool { 243 return it.tsIterator.Done 244 } 245 246 func (it *readerIterator) isClosed() bool { 247 return it.closed 248 } 249 250 func (it *readerIterator) hasNext() bool { 251 return !it.hasError() && !it.isDone() 252 } 253 254 // Reset resets the ReadIterator for reuse. 255 func (it *readerIterator) Reset(reader xio.Reader64, schema namespace.SchemaDescr) { 256 it.is.Reset(reader) 257 it.tsIterator = NewTimestampIterator(it.opts, it.tsIterator.SkipMarkers) 258 it.err = nil 259 it.isFloat = false 260 it.intVal = 0.0 261 it.mult = 0 262 it.sig = 0 263 it.closed = false 264 } 265 266 // Close closes the ReaderIterator. 267 func (it *readerIterator) Close() { 268 if it.closed { 269 return 270 } 271 272 it.closed = true 273 it.err = errClosed 274 pool := it.opts.ReaderIteratorPool() 275 if pool != nil { 276 pool.Put(it) 277 } 278 }