app/vmselect/promql: properly handle corner cases for rollup functions

This commit is contained in:
Aliaksandr Valialkin 2019-08-15 23:29:59 +03:00
parent f696cc503a
commit 1b5b9ced27
2 changed files with 29 additions and 8 deletions

View File

@ -615,10 +615,15 @@ func rollupDelta(rfa *rollupFuncArg) float64 {
if len(values) == 0 { if len(values) == 0 {
return nan return nan
} }
if len(values) == 1 {
// Assume that the previous non-existing value was 0.
return values[0]
}
prevValue = values[0] prevValue = values[0]
values = values[1:] values = values[1:]
} }
if len(values) == 0 { if len(values) == 0 {
// Assume that the value didn't change on the given interval.
return 0 return 0
} }
return values[len(values)-1] - prevValue return values[len(values)-1] - prevValue
@ -632,6 +637,7 @@ func rollupIdelta(rfa *rollupFuncArg) float64 {
if math.IsNaN(rfa.prevValue) { if math.IsNaN(rfa.prevValue) {
return nan return nan
} }
// Assume that the value didn't change on the given interval.
return 0 return 0
} }
lastValue := values[len(values)-1] lastValue := values[len(values)-1]
@ -639,7 +645,8 @@ func rollupIdelta(rfa *rollupFuncArg) float64 {
if len(values) == 0 { if len(values) == 0 {
prevValue := rfa.prevValue prevValue := rfa.prevValue
if math.IsNaN(prevValue) { if math.IsNaN(prevValue) {
return 0 // Assume that the previous non-existing value was 0.
return lastValue
} }
return lastValue - prevValue return lastValue - prevValue
} }
@ -661,7 +668,8 @@ func rollupDerivFast(rfa *rollupFuncArg) float64 {
prevValue := rfa.prevValue prevValue := rfa.prevValue
prevTimestamp := rfa.prevTimestamp prevTimestamp := rfa.prevTimestamp
if math.IsNaN(prevValue) { if math.IsNaN(prevValue) {
if len(values) == 0 { if len(values) < 2 {
// It is impossible to calculate derivative on 0 or 1 values.
return nan return nan
} }
prevValue = values[0] prevValue = values[0]
@ -670,6 +678,7 @@ func rollupDerivFast(rfa *rollupFuncArg) float64 {
timestamps = timestamps[1:] timestamps = timestamps[1:]
} }
if len(values) == 0 { if len(values) == 0 {
// Assume that the value didn't change on the given interval.
return 0 return 0
} }
vEnd := values[len(values)-1] vEnd := values[len(values)-1]
@ -684,11 +693,12 @@ func rollupIderiv(rfa *rollupFuncArg) float64 {
// before calling rollup funcs. // before calling rollup funcs.
values := rfa.values values := rfa.values
timestamps := rfa.timestamps timestamps := rfa.timestamps
if len(values) == 0 { if len(values) < 2 {
if math.IsNaN(rfa.prevValue) { if len(values) == 0 || math.IsNaN(rfa.prevValue) {
// It is impossible to calculate derivative on 0 or 1 values.
return nan return nan
} }
return 0 return (values[0] - rfa.prevValue) / float64(timestamps[0]-rfa.prevTimestamp)
} }
vEnd := values[len(values)-1] vEnd := values[len(values)-1]
tEnd := timestamps[len(timestamps)-1] tEnd := timestamps[len(timestamps)-1]

View File

@ -45,8 +45,19 @@ func TestRollupIderivDuplicateTimestamps(t *testing.T) {
timestamps: []int64{100}, timestamps: []int64{100},
} }
n = rollupIderiv(rfa) n = rollupIderiv(rfa)
if n != 0 { if !math.IsNaN(n) {
t.Fatalf("unexpected value; got %v; want %v", n, 0) t.Fatalf("unexpected value; got %v; want %v", n, nan)
}
rfa = &rollupFuncArg{
prevTimestamp: 90,
prevValue: 10,
values: []float64{15},
timestamps: []int64{100},
}
n = rollupIderiv(rfa)
if n != 0.5 {
t.Fatalf("unexpected value; got %v; want %v", n, 0.5)
} }
rfa = &rollupFuncArg{ rfa = &rollupFuncArg{
@ -569,7 +580,7 @@ func TestRollupFuncsNoWindow(t *testing.T) {
} }
rc.Timestamps = getTimestamps(rc.Start, rc.End, rc.Step) rc.Timestamps = getTimestamps(rc.Start, rc.End, rc.Step)
values := rc.Do(nil, testValues, testTimestamps) values := rc.Do(nil, testValues, testTimestamps)
valuesExpected := []float64{0, 33, -87, 0} valuesExpected := []float64{123, 33, -87, 0}
timestampsExpected := []int64{10, 50, 90, 130} timestampsExpected := []int64{10, 50, 90, 130}
testRowsEqual(t, values, rc.Timestamps, valuesExpected, timestampsExpected) testRowsEqual(t, values, rc.Timestamps, valuesExpected, timestampsExpected)
}) })