diff --git a/promql/functions.go b/promql/functions.go index 1c2d1ca82..016e676d3 100644 --- a/promql/functions.go +++ b/promql/functions.go @@ -1400,27 +1400,41 @@ func funcResets(vals []parser.Value, args parser.Expressions, enh *EvalNodeHelpe floats := vals[0].(Matrix)[0].Floats histograms := vals[0].(Matrix)[0].Histograms resets := 0 - - if len(floats) > 1 { - prev := floats[0].F - for _, sample := range floats[1:] { - current := sample.F - if current < prev { - resets++ - } - prev = current - } + if len(floats) == 0 && len(histograms) == 0 { + return enh.Out, nil } - if len(histograms) > 1 { - prev := histograms[0].H - for _, sample := range histograms[1:] { - current := sample.H - if current.DetectReset(prev) { + var prevSample, curSample Sample + for iFloat, iHistogram := 0, 0; iFloat < len(floats) || iHistogram < len(histograms); { + switch { + // Process a float sample if no histogram sample remains or its timestamp is earlier. + // Process a histogram sample if no float sample remains or its timestamp is earlier. + case iHistogram >= len(histograms) || iFloat < len(floats) && floats[iFloat].T < histograms[iHistogram].T: + curSample.F = floats[iFloat].F + curSample.H = nil + iFloat++ + case iFloat >= len(floats) || iHistogram < len(histograms) && floats[iFloat].T > histograms[iHistogram].T: + curSample.H = histograms[iHistogram].H + iHistogram++ + } + // Skip the comparison for the first sample, just initialize prevSample. + if iFloat+iHistogram == 1 { + prevSample = curSample + continue + } + switch { + case prevSample.H == nil && curSample.H == nil: + if curSample.F < prevSample.F { + resets++ + } + case prevSample.H != nil && curSample.H == nil, prevSample.H == nil && curSample.H != nil: + resets++ + case prevSample.H != nil && curSample.H != nil: + if curSample.H.DetectReset(prevSample.H) { resets++ } - prev = current } + prevSample = curSample } return append(enh.Out, Sample{F: float64(resets)}), nil @@ -1441,16 +1455,12 @@ func funcChanges(vals []parser.Value, args parser.Expressions, enh *EvalNodeHelp // Process a float sample if no histogram sample remains or its timestamp is earlier. // Process a histogram sample if no float sample remains or its timestamp is earlier. case iHistogram >= len(histograms) || iFloat < len(floats) && floats[iFloat].T < histograms[iHistogram].T: - { - curSample.F = floats[iFloat].F - curSample.H = nil - iFloat++ - } + curSample.F = floats[iFloat].F + curSample.H = nil + iFloat++ case iFloat >= len(floats) || iHistogram < len(histograms) && floats[iFloat].T > histograms[iHistogram].T: - { - curSample.H = histograms[iHistogram].H - iHistogram++ - } + curSample.H = histograms[iHistogram].H + iHistogram++ } // Skip the comparison for the first sample, just initialize prevSample. if iFloat+iHistogram == 1 { @@ -1459,20 +1469,14 @@ func funcChanges(vals []parser.Value, args parser.Expressions, enh *EvalNodeHelp } switch { case prevSample.H == nil && curSample.H == nil: - { - if curSample.F != prevSample.F && !(math.IsNaN(curSample.F) && math.IsNaN(prevSample.F)) { - changes++ - } - } - case prevSample.H != nil && curSample.H == nil, prevSample.H == nil && curSample.H != nil: - { + if curSample.F != prevSample.F && !(math.IsNaN(curSample.F) && math.IsNaN(prevSample.F)) { changes++ } + case prevSample.H != nil && curSample.H == nil, prevSample.H == nil && curSample.H != nil: + changes++ case prevSample.H != nil && curSample.H != nil: - { - if !curSample.H.Equals(prevSample.H) { - changes++ - } + if !curSample.H.Equals(prevSample.H) { + changes++ } } prevSample = curSample diff --git a/promql/promqltest/testdata/functions.test b/promql/promqltest/testdata/functions.test index a44a9fc67..eaf3eed2b 100644 --- a/promql/promqltest/testdata/functions.test +++ b/promql/promqltest/testdata/functions.test @@ -5,7 +5,7 @@ load 5m http_requests{path="/biz"} 0 0 0 0 0 1 1 1 1 1 http_requests_histogram{path="/foo"} {{schema:0 sum:1 count:1}}x9 http_requests_histogram{path="/bar"} 0 0 0 0 0 0 0 0 {{schema:0 sum:1 count:1}} {{schema:0 sum:1 count:1}} - http_requests_histogram{path="/biz"} 0 1 0 2 0 3 0 {{schema:0 sum:1 count:1}} {{schema:0 sum:2 count:2}} {{schema:0 sum:1 count:1}} + http_requests_histogram{path="/biz"} 0 1 0 2 0 3 0 {{schema:0 sum:1 count:1 z_bucket_w:0.001 z_bucket:2}} {{schema:0 sum:2 count:2 z_bucket_w:0.001 z_bucket:1}} {{schema:0 sum:1 count:1 z_bucket_w:0.001 z_bucket:2}} # Tests for resets(). eval instant at 50m resets(http_requests[5m]) @@ -42,6 +42,18 @@ eval instant at 50m resets(http_requests[50m]) eval instant at 50m resets(nonexistent_metric[50m]) +# Test for mix of floats and histograms. + +eval instant at 50m resets(http_requests_histogram[6m]) + {path="/foo"} 0 + {path="/bar"} 0 + {path="/biz"} 0 + +eval instant at 50m resets(http_requests_histogram[60m]) + {path="/foo"} 0 + {path="/bar"} 1 + {path="/biz"} 6 + # Tests for changes(). eval instant at 50m changes(http_requests[5m])