|
|
|
|
@ -576,35 +576,39 @@ func (ng *Engine) execEvalStmt(ctx context.Context, query *query, s *parser.Eval |
|
|
|
|
return mat, warnings, nil |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
// cumulativeSubqueryOffset returns the sum of range and offset of all subqueries in the path.
|
|
|
|
|
func (ng *Engine) cumulativeSubqueryOffset(path []parser.Node) time.Duration { |
|
|
|
|
var subqOffset time.Duration |
|
|
|
|
// subqueryOffsetRange returns the sum of offsets and ranges of all subqueries in the path.
|
|
|
|
|
func (ng *Engine) subqueryOffsetRange(path []parser.Node) (time.Duration, time.Duration) { |
|
|
|
|
var ( |
|
|
|
|
subqOffset time.Duration |
|
|
|
|
subqRange time.Duration |
|
|
|
|
) |
|
|
|
|
for _, node := range path { |
|
|
|
|
switch n := node.(type) { |
|
|
|
|
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 { |
|
|
|
|
var maxOffset time.Duration |
|
|
|
|
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) { |
|
|
|
|
case *parser.VectorSelector: |
|
|
|
|
if maxOffset < ng.lookbackDelta+subqOffset { |
|
|
|
|
maxOffset = ng.lookbackDelta + subqOffset |
|
|
|
|
if maxOffset < ng.lookbackDelta+subqOffset+subqRange { |
|
|
|
|
maxOffset = ng.lookbackDelta + subqOffset + subqRange |
|
|
|
|
} |
|
|
|
|
if n.Offset+ng.lookbackDelta+subqOffset > maxOffset { |
|
|
|
|
maxOffset = n.Offset + ng.lookbackDelta + subqOffset |
|
|
|
|
if n.Offset+ng.lookbackDelta+subqOffset+subqRange > maxOffset { |
|
|
|
|
maxOffset = n.Offset + ng.lookbackDelta + subqOffset + subqRange |
|
|
|
|
} |
|
|
|
|
case *parser.MatrixSelector: |
|
|
|
|
if maxOffset < n.Range+subqOffset { |
|
|
|
|
maxOffset = n.Range + subqOffset |
|
|
|
|
if maxOffset < n.Range+subqOffset+subqRange { |
|
|
|
|
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 |
|
|
|
|
} |
|
|
|
|
} |
|
|
|
|
@ -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.
|
|
|
|
|
// The cumulativeSubqueryOffset function gives the sum of range and the offset.
|
|
|
|
|
// TODO(gouthamve): Consider optimising it by separating out the range and offsets, and subtracting the offsets
|
|
|
|
|
// from end also. See: https://github.com/prometheus/prometheus/issues/7629.
|
|
|
|
|
// The subqueryOffsetRange function gives the sum of range and the
|
|
|
|
|
// sum of offset.
|
|
|
|
|
// 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) |
|
|
|
|
hints.Start = hints.Start - offsetMilliseconds |
|
|
|
|
hints.Start = hints.Start - offsetMilliseconds - durationMilliseconds(subqRange) |
|
|
|
|
hints.End = hints.End - offsetMilliseconds |
|
|
|
|
|
|
|
|
|
if evalRange == 0 { |
|
|
|
|
hints.Start = hints.Start - durationMilliseconds(ng.lookbackDelta) |
|
|
|
|
|