Store function implementations independently of their signatures

Signed-off-by: Tobias Guggenmos <tguggenm@redhat.com>
This commit is contained in:
Tobias Guggenmos 2020-02-03 18:19:54 +01:00
parent ff0ea1c1ac
commit 9a1366775e
3 changed files with 87 additions and 336 deletions

View file

@ -698,7 +698,7 @@ func (ng *Engine) populateSeries(ctx context.Context, q storage.Queryable, s *pa
level.Error(ng.logger).Log("msg", "error selecting series set", "err", err) level.Error(ng.logger).Log("msg", "error selecting series set", "err", err)
return err return err
} }
n.unexpandedSeriesSet = set n.UnexpandedSeriesSet = set
case *parser.MatrixSelector: case *parser.MatrixSelector:
evalRange = n.Range evalRange = n.Range
@ -744,12 +744,12 @@ func checkForSeriesSetExpansion(ctx context.Context, expr parser.Expr) {
case *parser.MatrixSelector: case *parser.MatrixSelector:
checkForSeriesSetExpansion(ctx, e.VectorSelector) checkForSeriesSetExpansion(ctx, e.VectorSelector)
case *parser.VectorSelector: case *parser.VectorSelector:
if e.series == nil { if e.Series == nil {
series, err := expandSeriesSet(ctx, e.unexpandedSeriesSet) series, err := expandSeriesSet(ctx, e.UnexpandedSeriesSet)
if err != nil { if err != nil {
panic(err) panic(err)
} else { } else {
e.series = series e.Series = series
} }
} }
} }
@ -1003,14 +1003,14 @@ func (ev *evaluator) evalSubquery(subq *parser.SubqueryExpr) *parser.MatrixSelec
val := ev.eval(subq).(Matrix) val := ev.eval(subq).(Matrix)
vs := &parser.VectorSelector{ vs := &parser.VectorSelector{
Offset: subq.Offset, Offset: subq.Offset,
series: make([]storage.Series, 0, len(val)), Series: make([]storage.Series, 0, len(val)),
} }
ms := &parser.MatrixSelector{ ms := &parser.MatrixSelector{
Range: subq.Range, Range: subq.Range,
parser.VectorSelector: vs, VectorSelector: vs,
} }
for _, s := range val { for _, s := range val {
vs.series = append(vs.series, NewStorageSeries(s)) vs.Series = append(vs.Series, NewStorageSeries(s))
} }
return ms return ms
} }
@ -1025,12 +1025,12 @@ func (ev *evaluator) eval(expr parser.Expr) parser.Value {
numSteps := int((ev.endTimestamp-ev.startTimestamp)/ev.interval) + 1 numSteps := int((ev.endTimestamp-ev.startTimestamp)/ev.interval) + 1
switch e := expr.(type) { switch e := expr.(type) {
case *AggregateExpr: case *parser.AggregateExpr:
unwrapParenExpr(&e.Param) unwrapParenExpr(&e.Param)
if s, ok := e.Param.(*StringLiteral); ok { if s, ok := e.Param.(*parser.StringLiteral); ok {
return ev.rangeEval(func(v []parser.Value, enh *EvalNodeHelper) Vector { return ev.rangeEval(func(v []parser.Value, enh *EvalNodeHelper) Vector {
return ev.aggregation(e.Op, e.Grouping, e.Without, s.Val, v[0].(Vector), enh) return ev.aggregation(e.Op, e.Grouping, e.Without, s.Val, v[0].(Vector), enh)
}, e.parser.Expr) }, e.Expr)
} }
return ev.rangeEval(func(v []parser.Value, enh *EvalNodeHelper) Vector { return ev.rangeEval(func(v []parser.Value, enh *EvalNodeHelper) Vector {
var param float64 var param float64
@ -1038,9 +1038,9 @@ func (ev *evaluator) eval(expr parser.Expr) parser.Value {
param = v[0].(Vector)[0].V param = v[0].(Vector)[0].V
} }
return ev.aggregation(e.Op, e.Grouping, e.Without, param, v[1].(Vector), enh) return ev.aggregation(e.Op, e.Grouping, e.Without, param, v[1].(Vector), enh)
}, e.Param, e.parser.Expr) }, e.Param, e.Expr)
case *Call: case *parser.Call:
if e.Func.Name == "timestamp" { if e.Func.Name == "timestamp" {
// Matrix evaluation always returns the evaluation time, // Matrix evaluation always returns the evaluation time,
// so this function needs special handling when given // so this function needs special handling when given
@ -1048,11 +1048,13 @@ func (ev *evaluator) eval(expr parser.Expr) parser.Value {
vs, ok := e.Args[0].(*parser.VectorSelector) vs, ok := e.Args[0].(*parser.VectorSelector)
if ok { if ok {
return ev.rangeEval(func(v []parser.Value, enh *EvalNodeHelper) Vector { return ev.rangeEval(func(v []parser.Value, enh *EvalNodeHelper) Vector {
return e.Func.Call([]parser.Value{ev.vectorSelector(vs, enh.ts)}, e.Args, enh) return funcTimestamp([]parser.Value{ev.vectorSelector(vs, enh.ts)}, e.Args, enh)
}) })
} }
} }
call := FunctionCalls[e.Func.Name]
// Check if the function has a matrix argument. // Check if the function has a matrix argument.
var matrixArgIndex int var matrixArgIndex int
var matrixArg bool var matrixArg bool
@ -1076,7 +1078,7 @@ func (ev *evaluator) eval(expr parser.Expr) parser.Value {
if !matrixArg { if !matrixArg {
// Does not have a matrix argument. // Does not have a matrix argument.
return ev.rangeEval(func(v []parser.Value, enh *EvalNodeHelper) Vector { return ev.rangeEval(func(v []parser.Value, enh *EvalNodeHelper) Vector {
return e.Func.Call(v, e.Args, enh) return call(v, e.Args, enh)
}, e.Args...) }, e.Args...)
} }
@ -1093,7 +1095,7 @@ func (ev *evaluator) eval(expr parser.Expr) parser.Value {
} }
sel := e.Args[matrixArgIndex].(*parser.MatrixSelector) sel := e.Args[matrixArgIndex].(*parser.MatrixSelector)
selVS := sel.parser.VectorSelector.(*parser.VectorSelector) selVS := sel.VectorSelector.(*parser.VectorSelector)
checkForSeriesSetExpansion(ev.ctx, sel) checkForSeriesSetExpansion(ev.ctx, sel)
mat := make(Matrix, 0, len(selVS.series)) // Output matrix. mat := make(Matrix, 0, len(selVS.series)) // Output matrix.

View file

@ -28,29 +28,22 @@ import (
"github.com/prometheus/prometheus/promql/parser" "github.com/prometheus/prometheus/promql/parser"
) )
// Function represents a function of the expression language and is // FunctionCall is the type of a PromQL function implementation
// used by function nodes. //
type Function struct { // vals is a list of the evaluated arguments for the function call.
Name string // For range vectors it will be a Matrix with one series, instant vectors a
ArgTypes []parser.ValueType // Vector, scalars a Vector with one series whose value is the scalar
Variadic int // value,and nil for strings.
ReturnType parser.ValueType // args are the original arguments to the function, where you can access
// matrixSelectors, vectorSelectors, and StringLiterals.
// vals is a list of the evaluated arguments for the function call. // enh.out is a pre-allocated empty vector that you may use to accumulate
// For range vectors it will be a Matrix with one series, instant vectors a // output before returning it. The vectors in vals should not be returned.a
// Vector, scalars a Vector with one series whose value is the scalar // Range vector functions need only return a vector with the right value,
// value,and nil for strings. // the metric and timestamp are not needed.
// args are the original arguments to the function, where you can access // Instant vector functions need only return a vector with the right values and
// matrixSelectors, vectorSelectors, and StringLiterals. // metrics, the timestamp are not needed.
// enh.out is a pre-allocated empty vector that you may use to accumulate // Scalar results should be returned as the value of a sample in a Vector.
// output before returning it. The vectors in vals should not be returned.a type FunctionCall func(vals []parser.Value, args parser.Expressions, enh *EvalNodeHelper) Vector
// Range vector functions need only return a vector with the right value,
// the metric and timestamp are not needed.
// Instant vector functions need only return a vector with the right values and
// metrics, the timestamp are not needed.
// Scalar results should be returned as the value of a sample in a Vector.
Call func(vals []parser.Value, args parser.Expressions, enh *EvalNodeHelper) Vector
}
// === time() float64 === // === time() float64 ===
func funcTime(vals []parser.Value, args parser.Expressions, enh *EvalNodeHelper) Vector { func funcTime(vals []parser.Value, args parser.Expressions, enh *EvalNodeHelper) Vector {
@ -614,7 +607,7 @@ func funcHistogramQuantile(vals []parser.Value, args parser.Expressions, enh *Ev
} }
} }
for _, el := range inVec { for _, el := range inVec {
upperBound, err := strconv.parser.ParseFloat( upperBound, err := strconv.ParseFloat(
el.Metric.Get(model.BucketLabel), 64, el.Metric.Get(model.BucketLabel), 64,
) )
if err != nil { if err != nil {
@ -877,303 +870,59 @@ func funcYear(vals []parser.Value, args parser.Expressions, enh *EvalNodeHelper)
} }
// Functions is a list of all functions supported by PromQL, including their types. // Functions is a list of all functions supported by PromQL, including their types.
var Functions = map[string]*Function{ var FunctionCalls = map[string]FunctionCall{
"abs": { "abs": funcAbs,
Name: "abs", "absent": funcAbsent,
ArgTypes: []parser.ValueType{parser.ValueTypeVector}, "absent_over_time": funcAbsentOverTime,
ReturnType: parser.ValueTypeVector, "avg_over_time": funcAvgOverTime,
Call: funcAbs, "ceil": funcCeil,
}, "changes": funcChanges,
"absent": { "clamp_max": funcClampMax,
Name: "absent", "clamp_min": funcClampMin,
ArgTypes: []parser.ValueType{parser.ValueTypeVector}, "count_over_time": funcCountOverTime,
ReturnType: parser.ValueTypeVector, "days_in_month": funcDaysInMonth,
Call: funcAbsent, "day_of_month": funcDayOfMonth,
}, "day_of_week": funcDayOfWeek,
"absent_over_time": { "delta": funcDelta,
Name: "absent_over_time", "deriv": funcDeriv,
ArgTypes: []parser.ValueType{parser.ValueTypeMatrix}, "exp": funcExp,
ReturnType: parser.ValueTypeVector, "floor": funcFloor,
Call: funcAbsentOverTime, "histogram_quantile": funcHistogramQuantile,
}, "holt_winters": funcHoltWinters,
"avg_over_time": { "hour": parser.ValueTypeVector,
Name: "avg_over_time", "idelta": funcIdelta,
ArgTypes: []parser.ValueType{parser.ValueTypeMatrix}, "increase": funcIncrease,
ReturnType: parser.ValueTypeVector, "irate": funcIrate,
Call: funcAvgOverTime, "label_replace": funcLabelReplace,
}, "label_join": funcLabelJoin,
"ceil": { "ln": funcLn,
Name: "ceil", "log10": funcLog10,
ArgTypes: []parser.ValueType{parser.ValueTypeVector}, "log2": funcLog2,
ReturnType: parser.ValueTypeVector, "max_over_time": funcMaxOverTime,
Call: funcCeil, "min_over_time": funcMinOverTime,
}, "minute": funcMinute,
"changes": { "month": funcMonth,
Name: "changes", "predict_linear": funcPredictLinear,
ArgTypes: []parser.ValueType{parser.ValueTypeMatrix}, "quantile_over_time": funcQuantileOverTime,
ReturnType: parser.ValueTypeVector, "rate": funcRate,
Call: funcChanges, "resets": funcResets,
}, "round": funcRound,
"clamp_max": { "scalar": funcScalar,
Name: "clamp_max", "sort": funcSort,
ArgTypes: []parser.ValueType{parser.ValueTypeVector, parser.ValueTypeScalar}, "sort_desc": funcSortDesc,
ReturnType: parser.ValueTypeVector, "sqrt": funcSqrt,
Call: funcClampMax, "stddev_over_time": funcStddevOverTime,
}, "stdvar_over_time": funcStdvarOverTime,
"clamp_min": { "sum_over_time": funcSumOverTime,
Name: "clamp_min", "time": funcTime,
ArgTypes: []parser.ValueType{parser.ValueTypeVector, parser.ValueTypeScalar}, "timestamp": funcTimestamp,
ReturnType: parser.ValueTypeVector, "vector": funcVector,
Call: funcClampMin, "year": funcYear,
},
"count_over_time": {
Name: "count_over_time",
ArgTypes: []parser.ValueType{parser.ValueTypeMatrix},
ReturnType: parser.ValueTypeVector,
Call: funcCountOverTime,
},
"days_in_month": {
Name: "days_in_month",
ArgTypes: []parser.ValueType{parser.ValueTypeVector},
Variadic: 1,
ReturnType: parser.ValueTypeVector,
Call: funcDaysInMonth,
},
"day_of_month": {
Name: "day_of_month",
ArgTypes: []parser.ValueType{parser.ValueTypeVector},
Variadic: 1,
ReturnType: parser.ValueTypeVector,
Call: funcDayOfMonth,
},
"day_of_week": {
Name: "day_of_week",
ArgTypes: []parser.ValueType{parser.ValueTypeVector},
Variadic: 1,
ReturnType: parser.ValueTypeVector,
Call: funcDayOfWeek,
},
"delta": {
Name: "delta",
ArgTypes: []parser.ValueType{parser.ValueTypeMatrix},
ReturnType: parser.ValueTypeVector,
Call: funcDelta,
},
"deriv": {
Name: "deriv",
ArgTypes: []parser.ValueType{parser.ValueTypeMatrix},
ReturnType: parser.ValueTypeVector,
Call: funcDeriv,
},
"exp": {
Name: "exp",
ArgTypes: []parser.ValueType{parser.ValueTypeVector},
ReturnType: parser.ValueTypeVector,
Call: funcExp,
},
"floor": {
Name: "floor",
ArgTypes: []parser.ValueType{parser.ValueTypeVector},
ReturnType: parser.ValueTypeVector,
Call: funcFloor,
},
"histogram_quantile": {
Name: "histogram_quantile",
ArgTypes: []parser.ValueType{parser.ValueTypeScalar, parser.ValueTypeVector},
ReturnType: parser.ValueTypeVector,
Call: funcHistogramQuantile,
},
"holt_winters": {
Name: "holt_winters",
ArgTypes: []parser.ValueType{parser.ValueTypeMatrix, parser.ValueTypeScalar, parser.ValueTypeScalar},
ReturnType: parser.ValueTypeVector,
Call: funcHoltWinters,
},
"hour": {
Name: "hour",
ArgTypes: []parser.ValueType{parser.ValueTypeVector},
Variadic: 1,
ReturnType: parser.ValueTypeVector,
Call: funcHour,
},
"idelta": {
Name: "idelta",
ArgTypes: []parser.ValueType{parser.ValueTypeMatrix},
ReturnType: parser.ValueTypeVector,
Call: funcIdelta,
},
"increase": {
Name: "increase",
ArgTypes: []parser.ValueType{parser.ValueTypeMatrix},
ReturnType: parser.ValueTypeVector,
Call: funcIncrease,
},
"irate": {
Name: "irate",
ArgTypes: []parser.ValueType{parser.ValueTypeMatrix},
ReturnType: parser.ValueTypeVector,
Call: funcIrate,
},
"label_replace": {
Name: "label_replace",
ArgTypes: []parser.ValueType{parser.ValueTypeVector, parser.ValueTypeString, parser.ValueTypeString, parser.ValueTypeString, parser.ValueTypeString},
ReturnType: parser.ValueTypeVector,
Call: funcLabelReplace,
},
"label_join": {
Name: "label_join",
ArgTypes: []parser.ValueType{parser.ValueTypeVector, parser.ValueTypeString, parser.ValueTypeString, parser.ValueTypeString},
Variadic: -1,
ReturnType: parser.ValueTypeVector,
Call: funcLabelJoin,
},
"ln": {
Name: "ln",
ArgTypes: []parser.ValueType{parser.ValueTypeVector},
ReturnType: parser.ValueTypeVector,
Call: funcLn,
},
"log10": {
Name: "log10",
ArgTypes: []parser.ValueType{parser.ValueTypeVector},
ReturnType: parser.ValueTypeVector,
Call: funcLog10,
},
"log2": {
Name: "log2",
ArgTypes: []parser.ValueType{parser.ValueTypeVector},
ReturnType: parser.ValueTypeVector,
Call: funcLog2,
},
"max_over_time": {
Name: "max_over_time",
ArgTypes: []parser.ValueType{parser.ValueTypeMatrix},
ReturnType: parser.ValueTypeVector,
Call: funcMaxOverTime,
},
"min_over_time": {
Name: "min_over_time",
ArgTypes: []parser.ValueType{parser.ValueTypeMatrix},
ReturnType: parser.ValueTypeVector,
Call: funcMinOverTime,
},
"minute": {
Name: "minute",
ArgTypes: []parser.ValueType{parser.ValueTypeVector},
Variadic: 1,
ReturnType: parser.ValueTypeVector,
Call: funcMinute,
},
"month": {
Name: "month",
ArgTypes: []parser.ValueType{parser.ValueTypeVector},
Variadic: 1,
ReturnType: parser.ValueTypeVector,
Call: funcMonth,
},
"predict_linear": {
Name: "predict_linear",
ArgTypes: []parser.ValueType{parser.ValueTypeMatrix, parser.ValueTypeScalar},
ReturnType: parser.ValueTypeVector,
Call: funcPredictLinear,
},
"quantile_over_time": {
Name: "quantile_over_time",
ArgTypes: []parser.ValueType{parser.ValueTypeScalar, parser.ValueTypeMatrix},
ReturnType: parser.ValueTypeVector,
Call: funcQuantileOverTime,
},
"rate": {
Name: "rate",
ArgTypes: []parser.ValueType{parser.ValueTypeMatrix},
ReturnType: parser.ValueTypeVector,
Call: funcRate,
},
"resets": {
Name: "resets",
ArgTypes: []parser.ValueType{parser.ValueTypeMatrix},
ReturnType: parser.ValueTypeVector,
Call: funcResets,
},
"round": {
Name: "round",
ArgTypes: []parser.ValueType{parser.ValueTypeVector, parser.ValueTypeScalar},
Variadic: 1,
ReturnType: parser.ValueTypeVector,
Call: funcRound,
},
"scalar": {
Name: "scalar",
ArgTypes: []parser.ValueType{parser.ValueTypeVector},
ReturnType: parser.ValueTypeScalar,
Call: funcScalar,
},
"sort": {
Name: "sort",
ArgTypes: []parser.ValueType{parser.ValueTypeVector},
ReturnType: parser.ValueTypeVector,
Call: funcSort,
},
"sort_desc": {
Name: "sort_desc",
ArgTypes: []parser.ValueType{parser.ValueTypeVector},
ReturnType: parser.ValueTypeVector,
Call: funcSortDesc,
},
"sqrt": {
Name: "sqrt",
ArgTypes: []parser.ValueType{parser.ValueTypeVector},
ReturnType: parser.ValueTypeVector,
Call: funcSqrt,
},
"stddev_over_time": {
Name: "stddev_over_time",
ArgTypes: []parser.ValueType{parser.ValueTypeMatrix},
ReturnType: parser.ValueTypeVector,
Call: funcStddevOverTime,
},
"stdvar_over_time": {
Name: "stdvar_over_time",
ArgTypes: []parser.ValueType{parser.ValueTypeMatrix},
ReturnType: parser.ValueTypeVector,
Call: funcStdvarOverTime,
},
"sum_over_time": {
Name: "sum_over_time",
ArgTypes: []parser.ValueType{parser.ValueTypeMatrix},
ReturnType: parser.ValueTypeVector,
Call: funcSumOverTime,
},
"time": {
Name: "time",
ArgTypes: []parser.ValueType{},
ReturnType: parser.ValueTypeScalar,
Call: funcTime,
},
"timestamp": {
Name: "timestamp",
ArgTypes: []parser.ValueType{parser.ValueTypeVector},
ReturnType: parser.ValueTypeVector,
Call: funcTimestamp,
},
"vector": {
Name: "vector",
ArgTypes: []parser.ValueType{parser.ValueTypeScalar},
ReturnType: parser.ValueTypeVector,
Call: funcVector,
},
"year": {
Name: "year",
ArgTypes: []parser.ValueType{parser.ValueTypeVector},
Variadic: 1,
ReturnType: parser.ValueTypeVector,
Call: funcYear,
},
} }
// getFunction returns a predefined Function object for the given name. // getFunction returns a predefined Function object for the given name.
func getFunction(name string) (*Function, bool) { func getFunctionCall(name string) (FunctionCall, bool) {
function, ok := Functions[name] function, ok := FunctionCalls[name]
return function, ok return function, ok
} }

View file

@ -168,8 +168,8 @@ type VectorSelector struct {
LabelMatchers []*labels.Matcher LabelMatchers []*labels.Matcher
// The unexpanded seriesSet populated at query preparation time. // The unexpanded seriesSet populated at query preparation time.
unexpandedSeriesSet storage.SeriesSet UnexpandedSeriesSet storage.SeriesSet
series []storage.Series Series []storage.Series
PosRange PositionRange PosRange PositionRange
} }