@@ -464,14 +464,14 @@ func (ng *Engine) execEvalStmt(ctx context.Context, query *query, s *EvalStmt) (
464464 if s .Start == s .End && s .Interval == 0 {
465465 start := timeMilliseconds (s .Start )
466466 evaluator := & evaluator {
467- startTimestamp : start ,
468- endTimestamp : start ,
469- interval : 1 ,
470- ctx : ctxInnerEval ,
471- maxSamples : ng .maxSamplesPerQuery ,
472- defaultEvalInterval : GetDefaultEvaluationInterval (),
473- logger : ng .logger ,
474- useV3ioAggregations : querier .(* tsdb.V3ioPromQuerier ).UseV3ioAggregations () ,
467+ startTimestamp : start ,
468+ endTimestamp : start ,
469+ interval : 1 ,
470+ ctx : ctxInnerEval ,
471+ maxSamples : ng .maxSamplesPerQuery ,
472+ defaultEvalInterval : GetDefaultEvaluationInterval (),
473+ logger : ng .logger ,
474+ isAlreadyV3IOAggregated : querier .(* tsdb.V3ioPromQuerier ).IsAlreadyAggregated ,
475475 }
476476 val , err := evaluator .Eval (s .Expr )
477477 if err != nil {
@@ -507,14 +507,14 @@ func (ng *Engine) execEvalStmt(ctx context.Context, query *query, s *EvalStmt) (
507507
508508 // Range evaluation.
509509 evaluator := & evaluator {
510- startTimestamp : timeMilliseconds (s .Start ),
511- endTimestamp : timeMilliseconds (s .End ),
512- interval : durationMilliseconds (s .Interval ),
513- ctx : ctxInnerEval ,
514- maxSamples : ng .maxSamplesPerQuery ,
515- defaultEvalInterval : GetDefaultEvaluationInterval (),
516- logger : ng .logger ,
517- useV3ioAggregations : querier .(* tsdb.V3ioPromQuerier ).UseV3ioAggregations () ,
510+ startTimestamp : timeMilliseconds (s .Start ),
511+ endTimestamp : timeMilliseconds (s .End ),
512+ interval : durationMilliseconds (s .Interval ),
513+ ctx : ctxInnerEval ,
514+ maxSamples : ng .maxSamplesPerQuery ,
515+ defaultEvalInterval : GetDefaultEvaluationInterval (),
516+ logger : ng .logger ,
517+ isAlreadyV3IOAggregated : querier .(* tsdb.V3ioPromQuerier ).IsAlreadyAggregated ,
518518 }
519519 val , err := evaluator .Eval (s .Expr )
520520 if err != nil {
@@ -556,6 +556,7 @@ func (ng *Engine) cumulativeSubqueryOffset(path []Node) time.Duration {
556556func (ng * Engine ) populateSeries (ctx context.Context , q storage.Queryable , s * EvalStmt ) (storage.Querier , storage.Warnings , error ) {
557557 var maxOffset time.Duration
558558 var aggregationWindow int64
559+ var subQueryStep int64
559560
560561 Inspect (s .Expr , func (node Node , path []Node ) error {
561562 subqOffset := ng .cumulativeSubqueryOffset (path )
@@ -568,13 +569,17 @@ func (ng *Engine) populateSeries(ctx context.Context, q storage.Queryable, s *Ev
568569 maxOffset = n .Offset + LookbackDelta + subqOffset
569570 }
570571 case * MatrixSelector :
571- aggregationWindow = n .Range . Nanoseconds () / 1000000
572+ aggregationWindow = durationToInt64Millis ( n .Range )
572573 if maxOffset < n .Range + subqOffset {
573574 maxOffset = n .Range + subqOffset
574575 }
575576 if n .Offset + n .Range + subqOffset > maxOffset {
576577 maxOffset = n .Offset + n .Range + subqOffset
577578 }
579+ case * SubqueryExpr :
580+ // Save the step if it is provided in a subquery rather than as an interval
581+ // Example query: `sum(metric)[1h:10m]` -> step=10m
582+ subQueryStep = durationToInt64Millis (n .Step )
578583 }
579584 return nil
580585 })
@@ -591,10 +596,16 @@ func (ng *Engine) populateSeries(ctx context.Context, q storage.Queryable, s *Ev
591596 Inspect (s .Expr , func (node Node , path []Node ) error {
592597 var set storage.SeriesSet
593598 var wrn storage.Warnings
599+
600+ // Get the Step from the sub query, in case the interval is not set.
601+ step := durationToInt64Millis (s .Interval )
602+ if step == 0 {
603+ step = subQueryStep
604+ }
594605 params := & storage.SelectParams {
595606 Start : timestamp .FromTime (s .Start ),
596607 End : timestamp .FromTime (s .End ),
597- Step : durationToInt64Millis ( s . Interval ) ,
608+ Step : step ,
598609 }
599610
600611 // We need to make sure we select the timerange selected by the subquery.
@@ -607,6 +618,9 @@ func (ng *Engine) populateSeries(ctx context.Context, q storage.Queryable, s *Ev
607618
608619 switch n := node .(type ) {
609620 case * VectorSelector :
621+ // Validate if the current query can be aggregated via v3io
622+ querier .(* tsdb.V3ioPromQuerier ).UseAggregates = isV3ioEligibleQueryExpr (path )
623+
610624 params .Start = params .Start - durationMilliseconds (LookbackDelta )
611625 params .Func = extractFuncFromPath (path )
612626 params .By , params .Grouping = extractGroupsFromPath (path )
@@ -629,6 +643,9 @@ func (ng *Engine) populateSeries(ctx context.Context, q storage.Queryable, s *Ev
629643 n .unexpandedSeriesSet = set
630644
631645 case * MatrixSelector :
646+ // Validate if the current query can be aggregated via v3io
647+ querier .(* tsdb.V3ioPromQuerier ).UseAggregates = isV3ioEligibleQueryExpr (path )
648+
632649 params .Func = extractFuncFromPath (path )
633650 params .Range = durationMilliseconds (n .Range )
634651 // For all matrix queries we want to ensure that we have (end-start) + range selected
@@ -738,7 +755,7 @@ type evaluator struct {
738755 defaultEvalInterval int64
739756 logger log.Logger
740757
741- useV3ioAggregations bool // Indicates whether v3io tsdb already queried and aggregated the data, or just returned raw data
758+ isAlreadyV3IOAggregated func ( op string ) bool // Indicates whether v3io tsdb already queried and aggregated the data, or just returned raw data
742759}
743760
744761// errorf causes a panic with the input formatted into an error.
@@ -980,7 +997,7 @@ func (ev *evaluator) eval(expr Expr) Value {
980997
981998 switch e := expr .(type ) {
982999 case * AggregateExpr :
983- if ev .useV3ioAggregations {
1000+ if ev .isAlreadyV3IOAggregated ( e . Op . String ()) {
9841001 return ev .emptyAggregation (e .Expr )
9851002 }
9861003 if s , ok := e .Param .(* StringLiteral ); ok {
@@ -1038,9 +1055,10 @@ func (ev *evaluator) eval(expr Expr) Value {
10381055 // Evaluate any non-matrix arguments.
10391056 otherArgs := make ([]Matrix , len (e .Args ))
10401057 otherInArgs := make ([]Vector , len (e .Args ))
1058+ function := e .Func .Name
10411059 for i , e := range e .Args {
10421060 if i != matrixArgIndex {
1043- if ev .useV3ioAggregations {
1061+ if ev .isAlreadyV3IOAggregated ( function ) {
10441062 return ev .emptyAggregation (e )
10451063 }
10461064
@@ -1226,14 +1244,14 @@ func (ev *evaluator) eval(expr Expr) Value {
12261244 offsetMillis := durationToInt64Millis (e .Offset )
12271245 rangeMillis := durationToInt64Millis (e .Range )
12281246 newEv := & evaluator {
1229- endTimestamp : ev .endTimestamp - offsetMillis ,
1230- interval : ev .defaultEvalInterval ,
1231- ctx : ev .ctx ,
1232- currentSamples : ev .currentSamples ,
1233- maxSamples : ev .maxSamples ,
1234- defaultEvalInterval : ev .defaultEvalInterval ,
1235- logger : ev .logger ,
1236- useV3ioAggregations : ev .useV3ioAggregations ,
1247+ endTimestamp : ev .endTimestamp - offsetMillis ,
1248+ interval : ev .defaultEvalInterval ,
1249+ ctx : ev .ctx ,
1250+ currentSamples : ev .currentSamples ,
1251+ maxSamples : ev .maxSamples ,
1252+ defaultEvalInterval : ev .defaultEvalInterval ,
1253+ logger : ev .logger ,
1254+ isAlreadyV3IOAggregated : ev .isAlreadyV3IOAggregated ,
12371255 }
12381256
12391257 if e .Step != 0 {
@@ -1996,28 +2014,34 @@ func isV3ioEligibleFunction(function string) bool {
19962014 return supportedV3ioFunctions [function ]
19972015}
19982016
1999- func isV3ioEligibleQueryExpr (e Expr ) bool {
2000- switch expr := e .(type ) {
2017+ func isV3ioEligibleQueryExpr (p []Node ) bool {
2018+ if len (p ) == 0 {
2019+ return true
2020+ }
2021+ switch n := p [len (p )- 1 ].(type ) {
20012022 case * AggregateExpr :
2002- if ! isV3ioEligibleAggregation (expr .Op ) {
2023+ if ! isV3ioEligibleAggregation (n .Op ) {
20032024 return false
20042025 }
2005- if expr .Without {
2026+ if n .Without {
20062027 return false
20072028 }
20082029 // Currently only supports non-nested functions.
20092030 // Not supported - avg(max_over_time(cpu[10m])), Supported - avg(cpu)
2010- if e , ok := expr .Expr .(* Call ); ok {
2031+ if e , ok := n .Expr .(* Call ); ok {
20112032 if e .Func != nil {
20122033 return false
20132034 }
20142035 }
20152036 return true
20162037 case * Call :
2017- return isV3ioEligibleFunction (expr .Func .Name )
2038+ return isV3ioEligibleFunction (n .Func .Name )
2039+ case * BinaryExpr :
2040+ // If we hit a binary expression we terminate since we only care about functions
2041+ // or aggregations over a single metric.
2042+ return false
20182043 }
2019-
2020- return false
2044+ return isV3ioEligibleQueryExpr (p [:len (p )- 1 ])
20212045}
20222046
20232047// btos returns 1 if b is true, 0 otherwise.
0 commit comments