diff --git a/app/vmselect/prometheus/prometheus.go b/app/vmselect/prometheus/prometheus.go index 19c93c26d..cf95f4099 100644 --- a/app/vmselect/prometheus/prometheus.go +++ b/app/vmselect/prometheus/prometheus.go @@ -791,8 +791,8 @@ func queryRangeHandler(w http.ResponseWriter, query string, start, end, step int return fmt.Errorf("cannot execute query: %w", err) } queryOffset := getLatencyOffsetMilliseconds() - if ct-end < queryOffset { - result = adjustLastPoints(result, ct, queryOffset) + if ct-queryOffset < end { + result = adjustLastPoints(result, ct-queryOffset, end) } // Remove NaN values as Prometheus does. @@ -837,46 +837,24 @@ func removeNaNValuesInplace(tss []netstorage.Result) { var queryRangeDuration = metrics.NewSummary(`vm_request_duration_seconds{path="/api/v1/query_range"}`) -// adjustLastPoints substitutes the last point values with the previous -// point values, since the last points may contain garbage. -func adjustLastPoints(tss []netstorage.Result, ct, queryOffset int64) []netstorage.Result { - if len(tss) == 0 { - return nil - } - - // Search for the last non-NaN value across all the timeseries. - lastNonNaNIdx := -1 +// adjustLastPoints substitutes the last point values on the time range (start..end] +// with the previous point values, since these points may contain garbage. +func adjustLastPoints(tss []netstorage.Result, start, end int64) []netstorage.Result { for i := range tss { - values := tss[i].Values - j := len(values) - 1 - for j >= 0 && math.IsNaN(values[j]) { + ts := &tss[i] + values := ts.Values + timestamps := ts.Timestamps + j := len(timestamps) - 1 + for j >= 0 && timestamps[j] > start { j-- } - if j > lastNonNaNIdx { - lastNonNaNIdx = j - } - } - if lastNonNaNIdx == -1 { - // All timeseries contain only NaNs. - return nil - } - - // Substitute the last two values starting from lastNonNaNIdx - // with the previous values for each timeseries. - for i := range tss { - values := tss[i].Values - if lastNonNaNIdx > len(values) { + j++ + if j <= 0 { continue } - end := tss[i].Timestamps[lastNonNaNIdx] - if ct-end < queryOffset { - for j := 1; j < 3; j++ { - idx := lastNonNaNIdx + j - if idx <= 0 || idx >= len(values) || math.IsNaN(values[idx-1]) { - continue - } - values[idx] = values[idx-1] - } + for j < len(timestamps) && timestamps[j] <= end { + values[j] = values[j-1] + j++ } } return tss diff --git a/app/vmselect/prometheus/prometheus_test.go b/app/vmselect/prometheus/prometheus_test.go index e1ce421f7..32bfdd585 100644 --- a/app/vmselect/prometheus/prometheus_test.go +++ b/app/vmselect/prometheus/prometheus_test.go @@ -115,9 +115,9 @@ func TestGetTimeError(t *testing.T) { } func TestAdjustLastPoints(t *testing.T) { - f := func(tss []netstorage.Result, ct, queryOffset int64, tssExpected []netstorage.Result) { + f := func(tss []netstorage.Result, start, end int64, tssExpected []netstorage.Result) { t.Helper() - tss = adjustLastPoints(tss, ct, queryOffset) + tss = adjustLastPoints(tss, start, end) for i, ts := range tss { for j, value := range ts.Values { expectedValue := tssExpected[i].Values[j] @@ -138,7 +138,7 @@ func TestAdjustLastPoints(t *testing.T) { nan := math.NaN() - f(nil, 500, 300, nil) + f(nil, 300, 500, nil) f([]netstorage.Result{ { @@ -149,7 +149,7 @@ func TestAdjustLastPoints(t *testing.T) { Timestamps: []int64{100, 200, 300, 400, 500}, Values: []float64{1, 2, 3, nan, nan}, }, - }, 500, 300, []netstorage.Result{ + }, 400, 500, []netstorage.Result{ { Timestamps: []int64{100, 200, 300, 400, 500}, Values: []float64{1, 2, 3, 4, 4}, @@ -169,7 +169,7 @@ func TestAdjustLastPoints(t *testing.T) { Timestamps: []int64{100, 200, 300, 400, 500}, Values: []float64{1, 2, nan, nan, nan}, }, - }, 500, 300, []netstorage.Result{ + }, 300, 500, []netstorage.Result{ { Timestamps: []int64{100, 200, 300, 400, 500}, Values: []float64{1, 2, 3, 3, 3}, @@ -209,7 +209,7 @@ func TestAdjustLastPoints(t *testing.T) { Timestamps: []int64{100, 200, 300, 400}, Values: []float64{1, 2, 3, 4}, }, - }, 500, 300, []netstorage.Result{ + }, 400, 500, []netstorage.Result{ { Timestamps: []int64{100, 200, 300, 400, 500}, Values: []float64{1, 2, 3, 4, 4}, @@ -229,7 +229,7 @@ func TestAdjustLastPoints(t *testing.T) { Timestamps: []int64{100, 200, 300}, Values: []float64{1, 2, nan}, }, - }, 500, 300, []netstorage.Result{ + }, 300, 600, []netstorage.Result{ { Timestamps: []int64{100, 200, 300, 400, 500}, Values: []float64{1, 2, 3, 3, 3},