mirror of
https://github.com/prometheus/prometheus.git
synced 2024-11-13 17:14:05 -08:00
Hints: Separating out the range and offsets of PromQL subqueries (#7667)
Fix #7629 Signed-off-by: Julien Pivotto <roidelapluie@inuits.eu>
This commit is contained in:
parent
4ae2ef94e0
commit
20ab94fedf
|
@ -576,35 +576,39 @@ func (ng *Engine) execEvalStmt(ctx context.Context, query *query, s *parser.Eval
|
||||||
return mat, warnings, nil
|
return mat, warnings, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
// cumulativeSubqueryOffset returns the sum of range and offset of all subqueries in the path.
|
// subqueryOffsetRange returns the sum of offsets and ranges of all subqueries in the path.
|
||||||
func (ng *Engine) cumulativeSubqueryOffset(path []parser.Node) time.Duration {
|
func (ng *Engine) subqueryOffsetRange(path []parser.Node) (time.Duration, time.Duration) {
|
||||||
var subqOffset time.Duration
|
var (
|
||||||
|
subqOffset time.Duration
|
||||||
|
subqRange time.Duration
|
||||||
|
)
|
||||||
for _, node := range path {
|
for _, node := range path {
|
||||||
switch n := node.(type) {
|
switch n := node.(type) {
|
||||||
case *parser.SubqueryExpr:
|
case *parser.SubqueryExpr:
|
||||||
subqOffset += n.Range + n.Offset
|
subqOffset += n.Offset
|
||||||
|
subqRange += n.Range
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
return subqOffset
|
return subqOffset, subqRange
|
||||||
}
|
}
|
||||||
|
|
||||||
func (ng *Engine) findMinTime(s *parser.EvalStmt) time.Time {
|
func (ng *Engine) findMinTime(s *parser.EvalStmt) time.Time {
|
||||||
var maxOffset time.Duration
|
var maxOffset time.Duration
|
||||||
parser.Inspect(s.Expr, func(node parser.Node, path []parser.Node) error {
|
parser.Inspect(s.Expr, func(node parser.Node, path []parser.Node) error {
|
||||||
subqOffset := ng.cumulativeSubqueryOffset(path)
|
subqOffset, subqRange := ng.subqueryOffsetRange(path)
|
||||||
switch n := node.(type) {
|
switch n := node.(type) {
|
||||||
case *parser.VectorSelector:
|
case *parser.VectorSelector:
|
||||||
if maxOffset < ng.lookbackDelta+subqOffset {
|
if maxOffset < ng.lookbackDelta+subqOffset+subqRange {
|
||||||
maxOffset = ng.lookbackDelta + subqOffset
|
maxOffset = ng.lookbackDelta + subqOffset + subqRange
|
||||||
}
|
}
|
||||||
if n.Offset+ng.lookbackDelta+subqOffset > maxOffset {
|
if n.Offset+ng.lookbackDelta+subqOffset+subqRange > maxOffset {
|
||||||
maxOffset = n.Offset + ng.lookbackDelta + subqOffset
|
maxOffset = n.Offset + ng.lookbackDelta + subqOffset + subqRange
|
||||||
}
|
}
|
||||||
case *parser.MatrixSelector:
|
case *parser.MatrixSelector:
|
||||||
if maxOffset < n.Range+subqOffset {
|
if maxOffset < n.Range+subqOffset+subqRange {
|
||||||
maxOffset = n.Range + subqOffset
|
maxOffset = n.Range + subqOffset + subqRange
|
||||||
}
|
}
|
||||||
if m := n.VectorSelector.(*parser.VectorSelector).Offset + n.Range + subqOffset; m > maxOffset {
|
if m := n.VectorSelector.(*parser.VectorSelector).Offset + n.Range + subqOffset + subqRange; m > maxOffset {
|
||||||
maxOffset = m
|
maxOffset = m
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -629,13 +633,13 @@ func (ng *Engine) populateSeries(querier storage.Querier, s *parser.EvalStmt) {
|
||||||
}
|
}
|
||||||
|
|
||||||
// We need to make sure we select the timerange selected by the subquery.
|
// We need to make sure we select the timerange selected by the subquery.
|
||||||
// The cumulativeSubqueryOffset function gives the sum of range and the offset.
|
// The subqueryOffsetRange function gives the sum of range and the
|
||||||
// TODO(gouthamve): Consider optimising it by separating out the range and offsets, and subtracting the offsets
|
// sum of offset.
|
||||||
// from end also. See: https://github.com/prometheus/prometheus/issues/7629.
|
|
||||||
// TODO(bwplotka): Add support for better hints when subquerying. See: https://github.com/prometheus/prometheus/issues/7630.
|
// TODO(bwplotka): Add support for better hints when subquerying. See: https://github.com/prometheus/prometheus/issues/7630.
|
||||||
subqOffset := ng.cumulativeSubqueryOffset(path)
|
subqOffset, subqRange := ng.subqueryOffsetRange(path)
|
||||||
offsetMilliseconds := durationMilliseconds(subqOffset)
|
offsetMilliseconds := durationMilliseconds(subqOffset)
|
||||||
hints.Start = hints.Start - offsetMilliseconds
|
hints.Start = hints.Start - offsetMilliseconds - durationMilliseconds(subqRange)
|
||||||
|
hints.End = hints.End - offsetMilliseconds
|
||||||
|
|
||||||
if evalRange == 0 {
|
if evalRange == 0 {
|
||||||
hints.Start = hints.Start - durationMilliseconds(ng.lookbackDelta)
|
hints.Start = hints.Start - durationMilliseconds(ng.lookbackDelta)
|
||||||
|
|
|
@ -289,12 +289,12 @@ func TestSelectHintsSetCorrectly(t *testing.T) {
|
||||||
}, {
|
}, {
|
||||||
query: "count_over_time(foo[2m:1s] offset 10s)", start: 300000,
|
query: "count_over_time(foo[2m:1s] offset 10s)", start: 300000,
|
||||||
expected: []*storage.SelectHints{
|
expected: []*storage.SelectHints{
|
||||||
{Start: 165000, End: 300000, Func: "count_over_time"},
|
{Start: 165000, End: 290000, Func: "count_over_time"},
|
||||||
},
|
},
|
||||||
}, {
|
}, {
|
||||||
query: "count_over_time((foo offset 10s)[2m:1s] offset 10s)", start: 300000,
|
query: "count_over_time((foo offset 10s)[2m:1s] offset 10s)", start: 300000,
|
||||||
expected: []*storage.SelectHints{
|
expected: []*storage.SelectHints{
|
||||||
{Start: 155000, End: 290000, Func: "count_over_time"},
|
{Start: 155000, End: 280000, Func: "count_over_time"},
|
||||||
},
|
},
|
||||||
}, {
|
}, {
|
||||||
|
|
||||||
|
@ -325,12 +325,12 @@ func TestSelectHintsSetCorrectly(t *testing.T) {
|
||||||
}, {
|
}, {
|
||||||
query: "count_over_time(foo[2m:1s] offset 10s)", start: 300000, end: 500000,
|
query: "count_over_time(foo[2m:1s] offset 10s)", start: 300000, end: 500000,
|
||||||
expected: []*storage.SelectHints{
|
expected: []*storage.SelectHints{
|
||||||
{Start: 165000, End: 500000, Func: "count_over_time", Step: 1000},
|
{Start: 165000, End: 490000, Func: "count_over_time", Step: 1000},
|
||||||
},
|
},
|
||||||
}, {
|
}, {
|
||||||
query: "count_over_time((foo offset 10s)[2m:1s] offset 10s)", start: 300000, end: 500000,
|
query: "count_over_time((foo offset 10s)[2m:1s] offset 10s)", start: 300000, end: 500000,
|
||||||
expected: []*storage.SelectHints{
|
expected: []*storage.SelectHints{
|
||||||
{Start: 155000, End: 490000, Func: "count_over_time", Step: 1000},
|
{Start: 155000, End: 480000, Func: "count_over_time", Step: 1000},
|
||||||
},
|
},
|
||||||
}, {
|
}, {
|
||||||
query: "sum by (dim1) (foo)", start: 10000,
|
query: "sum by (dim1) (foo)", start: 10000,
|
||||||
|
|
9
promql/testdata/selectors.test
vendored
9
promql/testdata/selectors.test
vendored
|
@ -57,3 +57,12 @@ eval instant at 0s http_requests{foo!~"bar", job="api-server"}
|
||||||
eval instant at 0s http_requests{foo!~"bar", job="api-server", instance="1", x!="y", z="", group!=""}
|
eval instant at 0s http_requests{foo!~"bar", job="api-server", instance="1", x!="y", z="", group!=""}
|
||||||
http_requests{job="api-server", instance="1", group="production"} 0
|
http_requests{job="api-server", instance="1", group="production"} 0
|
||||||
http_requests{job="api-server", instance="1", group="canary"} 0
|
http_requests{job="api-server", instance="1", group="canary"} 0
|
||||||
|
|
||||||
|
clear
|
||||||
|
load 1m
|
||||||
|
metric1{a="a"} 0+1x100
|
||||||
|
metric2{b="b"} 0+1x50
|
||||||
|
|
||||||
|
eval instant at 90m metric1 offset 15m or metric2 offset 45m
|
||||||
|
metric1{a="a"} 75
|
||||||
|
metric2{b="b"} 45
|
||||||
|
|
Loading…
Reference in a new issue