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  }