github.com/m3db/m3@v1.5.0/src/query/functions/unconsolidated/timestamp.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 unconsolidated
    22  
    23  import (
    24  	"fmt"
    25  	"math"
    26  	"time"
    27  
    28  	"github.com/m3db/m3/src/query/block"
    29  	"github.com/m3db/m3/src/query/executor/transform"
    30  	"github.com/m3db/m3/src/query/models"
    31  	"github.com/m3db/m3/src/query/parser"
    32  	"github.com/m3db/m3/src/query/util"
    33  )
    34  
    35  const (
    36  	// TimestampType returns the timestamp of each of the samples of the given
    37  	// time series as the number of seconds since January 1, 1970 UTC.
    38  	TimestampType = "timestamp"
    39  )
    40  
    41  // NewTimestampOp creates a new timestamp operation.
    42  func NewTimestampOp(opType string) (parser.Params, error) {
    43  	if opType != TimestampType {
    44  		return timestampOp{}, fmt.Errorf("operator not supported: %s", opType)
    45  	}
    46  
    47  	return newTimestampOp(opType), nil
    48  }
    49  
    50  type timestampOp struct {
    51  	opType string
    52  }
    53  
    54  // OpType for the operator.
    55  func (o timestampOp) OpType() string {
    56  	return o.opType
    57  }
    58  
    59  // String representation.
    60  func (o timestampOp) String() string {
    61  	return fmt.Sprintf("type: %s", o.OpType())
    62  }
    63  
    64  func newTimestampOp(opType string) timestampOp {
    65  	return timestampOp{
    66  		opType: opType,
    67  	}
    68  }
    69  
    70  // Node creates an execution node
    71  func (o timestampOp) Node(
    72  	controller *transform.Controller,
    73  	_ transform.Options,
    74  ) transform.OpNode {
    75  	return &timestampNode{
    76  		op:         o,
    77  		controller: controller,
    78  	}
    79  }
    80  
    81  type timestampNode struct {
    82  	op         timestampOp
    83  	controller *transform.Controller
    84  }
    85  
    86  func (n *timestampNode) Params() parser.Params {
    87  	return n.op
    88  }
    89  
    90  // Process the block
    91  func (n *timestampNode) Process(
    92  	queryCtx *models.QueryContext,
    93  	ID parser.NodeID,
    94  	b block.Block,
    95  ) error {
    96  	return transform.ProcessSimpleBlock(n, n.controller, queryCtx, ID, b)
    97  }
    98  
    99  func (n *timestampNode) ProcessBlock(
   100  	queryCtx *models.QueryContext,
   101  	ID parser.NodeID,
   102  	b block.Block,
   103  ) (block.Block, error) {
   104  	iter, err := b.StepIter()
   105  	if err != nil {
   106  		return nil, err
   107  	}
   108  
   109  	builder, err := n.controller.BlockBuilder(queryCtx, b.Meta(), iter.SeriesMeta())
   110  	if err != nil {
   111  		return nil, err
   112  	}
   113  
   114  	count := iter.StepCount()
   115  	seriesCount := len(iter.SeriesMeta())
   116  	if err = builder.AddCols(count); err != nil {
   117  		return nil, err
   118  	}
   119  
   120  	bounds := b.Meta().Bounds
   121  	currentStep := float64(bounds.Start) / float64(time.Second)
   122  	step := float64(bounds.StepSize) / float64(time.Second)
   123  	values := make([]float64, seriesCount)
   124  	for index := 0; iter.Next(); index++ {
   125  		curr := iter.Current()
   126  		util.Memset(values, currentStep)
   127  		for i, dp := range curr.Values() {
   128  			// NB: If there is no datapoint at this step, there should also not
   129  			// be a value for the timestamp function.
   130  			if math.IsNaN(dp) {
   131  				values[i] = math.NaN()
   132  			}
   133  		}
   134  
   135  		builder.AppendValues(index, values)
   136  		currentStep = currentStep + step
   137  	}
   138  
   139  	if err = iter.Err(); err != nil {
   140  		return nil, err
   141  	}
   142  
   143  	return builder.Build(), nil
   144  }