github.com/m3db/m3@v1.5.0/src/query/functions/fetch.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 functions
    22  
    23  import (
    24  	"fmt"
    25  	"time"
    26  
    27  	"github.com/m3db/m3/src/query/block"
    28  	"github.com/m3db/m3/src/query/executor/transform"
    29  	"github.com/m3db/m3/src/query/models"
    30  	"github.com/m3db/m3/src/query/parser"
    31  	"github.com/m3db/m3/src/query/storage"
    32  	"github.com/m3db/m3/src/query/util/logging"
    33  	"github.com/m3db/m3/src/x/instrument"
    34  	"github.com/m3db/m3/src/x/opentracing"
    35  
    36  	"go.uber.org/zap"
    37  )
    38  
    39  // FetchType gets the series from storage
    40  const FetchType = "fetch"
    41  
    42  // FetchOp stores required properties for fetch
    43  // TODO: Make FetchOp private
    44  type FetchOp struct {
    45  	Name     string
    46  	Range    time.Duration
    47  	Offset   time.Duration
    48  	Matchers models.Matchers
    49  }
    50  
    51  // FetchNode is a fetch execution node.
    52  // TODO: Make FetchNode private
    53  type FetchNode struct {
    54  	debug          bool
    55  	blockType      models.FetchedBlockType
    56  	op             FetchOp
    57  	controller     *transform.Controller
    58  	storage        storage.Storage
    59  	timespec       transform.TimeSpec
    60  	fetchOpts      *storage.FetchOptions
    61  	instrumentOpts instrument.Options
    62  }
    63  
    64  // OpType for the operator.
    65  func (o FetchOp) OpType() string {
    66  	return FetchType
    67  }
    68  
    69  // Bounds returns the bounds for this operation.
    70  func (o FetchOp) Bounds() transform.BoundSpec {
    71  	return transform.BoundSpec{
    72  		Range:  o.Range,
    73  		Offset: o.Offset,
    74  	}
    75  }
    76  
    77  // String is the string representation for this operation.
    78  func (o FetchOp) String() string {
    79  	return fmt.Sprintf("type: %s. name: %s, range: %v, offset: %v, matchers: %v",
    80  		o.OpType(), o.Name, o.Range, o.Offset, o.Matchers)
    81  }
    82  
    83  // Node creates the fetch execution node for this operation.
    84  func (o FetchOp) Node(
    85  	controller *transform.Controller,
    86  	storage storage.Storage,
    87  	options transform.Options,
    88  ) parser.Source {
    89  	return &FetchNode{
    90  		op:             o,
    91  		controller:     controller,
    92  		storage:        storage,
    93  		fetchOpts:      options.FetchOptions(),
    94  		timespec:       options.TimeSpec(),
    95  		debug:          options.Debug(),
    96  		blockType:      options.BlockType(),
    97  		instrumentOpts: options.InstrumentOptions(),
    98  	}
    99  }
   100  
   101  func (n *FetchNode) fetch(queryCtx *models.QueryContext) (block.Result, error) {
   102  	ctx := queryCtx.Ctx
   103  	sp, ctx := opentracing.StartSpanFromContext(ctx, "fetch")
   104  	defer sp.Finish()
   105  
   106  	timeSpec := n.timespec
   107  	// No need to adjust start and ends since physical plan
   108  	// already considers the offset, range
   109  	startTime := timeSpec.Start
   110  	endTime := timeSpec.End
   111  
   112  	opts, err := n.fetchOpts.QueryFetchOptions(queryCtx, n.blockType)
   113  	if err != nil {
   114  		return block.Result{}, err
   115  	}
   116  
   117  	offset := n.op.Offset
   118  	return n.storage.FetchBlocks(ctx, &storage.FetchQuery{
   119  		Start:       startTime.Add(-1 * offset).ToTime(),
   120  		End:         endTime.Add(-1 * offset).ToTime(),
   121  		TagMatchers: n.op.Matchers,
   122  		Interval:    timeSpec.Step,
   123  	}, opts)
   124  }
   125  
   126  // Execute runs the fetch node operation
   127  func (n *FetchNode) Execute(queryCtx *models.QueryContext) error {
   128  	ctx := queryCtx.Ctx
   129  	blockResult, err := n.fetch(queryCtx)
   130  	if err != nil {
   131  		return err
   132  	}
   133  
   134  	for _, block := range blockResult.Blocks {
   135  		if n.debug {
   136  			// Ignore any errors
   137  			iter, _ := block.StepIter()
   138  			if iter != nil {
   139  				logging.WithContext(ctx, n.instrumentOpts).
   140  					Info("fetch node", zap.Any("meta", block.Meta()))
   141  			}
   142  		}
   143  
   144  		if err := n.controller.Process(queryCtx, block); err != nil {
   145  			block.Close()
   146  			// Fail on first error
   147  			return err
   148  		}
   149  
   150  		// TODO: Revisit how and when we close blocks. At the each function step
   151  		// defers Close(), which means that we have half blocks hanging around for
   152  		// a long time. Ideally we should be able to transform blocks in place.
   153  		//
   154  		// NB: Until block closing is implemented correctly, this handles closing
   155  		// encoded iterators when there are additional processing steps, as these
   156  		// steps will not properly close the block. If there are no additional steps
   157  		// beyond the fetch, the read handler will close blocks.
   158  		if n.controller.HasMultipleOperations() {
   159  			block.Close()
   160  		}
   161  	}
   162  
   163  	return nil
   164  }