Skip to content

Commit dfb4b4f

Browse files
Emit error when querying native histograms with extended functions (#322)
* Emit error when querying native histograms with extended functions We saw panics on our setup because users tried to use the extended functions with native histograms, which led to rates calculated with only one sample in some windows. In this PR I am introducing a safeguard against this type of situation and emiting a warn when users try to query native histograms with extended functions. Signed-off-by: Pedro Tanaka <[email protected]> Fixing test case Signed-off-by: Pedro Tanaka <[email protected]> removing dead code Signed-off-by: Pedro Tanaka <[email protected]> Return error instead of warn Signed-off-by: Pedro Tanaka <[email protected]> fixing linting Signed-off-by: Pedro Tanaka <[email protected]> * Update execution/scan/functions.go Co-authored-by: Filip Petkovski <[email protected]> Signed-off-by: Pedro Tanaka <[email protected]> * Removing query context Signed-off-by: Pedro Tanaka <[email protected]> --------- Signed-off-by: Pedro Tanaka <[email protected]> Co-authored-by: Filip Petkovski <[email protected]>
1 parent 4517c0d commit dfb4b4f

File tree

3 files changed

+56
-2
lines changed

3 files changed

+56
-2
lines changed

engine/engine_test.go

+40
Original file line numberDiff line numberDiff line change
@@ -16,6 +16,8 @@ import (
1616
"testing"
1717
"time"
1818

19+
"github.com/stretchr/testify/require"
20+
1921
"github.com/efficientgo/core/errors"
2022
"github.com/efficientgo/core/testutil"
2123
"go.uber.org/goleak"
@@ -2138,6 +2140,44 @@ func TestDisabledXFunction(t *testing.T) {
21382140
}
21392141
}
21402142

2143+
func TestXFunctionsWithNativeHistograms(t *testing.T) {
2144+
defaultQueryTime := time.Unix(50, 0)
2145+
2146+
expr := "sum(xincrease(native_histogram_series[50s]))"
2147+
2148+
// Negative offset and at modifier are enabled by default
2149+
// since Prometheus v2.33.0, so we also enable them.
2150+
opts := promql.EngineOpts{
2151+
Timeout: 1 * time.Hour,
2152+
MaxSamples: 1e10,
2153+
EnableNegativeOffset: true,
2154+
EnableAtModifier: true,
2155+
}
2156+
2157+
lStorage := teststorage.New(t)
2158+
defer lStorage.Close()
2159+
2160+
app := lStorage.Appender(context.TODO())
2161+
testutil.Ok(t, generateFloatHistogramSeries(app, 3000, false))
2162+
testutil.Ok(t, app.Commit())
2163+
2164+
optimizers := logicalplan.AllOptimizers
2165+
2166+
ctx := context.Background()
2167+
newEngine := engine.New(engine.Opts{
2168+
EngineOpts: opts,
2169+
DisableFallback: true,
2170+
LogicalOptimizers: optimizers,
2171+
EnableXFunctions: true,
2172+
})
2173+
query, err := newEngine.NewInstantQuery(ctx, lStorage, nil, expr, defaultQueryTime)
2174+
testutil.Ok(t, err)
2175+
defer query.Close()
2176+
2177+
engineResult := query.Exec(ctx)
2178+
require.Error(t, engineResult.Err)
2179+
}
2180+
21412181
func TestXFunctionsWhenDisabled(t *testing.T) {
21422182
var (
21432183
query = "xincrease(http_requests[50s])"

execution/scan/functions.go

+5
Original file line numberDiff line numberDiff line change
@@ -381,6 +381,11 @@ func extendedRate(samples []Sample, isCounter, isRate bool, stepTime int64, sele
381381
// points[0] to be a histogram. It returns nil if any other Point in points is
382382
// not a histogram.
383383
func histogramRate(points []Sample, isCounter bool) *histogram.FloatHistogram {
384+
// Calculating a rate on a single sample is not defined.
385+
if len(points) < 2 {
386+
return nil
387+
}
388+
384389
prev := points[0].H // We already know that this is a histogram.
385390
last := points[len(points)-1].H
386391
if last == nil {

execution/scan/matrix_selector.go

+11-2
Original file line numberDiff line numberDiff line change
@@ -9,13 +9,13 @@ import (
99
"sync"
1010
"time"
1111

12+
"github.com/efficientgo/core/errors"
1213
"github.com/prometheus/prometheus/model/labels"
1314
"github.com/prometheus/prometheus/model/value"
15+
"github.com/prometheus/prometheus/promql/parser"
1416
"github.com/prometheus/prometheus/storage"
1517
"github.com/prometheus/prometheus/tsdb/chunkenc"
1618

17-
"github.com/prometheus/prometheus/promql/parser"
18-
1919
"github.com/thanos-io/promql-engine/execution/function"
2020
"github.com/thanos-io/promql-engine/execution/model"
2121
engstore "github.com/thanos-io/promql-engine/execution/storage"
@@ -60,6 +60,8 @@ type matrixSelector struct {
6060
model.OperatorTelemetry
6161
}
6262

63+
var ErrNativeHistogramsNotSupported = errors.New("native histograms are not supported in extended range functions")
64+
6365
// NewMatrixSelector creates operator which selects vector of series over time.
6466
func NewMatrixSelector(
6567
pool *model.VectorPool,
@@ -353,6 +355,7 @@ loop:
353355
// TODO(fpetkovski): Add max samples limit.
354356
func selectExtPoints(it *storage.BufferedSeriesIterator, mint, maxt int64, out []Sample, extLookbackDelta int64, metricAppearedTs **int64) ([]Sample, error) {
355357
extMint := mint - extLookbackDelta
358+
selectsNativeHistograms := false
356359

357360
if len(out) > 0 && out[len(out)-1].T >= mint {
358361
// There is an overlap between previous and current ranges, retain common
@@ -396,6 +399,7 @@ loop:
396399
case chunkenc.ValNone:
397400
break loop
398401
case chunkenc.ValHistogram, chunkenc.ValFloatHistogram:
402+
selectsNativeHistograms = true
399403
t, fh := buf.AtFloatHistogram()
400404
if value.IsStaleNaN(fh.Sum) {
401405
continue loop
@@ -431,6 +435,7 @@ loop:
431435
// The sought sample might also be in the range.
432436
switch soughtValueType {
433437
case chunkenc.ValHistogram, chunkenc.ValFloatHistogram:
438+
selectsNativeHistograms = true
434439
t, fh := it.AtFloatHistogram()
435440
if t == maxt && !value.IsStaleNaN(fh.Sum) {
436441
if *metricAppearedTs == nil {
@@ -448,5 +453,9 @@ loop:
448453
}
449454
}
450455

456+
if selectsNativeHistograms {
457+
return nil, ErrNativeHistogramsNotSupported
458+
}
459+
451460
return out, nil
452461
}

0 commit comments

Comments
 (0)