github.com/m3db/m3@v1.5.0/src/query/block/scalar.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 block
    22  
    23  import (
    24  	"errors"
    25  
    26  	"github.com/m3db/m3/src/query/models"
    27  	xtime "github.com/m3db/m3/src/x/time"
    28  )
    29  
    30  // Scalar is a block containing a single value over a certain bound
    31  // This represents constant values; it greatly simplifies downstream operations
    32  // by allowing them to treat this as a regular block, while at the same time
    33  // having an option to optimize by accessing the scalar value directly instead.
    34  type Scalar struct {
    35  	val  float64
    36  	meta Metadata
    37  }
    38  
    39  // NewScalar creates a scalar block whose value is given by the function over
    40  // the metadata bounds.
    41  func NewScalar(
    42  	val float64,
    43  	meta Metadata,
    44  ) Block {
    45  	// NB: sanity check to ensure scalar values always have clean metadata.
    46  	meta.ResultMetadata = NewResultMetadata()
    47  	return &Scalar{
    48  		val:  val,
    49  		meta: meta,
    50  	}
    51  }
    52  
    53  // Info returns information about the block.
    54  func (b *Scalar) Info() BlockInfo {
    55  	return NewBlockInfo(BlockScalar)
    56  }
    57  
    58  // Meta returns the metadata for the block.
    59  func (b *Scalar) Meta() Metadata {
    60  	return b.meta
    61  }
    62  
    63  // StepIter returns a step-wise block iterator, giving consolidated values
    64  // across all series comprising the box at a single time step.
    65  func (b *Scalar) StepIter() (StepIter, error) {
    66  	bounds := b.meta.Bounds
    67  	steps := bounds.Steps()
    68  	return &scalarStepIter{
    69  		meta:    b.meta,
    70  		vals:    []float64{b.val},
    71  		numVals: steps,
    72  		idx:     -1,
    73  	}, nil
    74  }
    75  
    76  // Close closes the block; this is a no-op for scalar block.
    77  func (b *Scalar) Close() error { return nil }
    78  
    79  // Value yields the constant value this scalar is set to.
    80  func (b *Scalar) Value() float64 {
    81  	return b.val
    82  }
    83  
    84  type scalarStepIter struct {
    85  	numVals, idx int
    86  	stepTime     xtime.UnixNano
    87  	err          error
    88  	meta         Metadata
    89  	vals         []float64
    90  }
    91  
    92  // build an empty SeriesMetadata.
    93  func buildSeriesMeta(meta Metadata) SeriesMeta {
    94  	return SeriesMeta{
    95  		Tags: models.NewTags(0, meta.Tags.Opts),
    96  	}
    97  }
    98  
    99  func (it *scalarStepIter) Close()         { /* No-op*/ }
   100  func (it *scalarStepIter) Err() error     { return it.err }
   101  func (it *scalarStepIter) StepCount() int { return it.numVals }
   102  func (it *scalarStepIter) SeriesMeta() []SeriesMeta {
   103  	return []SeriesMeta{buildSeriesMeta(it.meta)}
   104  }
   105  
   106  func (it *scalarStepIter) Next() bool {
   107  	if it.err != nil {
   108  		return false
   109  	}
   110  
   111  	it.idx++
   112  	next := it.idx < it.numVals
   113  	if !next {
   114  		return false
   115  	}
   116  
   117  	it.stepTime, it.err = it.meta.Bounds.TimeForIndex(it.idx)
   118  	if it.err != nil {
   119  		return false
   120  	}
   121  
   122  	return next
   123  }
   124  
   125  func (it *scalarStepIter) Current() Step {
   126  	t := it.stepTime
   127  	return &scalarStep{
   128  		vals: it.vals,
   129  		time: t,
   130  	}
   131  }
   132  
   133  type scalarStep struct {
   134  	vals []float64
   135  	time xtime.UnixNano
   136  }
   137  
   138  func (it *scalarStep) Time() xtime.UnixNano { return it.time }
   139  func (it *scalarStep) Values() []float64    { return it.vals }
   140  
   141  // SeriesIter is invalid for a scalar block.
   142  func (b *Scalar) SeriesIter() (SeriesIter, error) {
   143  	return nil, errors.New("series iterator undefined for a scalar block")
   144  }
   145  
   146  // MultiSeriesIter is invalid for a scalar block.
   147  func (b *Scalar) MultiSeriesIter(_ int) ([]SeriesIterBatch, error) {
   148  	return nil, errors.New("multi series iterator undefined for a scalar block")
   149  }