diff --git a/promql/engine.go b/promql/engine.go index c4048ae239..a3e8042ea4 100644 --- a/promql/engine.go +++ b/promql/engine.go @@ -2100,7 +2100,7 @@ func (ev *evaluator) eval(ctx context.Context, expr parser.Expr) (parser.Value, var chkIter chunkenc.Iterator var startTimestamps *StartTimestamps - if ev.useStartTimestamps && (e.Func.Name == "rate" || e.Func.Name == "irate" || e.Func.Name == "increase") { + if ev.useStartTimestamps && (e.Func.Name == "rate" || e.Func.Name == "irate" || e.Func.Name == "increase" || e.Func.Name == "resets") { // TODO: consider pooling this. startTimestamps = &StartTimestamps{} } diff --git a/promql/functions.go b/promql/functions.go index 5eac9080c1..aac8221452 100644 --- a/promql/functions.go +++ b/promql/functions.go @@ -1957,41 +1957,61 @@ func funcResets(_ []Vector, matrixVal Matrix, args parser.Expressions, enh *Eval return enh.Out, nil } - var prevSample, curSample Sample + var ( + prevSample, curSample Sample + prevST int64 + floatSTs, histogramSTs []int64 + ) + if sts := enh.StartTimestamps; sts != nil { + floatSTs = sts.Floats + histogramSTs = sts.Histograms + } firstSampleIndex, found := pickFirstSampleIndex(floats, args, enh) if !found { return enh.Out, nil } for iFloat, iHistogram := firstSampleIndex, 0; iFloat < len(floats) || iHistogram < len(histograms); { + var curST int64 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.T = floats[iFloat].T curSample.F = floats[iFloat].F curSample.H = nil + if iFloat < len(floatSTs) { + curST = floatSTs[iFloat] + } iFloat++ case iFloat >= len(floats) || iHistogram < len(histograms) && floats[iFloat].T > histograms[iHistogram].T: + curSample.T = histograms[iHistogram].T curSample.H = histograms[iHistogram].H + if iHistogram < len(histogramSTs) { + curST = histogramSTs[iHistogram] + } iHistogram++ } // Skip the comparison for the first sample, just initialize prevSample. if iFloat+iHistogram == 1+firstSampleIndex { prevSample = curSample + prevST = curST continue } + switch { case prevSample.H == nil && curSample.H == nil: - if curSample.F < prevSample.F { + if curSample.F < prevSample.F || isStartTimestampReset(prevST, prevSample.T, curST, curSample.T) { 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) { + if isStartTimestampReset(prevST, prevSample.T, curST, curSample.T) || curSample.H.DetectReset(prevSample.H) { resets++ } } prevSample = curSample + prevST = curST } return append(enh.Out, Sample{F: float64(resets)}), nil diff --git a/promql/promqltest/testdata/start_timestamps.test b/promql/promqltest/testdata/start_timestamps.test index 3ad31e85ba..592254bfc8 100644 --- a/promql/promqltest/testdata/start_timestamps.test +++ b/promql/promqltest/testdata/start_timestamps.test @@ -38,6 +38,12 @@ eval range from 7m to 15m step 1m increase(cumulative[5m:1m]) {type="st_resets"} 300x8 {type="normalized_resets"} 420 780 675 675 1275 900 900 1725 1125 +# Resets function also considers start timestamp resets. +eval range from 7m to 15m step 1m resets(cumulative[5m]) + {type="no_st"} 0x8 + {type="st_resets"} 1 2 1 1 2 1 1 2 1 + {type="normalized_resets"} 0x8 + clear # Tests for rate(), irate() and increase() on deltas. Includes various approaches for start timestamps: @@ -131,6 +137,10 @@ eval range from 7m to 15m step 1m rate(cumulative[5m]) eval range from 7m to 15m step 1m irate(cumulative[5m]) {} {{count:1 sum:1}}x8 +# Resets function also considers start timestamp resets. +eval range from 7m to 15m step 1m resets(cumulative[5m]) + {} 0x8 + clear # Tests for rate(), irate() and increase() on delta histograms.