github.com/m3db/m3@v1.5.0/src/query/graphite/common/context.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 common
    22  
    23  import (
    24  	ctx "context"
    25  	"sync"
    26  	"time"
    27  
    28  	"github.com/m3db/m3/src/query/graphite/context"
    29  	"github.com/m3db/m3/src/query/storage"
    30  )
    31  
    32  // contextBase are the real content of a Context, minus the lock so that we
    33  // can safely copy a context without violating the rules of go vet.
    34  // nolint
    35  type contextBase struct {
    36  	// TimeRangeAdjusted is a boolean indicating whether the time range has an adjustment.
    37  	TimeRangeAdjusted bool
    38  
    39  	// The start time to query against.
    40  	StartTime time.Time
    41  
    42  	// The end time to query against.
    43  	EndTime time.Time
    44  
    45  	// TimeRangeAdjustment is the time range adjustment made to the query.
    46  	TimeRangeAdjustment TimeRangeAdjustment
    47  
    48  	// The underlying engine.
    49  	Engine QueryEngine
    50  
    51  	// Trace records traces.
    52  	Trace Tracer
    53  
    54  	// Timeout indicates whether to use a custom timeout when fetching data,
    55  	// specify zero to indicate default timeout or a positive value
    56  	Timeout time.Duration
    57  
    58  	// Source is the query source.
    59  	Source []byte
    60  
    61  	// MaxDataPoints is the max datapoints for the query.
    62  	MaxDataPoints int64
    63  
    64  	// FetchOpts are the fetch options to use for the query.
    65  	FetchOpts *storage.FetchOptions
    66  
    67  	parent         *Context
    68  	reqCtx         ctx.Context
    69  	storageContext context.Context
    70  }
    71  
    72  // Context is the parameters to a query evaluation.
    73  type Context struct {
    74  	sync.RWMutex
    75  	contextBase
    76  }
    77  
    78  // ContextOptions provides the options to create the context with
    79  type ContextOptions struct {
    80  	Start         time.Time
    81  	End           time.Time
    82  	Engine        QueryEngine
    83  	Timeout       time.Duration
    84  	MaxDataPoints int64
    85  	FetchOpts     *storage.FetchOptions
    86  }
    87  
    88  // TimeRangeAdjustment is an applied time range adjustment.
    89  type TimeRangeAdjustment struct {
    90  	OriginalStart time.Time
    91  	OriginalEnd   time.Time
    92  	ShiftStart    time.Duration
    93  	ShiftEnd      time.Duration
    94  	ExpandStart   time.Duration
    95  	ExpandEnd     time.Duration
    96  }
    97  
    98  // NewContext creates a new context.
    99  func NewContext(options ContextOptions) *Context {
   100  	return &Context{
   101  		contextBase: contextBase{
   102  			StartTime:      options.Start,
   103  			EndTime:        options.End,
   104  			Engine:         options.Engine,
   105  			storageContext: context.New(),
   106  			Timeout:        options.Timeout,
   107  			MaxDataPoints:  options.MaxDataPoints,
   108  			FetchOpts:      options.FetchOpts,
   109  		},
   110  	}
   111  }
   112  
   113  // TracingEnabled checks whether tracing is enabled for this context.
   114  func (c *Context) TracingEnabled() bool { return c.Trace != nil }
   115  
   116  // ChildContextOptions is a set of options to pass when creating a child context.
   117  type ChildContextOptions struct {
   118  	adjustment struct {
   119  		adjusted    bool
   120  		shiftStart  time.Duration
   121  		shiftEnd    time.Duration
   122  		expandStart time.Duration
   123  		expandEnd   time.Duration
   124  	}
   125  }
   126  
   127  // NewChildContextOptions returns an initialized ChildContextOptions struct.
   128  func NewChildContextOptions() ChildContextOptions {
   129  	return ChildContextOptions{}
   130  }
   131  
   132  // AdjustTimeRange will adjust the child context's time range.
   133  func (o *ChildContextOptions) AdjustTimeRange(
   134  	shiftStart, shiftEnd, expandStart, expandEnd time.Duration,
   135  ) {
   136  	if shiftStart == 0 && shiftEnd == 0 && expandStart == 0 && expandEnd == 0 {
   137  		// Not an adjustment, don't mark "adjusted" true
   138  		return
   139  	}
   140  	o.adjustment.adjusted = true
   141  	o.adjustment.shiftStart = shiftStart
   142  	o.adjustment.shiftEnd = shiftEnd
   143  	o.adjustment.expandStart = expandStart
   144  	o.adjustment.expandEnd = expandEnd
   145  }
   146  
   147  // NewChildContext creates a child context.  Child contexts can have any of
   148  // their parameters modified, but share the same underlying storage context.
   149  func (c *Context) NewChildContext(opts ChildContextOptions) *Context {
   150  	// create a duplicate of the parent context with an independent lock
   151  	// (otherwise `go vet` complains due to the -copylock check)
   152  	c.RLock()
   153  	child := &Context{
   154  		contextBase: c.contextBase,
   155  	}
   156  	child.parent = c
   157  	c.RUnlock()
   158  
   159  	origStart, origEnd := child.StartTime, child.EndTime
   160  	if child.TimeRangeAdjusted {
   161  		origStart, origEnd = c.TimeRangeAdjustment.OriginalStart, c.TimeRangeAdjustment.OriginalEnd
   162  	}
   163  
   164  	if opts.adjustment.adjusted {
   165  		child.TimeRangeAdjusted = true
   166  		child.TimeRangeAdjustment.OriginalStart = origStart
   167  		child.TimeRangeAdjustment.OriginalEnd = origEnd
   168  		child.TimeRangeAdjustment.ShiftStart += opts.adjustment.shiftStart
   169  		child.TimeRangeAdjustment.ShiftEnd += opts.adjustment.shiftEnd
   170  		child.TimeRangeAdjustment.ExpandStart += opts.adjustment.expandStart
   171  		child.TimeRangeAdjustment.ExpandEnd += opts.adjustment.expandEnd
   172  
   173  		child.StartTime = origStart.
   174  			Add(child.TimeRangeAdjustment.ShiftStart).
   175  			Add(-child.TimeRangeAdjustment.ExpandStart)
   176  		child.EndTime = origEnd.
   177  			Add(child.TimeRangeAdjustment.ShiftEnd).
   178  			Add(child.TimeRangeAdjustment.ExpandEnd)
   179  	}
   180  
   181  	child.reqCtx = c.reqCtx
   182  	return child
   183  }
   184  
   185  // Close closes the context
   186  func (c *Context) Close() error {
   187  	if c.parent != nil {
   188  		// Closing a child context is meaningless.
   189  		return nil
   190  	}
   191  
   192  	return c.storageContext.Close()
   193  }
   194  
   195  // SetRequestContext sets the given context as the request context for this
   196  // execution context. This is used for calls to the m3 storage wrapper.
   197  func (c *Context) SetRequestContext(reqCtx ctx.Context) {
   198  	c.Lock()
   199  	c.reqCtx = reqCtx
   200  	c.Unlock()
   201  }
   202  
   203  // RequestContext will provide the wrapped request context. Used for calls
   204  // to m3 storage wrapper.
   205  func (c *Context) RequestContext() ctx.Context {
   206  	c.RLock()
   207  	r := c.reqCtx
   208  	c.RUnlock()
   209  	return r
   210  }
   211  
   212  // RegisterCloser registers a new Closer with the context.
   213  func (c *Context) RegisterCloser(closer context.Closer) {
   214  	c.storageContext.RegisterCloser(closer)
   215  }
   216  
   217  // AddAsyncTasks adds tracked asynchronous task(s)
   218  func (c *Context) AddAsyncTasks(count int) {
   219  	c.storageContext.AddAsyncTasks(count)
   220  }
   221  
   222  // DoneAsyncTask marks a single tracked asynchronous task complete
   223  func (c *Context) DoneAsyncTask() {
   224  	c.storageContext.DoneAsyncTask()
   225  }
   226  
   227  // A Trace is tracing information about a function or fetch within a query.
   228  type Trace struct {
   229  	// ActivityName is the name of the activity being traced.
   230  	ActivityName string
   231  
   232  	// Duration is the amount of time it took to execute the activity.
   233  	Duration time.Duration
   234  
   235  	// Inputs are the number of timeseries processed by the trace.
   236  	Inputs []TraceStats
   237  
   238  	// Outputs is the number of timeseries returned by the trace.
   239  	Outputs TraceStats
   240  }
   241  
   242  // TraceStats tracks the number of timeseries used by a trace.
   243  type TraceStats struct {
   244  	NumSeries int // number of timeseries being acted on
   245  }
   246  
   247  // A Tracer is used to record a Trace.
   248  type Tracer func(t Trace)