github.com/m3db/m3@v1.5.0/src/query/functions/scalar/time.go (about)

     1  // Copyright (c) 2019 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 scalar
    22  
    23  import (
    24  	"go.uber.org/zap"
    25  
    26  	"github.com/m3db/m3/src/query/block"
    27  	"github.com/m3db/m3/src/query/executor/transform"
    28  	"github.com/m3db/m3/src/query/models"
    29  	"github.com/m3db/m3/src/query/parser"
    30  	"github.com/m3db/m3/src/query/util/logging"
    31  )
    32  
    33  type timeOp struct {
    34  	tagOptions models.TagOptions
    35  }
    36  
    37  func (o timeOp) OpType() string {
    38  	return TimeType
    39  }
    40  
    41  func (o timeOp) String() string {
    42  	return "type: time"
    43  }
    44  
    45  func (o timeOp) Node(
    46  	controller *transform.Controller,
    47  	opts transform.Options,
    48  ) parser.Source {
    49  	return &timeNode{
    50  		controller: controller,
    51  		tagOptions: o.tagOptions,
    52  		opts:       opts,
    53  	}
    54  }
    55  
    56  // NewTimeOp creates an operation that yields a time-based source.
    57  func NewTimeOp(tagOptions models.TagOptions) (parser.Params, error) {
    58  	return &timeOp{
    59  		tagOptions: tagOptions,
    60  	}, nil
    61  }
    62  
    63  // timeNode is the execution node for time source.
    64  type timeNode struct {
    65  	tagOptions models.TagOptions
    66  	controller *transform.Controller
    67  	opts       transform.Options
    68  }
    69  
    70  // Execute runs the time source's pipeline.
    71  func (n *timeNode) Execute(queryCtx *models.QueryContext) error {
    72  	bounds := n.opts.TimeSpec().Bounds()
    73  	meta := block.Metadata{
    74  		Bounds:         bounds,
    75  		Tags:           models.NewTags(0, n.tagOptions),
    76  		ResultMetadata: block.NewResultMetadata(),
    77  	}
    78  
    79  	seriesMeta := []block.SeriesMeta{
    80  		{
    81  			Tags: models.NewTags(0, n.tagOptions),
    82  			Name: []byte(TimeType),
    83  		},
    84  	}
    85  
    86  	builder := block.NewColumnBlockBuilder(queryCtx, meta, seriesMeta)
    87  	steps := bounds.Steps()
    88  	err := builder.AddCols(steps)
    89  	if err != nil {
    90  		return err
    91  	}
    92  
    93  	for i := 0; i < steps; i++ {
    94  		t, err := bounds.TimeForIndex(i)
    95  		if err != nil {
    96  			return err
    97  		}
    98  
    99  		timeVal := float64(t.Seconds())
   100  		if err := builder.AppendValue(i, timeVal); err != nil {
   101  			return err
   102  		}
   103  	}
   104  
   105  	block := builder.BuildAsType(block.BlockTime)
   106  	if n.opts.Debug() {
   107  		// Ignore any errors
   108  		iter, _ := block.StepIter()
   109  		if iter != nil {
   110  			logging.WithContext(queryCtx.Ctx, n.opts.InstrumentOptions()).
   111  				Info("time node", zap.String("meta", block.Meta().String()))
   112  		}
   113  	}
   114  
   115  	if err := n.controller.Process(queryCtx, block); err != nil {
   116  		block.Close()
   117  		// Fail on first error
   118  		return err
   119  	}
   120  
   121  	block.Close()
   122  	return nil
   123  }