Export members of EvalNodeHelper to facilitate usage in external functions (#7860)

Signed-off-by: Vijay Samuel <vjsamuel@ebay.com>
This commit is contained in:
Vijay Samuel 2020-08-27 11:30:10 -07:00 committed by GitHub
parent c806262206
commit 00ee73ef91
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
2 changed files with 98 additions and 98 deletions

View file

@ -792,13 +792,13 @@ func (ev *evaluator) Eval(expr parser.Expr) (v parser.Value, ws storage.Warnings
// EvalNodeHelper stores extra information and caches for evaluating a single node across steps. // EvalNodeHelper stores extra information and caches for evaluating a single node across steps.
type EvalNodeHelper struct { type EvalNodeHelper struct {
// Evaluation timestamp. // Evaluation timestamp.
ts int64 Ts int64
// Vector that can be used for output. // Vector that can be used for output.
out Vector Out Vector
// Caches. // Caches.
// dropMetricName and label_*. // DropMetricName and label_*.
dmn map[uint64]labels.Labels Dmn map[uint64]labels.Labels
// signatureFunc. // signatureFunc.
sigf map[string]string sigf map[string]string
// funcHistogramQuantile. // funcHistogramQuantile.
@ -816,24 +816,24 @@ type EvalNodeHelper struct {
resultMetric map[string]labels.Labels resultMetric map[string]labels.Labels
} }
// dropMetricName is a cached version of dropMetricName. // DropMetricName is a cached version of DropMetricName.
func (enh *EvalNodeHelper) dropMetricName(l labels.Labels) labels.Labels { func (enh *EvalNodeHelper) DropMetricName(l labels.Labels) labels.Labels {
if enh.dmn == nil { if enh.Dmn == nil {
enh.dmn = make(map[uint64]labels.Labels, len(enh.out)) enh.Dmn = make(map[uint64]labels.Labels, len(enh.Out))
} }
h := l.Hash() h := l.Hash()
ret, ok := enh.dmn[h] ret, ok := enh.Dmn[h]
if ok { if ok {
return ret return ret
} }
ret = dropMetricName(l) ret = dropMetricName(l)
enh.dmn[h] = ret enh.Dmn[h] = ret
return ret return ret
} }
func (enh *EvalNodeHelper) signatureFunc(on bool, names ...string) func(labels.Labels) string { func (enh *EvalNodeHelper) signatureFunc(on bool, names ...string) func(labels.Labels) string {
if enh.sigf == nil { if enh.sigf == nil {
enh.sigf = make(map[string]string, len(enh.out)) enh.sigf = make(map[string]string, len(enh.Out))
} }
f := signatureFunc(on, enh.lblBuf, names...) f := signatureFunc(on, enh.lblBuf, names...)
return func(l labels.Labels) string { return func(l labels.Labels) string {
@ -885,7 +885,7 @@ func (ev *evaluator) rangeEval(f func([]parser.Value, *EvalNodeHelper) (Vector,
biggestLen = len(matrixes[i]) biggestLen = len(matrixes[i])
} }
} }
enh := &EvalNodeHelper{out: make(Vector, 0, biggestLen)} enh := &EvalNodeHelper{Out: make(Vector, 0, biggestLen)}
seriess := make(map[uint64]Series, biggestLen) // Output series by series hash. seriess := make(map[uint64]Series, biggestLen) // Output series by series hash.
tempNumSamples := ev.currentSamples tempNumSamples := ev.currentSamples
for ts := ev.startTimestamp; ts <= ev.endTimestamp; ts += ev.interval { for ts := ev.startTimestamp; ts <= ev.endTimestamp; ts += ev.interval {
@ -916,12 +916,12 @@ func (ev *evaluator) rangeEval(f func([]parser.Value, *EvalNodeHelper) (Vector,
args[i] = vectors[i] args[i] = vectors[i]
} }
// Make the function call. // Make the function call.
enh.ts = ts enh.Ts = ts
result, ws := f(args, enh) result, ws := f(args, enh)
if result.ContainsSameLabelset() { if result.ContainsSameLabelset() {
ev.errorf("vector cannot contain metrics with the same labelset") ev.errorf("vector cannot contain metrics with the same labelset")
} }
enh.out = result[:0] // Reuse result vector. enh.Out = result[:0] // Reuse result vector.
warnings = append(warnings, ws...) warnings = append(warnings, ws...)
ev.currentSamples += len(result) ev.currentSamples += len(result)
@ -1030,7 +1030,7 @@ func (ev *evaluator) eval(expr parser.Expr) (parser.Value, storage.Warnings) {
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, storage.Warnings) { return ev.rangeEval(func(v []parser.Value, enh *EvalNodeHelper) (Vector, storage.Warnings) {
val, ws := ev.vectorSelector(vs, enh.ts) val, ws := ev.vectorSelector(vs, enh.Ts)
return call([]parser.Value{val}, e.Args, enh), ws return call([]parser.Value{val}, e.Args, enh), ws
}) })
} }
@ -1101,7 +1101,7 @@ func (ev *evaluator) eval(expr parser.Expr) (parser.Value, storage.Warnings) {
points := getPointSlice(16) points := getPointSlice(16)
inMatrix := make(Matrix, 1) inMatrix := make(Matrix, 1)
inArgs[matrixArgIndex] = inMatrix inArgs[matrixArgIndex] = inMatrix
enh := &EvalNodeHelper{out: make(Vector, 0, 1)} enh := &EvalNodeHelper{Out: make(Vector, 0, 1)}
// Process all the calls for one time series at a time. // Process all the calls for one time series at a time.
it := storage.NewBuffer(selRange) it := storage.NewBuffer(selRange)
for i, s := range selVS.Series { for i, s := range selVS.Series {
@ -1134,10 +1134,10 @@ func (ev *evaluator) eval(expr parser.Expr) (parser.Value, storage.Warnings) {
continue continue
} }
inMatrix[0].Points = points inMatrix[0].Points = points
enh.ts = ts enh.Ts = ts
// Make the function call. // Make the function call.
outVec := call(inArgs, e.Args, enh) outVec := call(inArgs, e.Args, enh)
enh.out = outVec[:0] enh.Out = outVec[:0]
if len(outVec) > 0 { if len(outVec) > 0 {
ss.Points = append(ss.Points, Point{V: outVec[0].Point.V, T: ts}) ss.Points = append(ss.Points, Point{V: outVec[0].Point.V, T: ts})
} }
@ -1227,7 +1227,7 @@ func (ev *evaluator) eval(expr parser.Expr) (parser.Value, storage.Warnings) {
case lt == parser.ValueTypeScalar && rt == parser.ValueTypeScalar: case lt == parser.ValueTypeScalar && rt == parser.ValueTypeScalar:
return ev.rangeEval(func(v []parser.Value, enh *EvalNodeHelper) (Vector, storage.Warnings) { return ev.rangeEval(func(v []parser.Value, enh *EvalNodeHelper) (Vector, storage.Warnings) {
val := scalarBinop(e.Op, v[0].(Vector)[0].Point.V, v[1].(Vector)[0].Point.V) val := scalarBinop(e.Op, v[0].(Vector)[0].Point.V, v[1].(Vector)[0].Point.V)
return append(enh.out, Sample{Point: Point{V: val}}), nil return append(enh.Out, Sample{Point: Point{V: val}}), nil
}, e.LHS, e.RHS) }, e.LHS, e.RHS)
case lt == parser.ValueTypeVector && rt == parser.ValueTypeVector: case lt == parser.ValueTypeVector && rt == parser.ValueTypeVector:
switch e.Op { switch e.Op {
@ -1262,7 +1262,7 @@ func (ev *evaluator) eval(expr parser.Expr) (parser.Value, storage.Warnings) {
case *parser.NumberLiteral: case *parser.NumberLiteral:
return ev.rangeEval(func(v []parser.Value, enh *EvalNodeHelper) (Vector, storage.Warnings) { return ev.rangeEval(func(v []parser.Value, enh *EvalNodeHelper) (Vector, storage.Warnings) {
return append(enh.out, Sample{Point: Point{V: e.Val}}), nil return append(enh.Out, Sample{Point: Point{V: e.Val}}), nil
}) })
case *parser.VectorSelector: case *parser.VectorSelector:
@ -1530,10 +1530,10 @@ func (ev *evaluator) VectorAnd(lhs, rhs Vector, matching *parser.VectorMatching,
for _, ls := range lhs { for _, ls := range lhs {
// If there's a matching entry in the right-hand side Vector, add the sample. // If there's a matching entry in the right-hand side Vector, add the sample.
if _, ok := rightSigs[sigf(ls.Metric)]; ok { if _, ok := rightSigs[sigf(ls.Metric)]; ok {
enh.out = append(enh.out, ls) enh.Out = append(enh.Out, ls)
} }
} }
return enh.out return enh.Out
} }
func (ev *evaluator) VectorOr(lhs, rhs Vector, matching *parser.VectorMatching, enh *EvalNodeHelper) Vector { func (ev *evaluator) VectorOr(lhs, rhs Vector, matching *parser.VectorMatching, enh *EvalNodeHelper) Vector {
@ -1546,15 +1546,15 @@ func (ev *evaluator) VectorOr(lhs, rhs Vector, matching *parser.VectorMatching,
// Add everything from the left-hand-side Vector. // Add everything from the left-hand-side Vector.
for _, ls := range lhs { for _, ls := range lhs {
leftSigs[sigf(ls.Metric)] = struct{}{} leftSigs[sigf(ls.Metric)] = struct{}{}
enh.out = append(enh.out, ls) enh.Out = append(enh.Out, ls)
} }
// Add all right-hand side elements which have not been added from the left-hand side. // Add all right-hand side elements which have not been added from the left-hand side.
for _, rs := range rhs { for _, rs := range rhs {
if _, ok := leftSigs[sigf(rs.Metric)]; !ok { if _, ok := leftSigs[sigf(rs.Metric)]; !ok {
enh.out = append(enh.out, rs) enh.Out = append(enh.Out, rs)
} }
} }
return enh.out return enh.Out
} }
func (ev *evaluator) VectorUnless(lhs, rhs Vector, matching *parser.VectorMatching, enh *EvalNodeHelper) Vector { func (ev *evaluator) VectorUnless(lhs, rhs Vector, matching *parser.VectorMatching, enh *EvalNodeHelper) Vector {
@ -1570,10 +1570,10 @@ func (ev *evaluator) VectorUnless(lhs, rhs Vector, matching *parser.VectorMatchi
for _, ls := range lhs { for _, ls := range lhs {
if _, ok := rightSigs[sigf(ls.Metric)]; !ok { if _, ok := rightSigs[sigf(ls.Metric)]; !ok {
enh.out = append(enh.out, ls) enh.Out = append(enh.Out, ls)
} }
} }
return enh.out return enh.Out
} }
// VectorBinop evaluates a binary operation between two Vectors, excluding set operators. // VectorBinop evaluates a binary operation between two Vectors, excluding set operators.
@ -1592,7 +1592,7 @@ func (ev *evaluator) VectorBinop(op parser.ItemType, lhs, rhs Vector, matching *
// All samples from the rhs hashed by the matching label/values. // All samples from the rhs hashed by the matching label/values.
if enh.rightSigs == nil { if enh.rightSigs == nil {
enh.rightSigs = make(map[string]Sample, len(enh.out)) enh.rightSigs = make(map[string]Sample, len(enh.Out))
} else { } else {
for k := range enh.rightSigs { for k := range enh.rightSigs {
delete(enh.rightSigs, k) delete(enh.rightSigs, k)
@ -1657,7 +1657,7 @@ func (ev *evaluator) VectorBinop(op parser.ItemType, lhs, rhs Vector, matching *
} }
metric := resultMetric(ls.Metric, rs.Metric, op, matching, enh) metric := resultMetric(ls.Metric, rs.Metric, op, matching, enh)
if returnBool { if returnBool {
metric = enh.dropMetricName(metric) metric = enh.DropMetricName(metric)
} }
insertedSigs, exists := matchedSigs[sig] insertedSigs, exists := matchedSigs[sig]
if matching.Card == parser.CardOneToOne { if matching.Card == parser.CardOneToOne {
@ -1680,12 +1680,12 @@ func (ev *evaluator) VectorBinop(op parser.ItemType, lhs, rhs Vector, matching *
insertedSigs[insertSig] = struct{}{} insertedSigs[insertSig] = struct{}{}
} }
enh.out = append(enh.out, Sample{ enh.Out = append(enh.Out, Sample{
Metric: metric, Metric: metric,
Point: Point{V: value}, Point: Point{V: value},
}) })
} }
return enh.out return enh.Out
} }
func signatureFunc(on bool, b []byte, names ...string) func(labels.Labels) string { func signatureFunc(on bool, b []byte, names ...string) func(labels.Labels) string {
@ -1704,7 +1704,7 @@ func signatureFunc(on bool, b []byte, names ...string) func(labels.Labels) strin
// binary operation and the matching options. // binary operation and the matching options.
func resultMetric(lhs, rhs labels.Labels, op parser.ItemType, matching *parser.VectorMatching, enh *EvalNodeHelper) labels.Labels { func resultMetric(lhs, rhs labels.Labels, op parser.ItemType, matching *parser.VectorMatching, enh *EvalNodeHelper) labels.Labels {
if enh.resultMetric == nil { if enh.resultMetric == nil {
enh.resultMetric = make(map[string]labels.Labels, len(enh.out)) enh.resultMetric = make(map[string]labels.Labels, len(enh.Out))
} }
if enh.lb == nil { if enh.lb == nil {
@ -1784,12 +1784,12 @@ func (ev *evaluator) VectorscalarBinop(op parser.ItemType, lhs Vector, rhs Scala
if keep { if keep {
lhsSample.V = value lhsSample.V = value
if shouldDropMetricName(op) || returnBool { if shouldDropMetricName(op) || returnBool {
lhsSample.Metric = enh.dropMetricName(lhsSample.Metric) lhsSample.Metric = enh.DropMetricName(lhsSample.Metric)
} }
enh.out = append(enh.out, lhsSample) enh.Out = append(enh.Out, lhsSample)
} }
} }
return enh.out return enh.Out
} }
func dropMetricName(l labels.Labels) labels.Labels { func dropMetricName(l labels.Labels) labels.Labels {
@ -2069,7 +2069,7 @@ func (ev *evaluator) aggregation(op parser.ItemType, grouping []string, without
// The heap keeps the lowest value on top, so reverse it. // The heap keeps the lowest value on top, so reverse it.
sort.Sort(sort.Reverse(aggr.heap)) sort.Sort(sort.Reverse(aggr.heap))
for _, v := range aggr.heap { for _, v := range aggr.heap {
enh.out = append(enh.out, Sample{ enh.Out = append(enh.Out, Sample{
Metric: v.Metric, Metric: v.Metric,
Point: Point{V: v.V}, Point: Point{V: v.V},
}) })
@ -2080,7 +2080,7 @@ func (ev *evaluator) aggregation(op parser.ItemType, grouping []string, without
// The heap keeps the lowest value on top, so reverse it. // The heap keeps the lowest value on top, so reverse it.
sort.Sort(sort.Reverse(aggr.reverseHeap)) sort.Sort(sort.Reverse(aggr.reverseHeap))
for _, v := range aggr.reverseHeap { for _, v := range aggr.reverseHeap {
enh.out = append(enh.out, Sample{ enh.Out = append(enh.Out, Sample{
Metric: v.Metric, Metric: v.Metric,
Point: Point{V: v.V}, Point: Point{V: v.V},
}) })
@ -2094,12 +2094,12 @@ func (ev *evaluator) aggregation(op parser.ItemType, grouping []string, without
// For other aggregations, we already have the right value. // For other aggregations, we already have the right value.
} }
enh.out = append(enh.out, Sample{ enh.Out = append(enh.Out, Sample{
Metric: aggr.labels, Metric: aggr.labels,
Point: Point{V: aggr.value}, Point: Point{V: aggr.value},
}) })
} }
return enh.out return enh.Out
} }
// btos returns 1 if b is true, 0 otherwise. // btos returns 1 if b is true, 0 otherwise.

View file

@ -36,7 +36,7 @@ import (
// value,and nil for strings. // value,and nil for strings.
// args are the original arguments to the function, where you can access // args are the original arguments to the function, where you can access
// matrixSelectors, vectorSelectors, and StringLiterals. // matrixSelectors, vectorSelectors, and StringLiterals.
// enh.out is a pre-allocated empty vector that you may use to accumulate // enh.Out is a pre-allocated empty vector that you may use to accumulate
// output before returning it. The vectors in vals should not be returned.a // output before returning it. The vectors in vals should not be returned.a
// Range vector functions need only return a vector with the right value, // Range vector functions need only return a vector with the right value,
// the metric and timestamp are not needed. // the metric and timestamp are not needed.
@ -48,7 +48,7 @@ type FunctionCall func(vals []parser.Value, args parser.Expressions, enh *EvalNo
// === 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 {
return Vector{Sample{Point: Point{ return Vector{Sample{Point: Point{
V: float64(enh.ts) / 1000, V: float64(enh.Ts) / 1000,
}}} }}}
} }
@ -62,14 +62,14 @@ func extrapolatedRate(vals []parser.Value, args parser.Expressions, enh *EvalNod
var ( var (
samples = vals[0].(Matrix)[0] samples = vals[0].(Matrix)[0]
rangeStart = enh.ts - durationMilliseconds(ms.Range+vs.Offset) rangeStart = enh.Ts - durationMilliseconds(ms.Range+vs.Offset)
rangeEnd = enh.ts - durationMilliseconds(vs.Offset) rangeEnd = enh.Ts - durationMilliseconds(vs.Offset)
) )
// No sense in trying to compute a rate without at least two points. Drop // No sense in trying to compute a rate without at least two points. Drop
// this Vector element. // this Vector element.
if len(samples.Points) < 2 { if len(samples.Points) < 2 {
return enh.out return enh.Out
} }
var ( var (
counterCorrection float64 counterCorrection float64
@ -126,7 +126,7 @@ func extrapolatedRate(vals []parser.Value, args parser.Expressions, enh *EvalNod
resultValue = resultValue / ms.Range.Seconds() resultValue = resultValue / ms.Range.Seconds()
} }
return append(enh.out, Sample{ return append(enh.Out, Sample{
Point: Point{V: resultValue}, Point: Point{V: resultValue},
}) })
} }
@ -148,12 +148,12 @@ func funcIncrease(vals []parser.Value, args parser.Expressions, enh *EvalNodeHel
// === irate(node parser.ValueTypeMatrix) Vector === // === irate(node parser.ValueTypeMatrix) Vector ===
func funcIrate(vals []parser.Value, args parser.Expressions, enh *EvalNodeHelper) Vector { func funcIrate(vals []parser.Value, args parser.Expressions, enh *EvalNodeHelper) Vector {
return instantValue(vals, enh.out, true) return instantValue(vals, enh.Out, true)
} }
// === idelta(node model.ValMatrix) Vector === // === idelta(node model.ValMatrix) Vector ===
func funcIdelta(vals []parser.Value, args parser.Expressions, enh *EvalNodeHelper) Vector { func funcIdelta(vals []parser.Value, args parser.Expressions, enh *EvalNodeHelper) Vector {
return instantValue(vals, enh.out, false) return instantValue(vals, enh.Out, false)
} }
func instantValue(vals []parser.Value, out Vector, isRate bool) Vector { func instantValue(vals []parser.Value, out Vector, isRate bool) Vector {
@ -234,7 +234,7 @@ func funcHoltWinters(vals []parser.Value, args parser.Expressions, enh *EvalNode
// Can't do the smoothing operation with less than two points. // Can't do the smoothing operation with less than two points.
if l < 2 { if l < 2 {
return enh.out return enh.Out
} }
var s0, s1, b float64 var s0, s1, b float64
@ -256,7 +256,7 @@ func funcHoltWinters(vals []parser.Value, args parser.Expressions, enh *EvalNode
s0, s1 = s1, x+y s0, s1 = s1, x+y
} }
return append(enh.out, Sample{ return append(enh.Out, Sample{
Point: Point{V: s1}, Point: Point{V: s1},
}) })
} }
@ -284,12 +284,12 @@ func funcClampMax(vals []parser.Value, args parser.Expressions, enh *EvalNodeHel
vec := vals[0].(Vector) vec := vals[0].(Vector)
max := vals[1].(Vector)[0].Point.V max := vals[1].(Vector)[0].Point.V
for _, el := range vec { for _, el := range vec {
enh.out = append(enh.out, Sample{ enh.Out = append(enh.Out, Sample{
Metric: enh.dropMetricName(el.Metric), Metric: enh.DropMetricName(el.Metric),
Point: Point{V: math.Min(max, el.V)}, Point: Point{V: math.Min(max, el.V)},
}) })
} }
return enh.out return enh.Out
} }
// === clamp_min(Vector parser.ValueTypeVector, min Scalar) Vector === // === clamp_min(Vector parser.ValueTypeVector, min Scalar) Vector ===
@ -297,12 +297,12 @@ func funcClampMin(vals []parser.Value, args parser.Expressions, enh *EvalNodeHel
vec := vals[0].(Vector) vec := vals[0].(Vector)
min := vals[1].(Vector)[0].Point.V min := vals[1].(Vector)[0].Point.V
for _, el := range vec { for _, el := range vec {
enh.out = append(enh.out, Sample{ enh.Out = append(enh.Out, Sample{
Metric: enh.dropMetricName(el.Metric), Metric: enh.DropMetricName(el.Metric),
Point: Point{V: math.Max(min, el.V)}, Point: Point{V: math.Max(min, el.V)},
}) })
} }
return enh.out return enh.Out
} }
// === round(Vector parser.ValueTypeVector, toNearest=1 Scalar) Vector === // === round(Vector parser.ValueTypeVector, toNearest=1 Scalar) Vector ===
@ -319,23 +319,23 @@ func funcRound(vals []parser.Value, args parser.Expressions, enh *EvalNodeHelper
for _, el := range vec { for _, el := range vec {
v := math.Floor(el.V*toNearestInverse+0.5) / toNearestInverse v := math.Floor(el.V*toNearestInverse+0.5) / toNearestInverse
enh.out = append(enh.out, Sample{ enh.Out = append(enh.Out, Sample{
Metric: enh.dropMetricName(el.Metric), Metric: enh.DropMetricName(el.Metric),
Point: Point{V: v}, Point: Point{V: v},
}) })
} }
return enh.out return enh.Out
} }
// === Scalar(node parser.ValueTypeVector) Scalar === // === Scalar(node parser.ValueTypeVector) Scalar ===
func funcScalar(vals []parser.Value, args parser.Expressions, enh *EvalNodeHelper) Vector { func funcScalar(vals []parser.Value, args parser.Expressions, enh *EvalNodeHelper) Vector {
v := vals[0].(Vector) v := vals[0].(Vector)
if len(v) != 1 { if len(v) != 1 {
return append(enh.out, Sample{ return append(enh.Out, Sample{
Point: Point{V: math.NaN()}, Point: Point{V: math.NaN()},
}) })
} }
return append(enh.out, Sample{ return append(enh.Out, Sample{
Point: Point{V: v[0].V}, Point: Point{V: v[0].V},
}) })
} }
@ -343,7 +343,7 @@ func funcScalar(vals []parser.Value, args parser.Expressions, enh *EvalNodeHelpe
func aggrOverTime(vals []parser.Value, enh *EvalNodeHelper, aggrFn func([]Point) float64) Vector { func aggrOverTime(vals []parser.Value, enh *EvalNodeHelper, aggrFn func([]Point) float64) Vector {
el := vals[0].(Matrix)[0] el := vals[0].(Matrix)[0]
return append(enh.out, Sample{ return append(enh.Out, Sample{
Point: Point{V: aggrFn(el.Points)}, Point: Point{V: aggrFn(el.Points)},
}) })
} }
@ -431,7 +431,7 @@ func funcQuantileOverTime(vals []parser.Value, args parser.Expressions, enh *Eva
for _, v := range el.Points { for _, v := range el.Points {
values = append(values, Sample{Point: Point{V: v.V}}) values = append(values, Sample{Point: Point{V: v.V}})
} }
return append(enh.out, Sample{ return append(enh.Out, Sample{
Point: Point{V: quantile(q, values)}, Point: Point{V: quantile(q, values)},
}) })
} }
@ -467,9 +467,9 @@ func funcStdvarOverTime(vals []parser.Value, args parser.Expressions, enh *EvalN
// === absent(Vector parser.ValueTypeVector) Vector === // === absent(Vector parser.ValueTypeVector) Vector ===
func funcAbsent(vals []parser.Value, args parser.Expressions, enh *EvalNodeHelper) Vector { func funcAbsent(vals []parser.Value, args parser.Expressions, enh *EvalNodeHelper) Vector {
if len(vals[0].(Vector)) > 0 { if len(vals[0].(Vector)) > 0 {
return enh.out return enh.Out
} }
return append(enh.out, return append(enh.Out,
Sample{ Sample{
Metric: createLabelsForAbsentFunction(args[0]), Metric: createLabelsForAbsentFunction(args[0]),
Point: Point{V: 1}, Point: Point{V: 1},
@ -482,7 +482,7 @@ func funcAbsent(vals []parser.Value, args parser.Expressions, enh *EvalNodeHelpe
// Due to engine optimization, this function is only called when this condition is true. // Due to engine optimization, this function is only called when this condition is true.
// Then, the engine post-processes the results to get the expected output. // Then, the engine post-processes the results to get the expected output.
func funcAbsentOverTime(vals []parser.Value, args parser.Expressions, enh *EvalNodeHelper) Vector { func funcAbsentOverTime(vals []parser.Value, args parser.Expressions, enh *EvalNodeHelper) Vector {
return append(enh.out, return append(enh.Out,
Sample{ Sample{
Point: Point{V: 1}, Point: Point{V: 1},
}) })
@ -490,12 +490,12 @@ func funcAbsentOverTime(vals []parser.Value, args parser.Expressions, enh *EvalN
func simpleFunc(vals []parser.Value, enh *EvalNodeHelper, f func(float64) float64) Vector { func simpleFunc(vals []parser.Value, enh *EvalNodeHelper, f func(float64) float64) Vector {
for _, el := range vals[0].(Vector) { for _, el := range vals[0].(Vector) {
enh.out = append(enh.out, Sample{ enh.Out = append(enh.Out, Sample{
Metric: enh.dropMetricName(el.Metric), Metric: enh.DropMetricName(el.Metric),
Point: Point{V: f(el.V)}, Point: Point{V: f(el.V)},
}) })
} }
return enh.out return enh.Out
} }
// === abs(Vector parser.ValueTypeVector) Vector === // === abs(Vector parser.ValueTypeVector) Vector ===
@ -542,12 +542,12 @@ func funcLog10(vals []parser.Value, args parser.Expressions, enh *EvalNodeHelper
func funcTimestamp(vals []parser.Value, args parser.Expressions, enh *EvalNodeHelper) Vector { func funcTimestamp(vals []parser.Value, args parser.Expressions, enh *EvalNodeHelper) Vector {
vec := vals[0].(Vector) vec := vals[0].(Vector)
for _, el := range vec { for _, el := range vec {
enh.out = append(enh.out, Sample{ enh.Out = append(enh.Out, Sample{
Metric: enh.dropMetricName(el.Metric), Metric: enh.DropMetricName(el.Metric),
Point: Point{V: float64(el.T) / 1000}, Point: Point{V: float64(el.T) / 1000},
}) })
} }
return enh.out return enh.Out
} }
// linearRegression performs a least-square linear regression analysis on the // linearRegression performs a least-square linear regression analysis on the
@ -582,14 +582,14 @@ func funcDeriv(vals []parser.Value, args parser.Expressions, enh *EvalNodeHelper
// No sense in trying to compute a derivative without at least two points. // No sense in trying to compute a derivative without at least two points.
// Drop this Vector element. // Drop this Vector element.
if len(samples.Points) < 2 { if len(samples.Points) < 2 {
return enh.out return enh.Out
} }
// We pass in an arbitrary timestamp that is near the values in use // We pass in an arbitrary timestamp that is near the values in use
// to avoid floating point accuracy issues, see // to avoid floating point accuracy issues, see
// https://github.com/prometheus/prometheus/issues/2674 // https://github.com/prometheus/prometheus/issues/2674
slope, _ := linearRegression(samples.Points, samples.Points[0].T) slope, _ := linearRegression(samples.Points, samples.Points[0].T)
return append(enh.out, Sample{ return append(enh.Out, Sample{
Point: Point{V: slope}, Point: Point{V: slope},
}) })
} }
@ -602,11 +602,11 @@ func funcPredictLinear(vals []parser.Value, args parser.Expressions, enh *EvalNo
// No sense in trying to predict anything without at least two points. // No sense in trying to predict anything without at least two points.
// Drop this Vector element. // Drop this Vector element.
if len(samples.Points) < 2 { if len(samples.Points) < 2 {
return enh.out return enh.Out
} }
slope, intercept := linearRegression(samples.Points, enh.ts) slope, intercept := linearRegression(samples.Points, enh.Ts)
return append(enh.out, Sample{ return append(enh.Out, Sample{
Point: Point{V: slope*duration + intercept}, Point: Point{V: slope*duration + intercept},
}) })
} }
@ -649,14 +649,14 @@ func funcHistogramQuantile(vals []parser.Value, args parser.Expressions, enh *Ev
for _, mb := range enh.signatureToMetricWithBuckets { for _, mb := range enh.signatureToMetricWithBuckets {
if len(mb.buckets) > 0 { if len(mb.buckets) > 0 {
enh.out = append(enh.out, Sample{ enh.Out = append(enh.Out, Sample{
Metric: mb.metric, Metric: mb.metric,
Point: Point{V: bucketQuantile(q, mb.buckets)}, Point: Point{V: bucketQuantile(q, mb.buckets)},
}) })
} }
} }
return enh.out return enh.Out
} }
// === resets(Matrix parser.ValueTypeMatrix) Vector === // === resets(Matrix parser.ValueTypeMatrix) Vector ===
@ -673,7 +673,7 @@ func funcResets(vals []parser.Value, args parser.Expressions, enh *EvalNodeHelpe
prev = current prev = current
} }
return append(enh.out, Sample{ return append(enh.Out, Sample{
Point: Point{V: float64(resets)}, Point: Point{V: float64(resets)},
}) })
} }
@ -692,7 +692,7 @@ func funcChanges(vals []parser.Value, args parser.Expressions, enh *EvalNodeHelp
prev = current prev = current
} }
return append(enh.out, Sample{ return append(enh.Out, Sample{
Point: Point{V: float64(changes)}, Point: Point{V: float64(changes)},
}) })
} }
@ -716,13 +716,13 @@ func funcLabelReplace(vals []parser.Value, args parser.Expressions, enh *EvalNod
if !model.LabelNameRE.MatchString(dst) { if !model.LabelNameRE.MatchString(dst) {
panic(errors.Errorf("invalid destination label name in label_replace(): %s", dst)) panic(errors.Errorf("invalid destination label name in label_replace(): %s", dst))
} }
enh.dmn = make(map[uint64]labels.Labels, len(enh.out)) enh.Dmn = make(map[uint64]labels.Labels, len(enh.Out))
} }
for _, el := range vector { for _, el := range vector {
h := el.Metric.Hash() h := el.Metric.Hash()
var outMetric labels.Labels var outMetric labels.Labels
if l, ok := enh.dmn[h]; ok { if l, ok := enh.Dmn[h]; ok {
outMetric = l outMetric = l
} else { } else {
srcVal := el.Metric.Get(src) srcVal := el.Metric.Get(src)
@ -730,7 +730,7 @@ func funcLabelReplace(vals []parser.Value, args parser.Expressions, enh *EvalNod
if indexes == nil { if indexes == nil {
// If there is no match, no replacement should take place. // If there is no match, no replacement should take place.
outMetric = el.Metric outMetric = el.Metric
enh.dmn[h] = outMetric enh.Dmn[h] = outMetric
} else { } else {
res := enh.regex.ExpandString([]byte{}, repl, srcVal, indexes) res := enh.regex.ExpandString([]byte{}, repl, srcVal, indexes)
@ -739,21 +739,21 @@ func funcLabelReplace(vals []parser.Value, args parser.Expressions, enh *EvalNod
lb.Set(dst, string(res)) lb.Set(dst, string(res))
} }
outMetric = lb.Labels() outMetric = lb.Labels()
enh.dmn[h] = outMetric enh.Dmn[h] = outMetric
} }
} }
enh.out = append(enh.out, Sample{ enh.Out = append(enh.Out, Sample{
Metric: outMetric, Metric: outMetric,
Point: Point{V: el.Point.V}, Point: Point{V: el.Point.V},
}) })
} }
return enh.out return enh.Out
} }
// === Vector(s Scalar) Vector === // === Vector(s Scalar) Vector ===
func funcVector(vals []parser.Value, args parser.Expressions, enh *EvalNodeHelper) Vector { func funcVector(vals []parser.Value, args parser.Expressions, enh *EvalNodeHelper) Vector {
return append(enh.out, return append(enh.Out,
Sample{ Sample{
Metric: labels.Labels{}, Metric: labels.Labels{},
Point: Point{V: vals[0].(Vector)[0].V}, Point: Point{V: vals[0].(Vector)[0].V},
@ -769,8 +769,8 @@ func funcLabelJoin(vals []parser.Value, args parser.Expressions, enh *EvalNodeHe
srcLabels = make([]string, len(args)-3) srcLabels = make([]string, len(args)-3)
) )
if enh.dmn == nil { if enh.Dmn == nil {
enh.dmn = make(map[uint64]labels.Labels, len(enh.out)) enh.Dmn = make(map[uint64]labels.Labels, len(enh.Out))
} }
for i := 3; i < len(args); i++ { for i := 3; i < len(args); i++ {
@ -789,7 +789,7 @@ func funcLabelJoin(vals []parser.Value, args parser.Expressions, enh *EvalNodeHe
for _, el := range vector { for _, el := range vector {
h := el.Metric.Hash() h := el.Metric.Hash()
var outMetric labels.Labels var outMetric labels.Labels
if l, ok := enh.dmn[h]; ok { if l, ok := enh.Dmn[h]; ok {
outMetric = l outMetric = l
} else { } else {
@ -807,35 +807,35 @@ func funcLabelJoin(vals []parser.Value, args parser.Expressions, enh *EvalNodeHe
} }
outMetric = lb.Labels() outMetric = lb.Labels()
enh.dmn[h] = outMetric enh.Dmn[h] = outMetric
} }
enh.out = append(enh.out, Sample{ enh.Out = append(enh.Out, Sample{
Metric: outMetric, Metric: outMetric,
Point: Point{V: el.Point.V}, Point: Point{V: el.Point.V},
}) })
} }
return enh.out return enh.Out
} }
// Common code for date related functions. // Common code for date related functions.
func dateWrapper(vals []parser.Value, enh *EvalNodeHelper, f func(time.Time) float64) Vector { func dateWrapper(vals []parser.Value, enh *EvalNodeHelper, f func(time.Time) float64) Vector {
if len(vals) == 0 { if len(vals) == 0 {
return append(enh.out, return append(enh.Out,
Sample{ Sample{
Metric: labels.Labels{}, Metric: labels.Labels{},
Point: Point{V: f(time.Unix(enh.ts/1000, 0).UTC())}, Point: Point{V: f(time.Unix(enh.Ts/1000, 0).UTC())},
}) })
} }
for _, el := range vals[0].(Vector) { for _, el := range vals[0].(Vector) {
t := time.Unix(int64(el.V), 0).UTC() t := time.Unix(int64(el.V), 0).UTC()
enh.out = append(enh.out, Sample{ enh.Out = append(enh.Out, Sample{
Metric: enh.dropMetricName(el.Metric), Metric: enh.DropMetricName(el.Metric),
Point: Point{V: f(t)}, Point: Point{V: f(t)},
}) })
} }
return enh.out return enh.Out
} }
// === days_in_month(v Vector) Scalar === // === days_in_month(v Vector) Scalar ===