|
|
|
@ -408,44 +408,50 @@ func (ng *Engine) SetQueryLogger(l QueryLogger) {
|
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
// NewInstantQuery returns an evaluation query for the given expression at the given time.
|
|
|
|
|
func (ng *Engine) NewInstantQuery(_ context.Context, q storage.Queryable, opts *QueryOpts, qs string, ts time.Time) (Query, error) { |
|
|
|
|
expr, err := parser.ParseExpr(qs) |
|
|
|
|
func (ng *Engine) NewInstantQuery(ctx context.Context, q storage.Queryable, opts *QueryOpts, qs string, ts time.Time) (Query, error) { |
|
|
|
|
pExpr, qry := ng.newQuery(q, qs, opts, ts, ts, 0) |
|
|
|
|
finishQueue, err := ng.queueActive(ctx, qry) |
|
|
|
|
if err != nil { |
|
|
|
|
return nil, err |
|
|
|
|
} |
|
|
|
|
qry, err := ng.newQuery(q, opts, expr, ts, ts, 0) |
|
|
|
|
defer finishQueue() |
|
|
|
|
expr, err := parser.ParseExpr(qs) |
|
|
|
|
if err != nil { |
|
|
|
|
return nil, err |
|
|
|
|
} |
|
|
|
|
qry.q = qs |
|
|
|
|
if err := ng.validateOpts(expr); err != nil { |
|
|
|
|
return nil, err |
|
|
|
|
} |
|
|
|
|
*pExpr = PreprocessExpr(expr, ts, ts) |
|
|
|
|
|
|
|
|
|
return qry, nil |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
// NewRangeQuery returns an evaluation query for the given time range and with
|
|
|
|
|
// the resolution set by the interval.
|
|
|
|
|
func (ng *Engine) NewRangeQuery(_ context.Context, q storage.Queryable, opts *QueryOpts, qs string, start, end time.Time, interval time.Duration) (Query, error) { |
|
|
|
|
func (ng *Engine) NewRangeQuery(ctx context.Context, q storage.Queryable, opts *QueryOpts, qs string, start, end time.Time, interval time.Duration) (Query, error) { |
|
|
|
|
pExpr, qry := ng.newQuery(q, qs, opts, start, end, interval) |
|
|
|
|
finishQueue, err := ng.queueActive(ctx, qry) |
|
|
|
|
if err != nil { |
|
|
|
|
return nil, err |
|
|
|
|
} |
|
|
|
|
defer finishQueue() |
|
|
|
|
expr, err := parser.ParseExpr(qs) |
|
|
|
|
if err != nil { |
|
|
|
|
return nil, err |
|
|
|
|
} |
|
|
|
|
if err := ng.validateOpts(expr); err != nil { |
|
|
|
|
return nil, err |
|
|
|
|
} |
|
|
|
|
if expr.Type() != parser.ValueTypeVector && expr.Type() != parser.ValueTypeScalar { |
|
|
|
|
return nil, fmt.Errorf("invalid expression type %q for range query, must be Scalar or instant Vector", parser.DocumentedType(expr.Type())) |
|
|
|
|
} |
|
|
|
|
qry, err := ng.newQuery(q, opts, expr, start, end, interval) |
|
|
|
|
if err != nil { |
|
|
|
|
return nil, err |
|
|
|
|
} |
|
|
|
|
qry.q = qs |
|
|
|
|
*pExpr = PreprocessExpr(expr, start, end) |
|
|
|
|
|
|
|
|
|
return qry, nil |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
func (ng *Engine) newQuery(q storage.Queryable, opts *QueryOpts, expr parser.Expr, start, end time.Time, interval time.Duration) (*query, error) { |
|
|
|
|
if err := ng.validateOpts(expr); err != nil { |
|
|
|
|
return nil, err |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
func (ng *Engine) newQuery(q storage.Queryable, qs string, opts *QueryOpts, start, end time.Time, interval time.Duration) (*parser.Expr, *query) { |
|
|
|
|
// Default to empty QueryOpts if not provided.
|
|
|
|
|
if opts == nil { |
|
|
|
|
opts = &QueryOpts{} |
|
|
|
@ -457,20 +463,20 @@ func (ng *Engine) newQuery(q storage.Queryable, opts *QueryOpts, expr parser.Exp
|
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
es := &parser.EvalStmt{ |
|
|
|
|
Expr: PreprocessExpr(expr, start, end), |
|
|
|
|
Start: start, |
|
|
|
|
End: end, |
|
|
|
|
Interval: interval, |
|
|
|
|
LookbackDelta: lookbackDelta, |
|
|
|
|
} |
|
|
|
|
qry := &query{ |
|
|
|
|
q: qs, |
|
|
|
|
stmt: es, |
|
|
|
|
ng: ng, |
|
|
|
|
stats: stats.NewQueryTimers(), |
|
|
|
|
sampleStats: stats.NewQuerySamples(ng.enablePerStepStats && opts.EnablePerStepStats), |
|
|
|
|
queryable: q, |
|
|
|
|
} |
|
|
|
|
return qry, nil |
|
|
|
|
return &es.Expr, qry |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
var ( |
|
|
|
@ -589,18 +595,11 @@ func (ng *Engine) exec(ctx context.Context, q *query) (v parser.Value, ws storag
|
|
|
|
|
execSpanTimer, ctx := q.stats.GetSpanTimer(ctx, stats.ExecTotalTime) |
|
|
|
|
defer execSpanTimer.Finish() |
|
|
|
|
|
|
|
|
|
queueSpanTimer, _ := q.stats.GetSpanTimer(ctx, stats.ExecQueueTime, ng.metrics.queryQueueTime) |
|
|
|
|
// Log query in active log. The active log guarantees that we don't run over
|
|
|
|
|
// MaxConcurrent queries.
|
|
|
|
|
if ng.activeQueryTracker != nil { |
|
|
|
|
queryIndex, err := ng.activeQueryTracker.Insert(ctx, q.q) |
|
|
|
|
if err != nil { |
|
|
|
|
queueSpanTimer.Finish() |
|
|
|
|
return nil, nil, contextErr(err, "query queue") |
|
|
|
|
} |
|
|
|
|
defer ng.activeQueryTracker.Delete(queryIndex) |
|
|
|
|
finishQueue, err := ng.queueActive(ctx, q) |
|
|
|
|
if err != nil { |
|
|
|
|
return nil, nil, err |
|
|
|
|
} |
|
|
|
|
queueSpanTimer.Finish() |
|
|
|
|
defer finishQueue() |
|
|
|
|
|
|
|
|
|
// Cancel when execution is done or an error was raised.
|
|
|
|
|
defer q.cancel() |
|
|
|
@ -623,6 +622,18 @@ func (ng *Engine) exec(ctx context.Context, q *query) (v parser.Value, ws storag
|
|
|
|
|
panic(fmt.Errorf("promql.Engine.exec: unhandled statement of type %T", q.Statement())) |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
// Log query in active log. The active log guarantees that we don't run over
|
|
|
|
|
// MaxConcurrent queries.
|
|
|
|
|
func (ng *Engine) queueActive(ctx context.Context, q *query) (func(), error) { |
|
|
|
|
if ng.activeQueryTracker == nil { |
|
|
|
|
return func() {}, nil |
|
|
|
|
} |
|
|
|
|
queueSpanTimer, _ := q.stats.GetSpanTimer(ctx, stats.ExecQueueTime, ng.metrics.queryQueueTime) |
|
|
|
|
queryIndex, err := ng.activeQueryTracker.Insert(ctx, q.q) |
|
|
|
|
queueSpanTimer.Finish() |
|
|
|
|
return func() { ng.activeQueryTracker.Delete(queryIndex) }, err |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
func timeMilliseconds(t time.Time) int64 { |
|
|
|
|
return t.UnixNano() / int64(time.Millisecond/time.Nanosecond) |
|
|
|
|
} |
|
|
|
|