github.com/m3db/m3@v1.5.1-0.20231129193456-75a402aa583b/src/query/executor/engine.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 executor 22 23 import ( 24 "context" 25 "time" 26 27 "github.com/m3db/m3/src/query/block" 28 "github.com/m3db/m3/src/query/models" 29 "github.com/m3db/m3/src/query/parser" 30 "github.com/m3db/m3/src/query/storage" 31 "github.com/m3db/m3/src/x/opentracing" 32 33 "github.com/uber-go/tally" 34 ) 35 36 type engine struct { 37 opts EngineOptions 38 metrics *engineMetrics 39 } 40 41 // QueryOptions can be used to pass custom flags to engine. 42 type QueryOptions struct { 43 QueryContextOptions models.QueryContextOptions 44 } 45 46 // NewEngine returns a new instance of QueryExecutor. 47 func NewEngine( 48 engineOpts EngineOptions, 49 ) Engine { 50 return &engine{ 51 metrics: newEngineMetrics(engineOpts.InstrumentOptions().MetricsScope()), 52 opts: engineOpts, 53 } 54 } 55 56 type engineMetrics struct { 57 all *counterWithDecrement 58 compiling *counterWithDecrement 59 planning *counterWithDecrement 60 executing *counterWithDecrement 61 62 activeHist tally.Histogram 63 compilingHist tally.Histogram 64 planningHist tally.Histogram 65 executingHist tally.Histogram 66 } 67 68 type counterWithDecrement struct { 69 start tally.Counter 70 end tally.Counter 71 } 72 73 func (c *counterWithDecrement) Inc() { 74 c.start.Inc(1) 75 } 76 77 func (c *counterWithDecrement) Dec() { 78 c.end.Inc(1) 79 } 80 81 func newCounterWithDecrement(scope tally.Scope) *counterWithDecrement { 82 return &counterWithDecrement{ 83 start: scope.Counter("start"), 84 end: scope.Counter("end"), 85 } 86 } 87 88 func newEngineMetrics(scope tally.Scope) *engineMetrics { 89 durationBuckets := tally.MustMakeExponentialDurationBuckets(time.Millisecond, 10, 5) 90 return &engineMetrics{ 91 all: newCounterWithDecrement(scope.SubScope(all.String())), 92 compiling: newCounterWithDecrement(scope.SubScope(compiling.String())), 93 planning: newCounterWithDecrement(scope.SubScope(planning.String())), 94 executing: newCounterWithDecrement(scope.SubScope(executing.String())), 95 activeHist: scope.Histogram(all.durationString(), durationBuckets), 96 compilingHist: scope.Histogram(compiling.durationString(), durationBuckets), 97 planningHist: scope.Histogram(planning.durationString(), durationBuckets), 98 executingHist: scope.Histogram(executing.durationString(), durationBuckets), 99 } 100 } 101 102 func (e *engine) ExecuteProm( 103 ctx context.Context, 104 query *storage.FetchQuery, 105 opts *QueryOptions, 106 fetchOpts *storage.FetchOptions, 107 ) (storage.PromResult, error) { 108 return e.opts.Store().FetchProm(ctx, query, fetchOpts) 109 } 110 111 func (e *engine) ExecuteExpr( 112 ctx context.Context, 113 parser parser.Parser, 114 opts *QueryOptions, 115 fetchOpts *storage.FetchOptions, 116 params models.RequestParams, 117 ) (block.Block, error) { 118 req := newRequest(e, params, fetchOpts, e.opts.InstrumentOptions()) 119 nodes, edges, err := req.compile(ctx, parser) 120 if err != nil { 121 return nil, err 122 } 123 124 pp, err := req.plan(ctx, nodes, edges) 125 if err != nil { 126 return nil, err 127 } 128 129 state, err := req.generateExecutionState(ctx, pp) 130 if err != nil { 131 return nil, err 132 } 133 134 // free up resources 135 sp, ctx := opentracing.StartSpanFromContext(ctx, "executing") 136 defer sp.Finish() 137 138 scope := e.opts.InstrumentOptions().MetricsScope() 139 queryCtx := models.NewQueryContext(ctx, scope, 140 opts.QueryContextOptions) 141 142 if err := state.Execute(queryCtx); err != nil { 143 state.sink.closeWithError(err) 144 return nil, err 145 } 146 147 return state.sink.getValue() 148 } 149 150 func (e *engine) Options() EngineOptions { 151 return e.opts 152 } 153 154 func (e *engine) Close() error { 155 return nil 156 }