PromQL: AST: Make VectorSelector Children of MatrixSelector (#6590)

Make Vector selectors children of Matrix Selectors

Signed-off-by: Tobias Guggenmos <tguggenm@redhat.com>
This commit is contained in:
Tobias Guggenmos 2020-01-10 15:25:41 +01:00 committed by Brian Brazil
parent e7f7b6a06f
commit 64194f7d45
8 changed files with 185 additions and 172 deletions

View file

@ -107,14 +107,8 @@ type Call struct {
// MatrixSelector represents a Matrix selection. // MatrixSelector represents a Matrix selection.
type MatrixSelector struct { type MatrixSelector struct {
Name string VectorSelector *VectorSelector
Range time.Duration Range time.Duration
Offset time.Duration
LabelMatchers []*labels.Matcher
// The unexpanded seriesSet populated at query preparation time.
unexpandedSeriesSet storage.SeriesSet
series []storage.Series
} }
// SubqueryExpr represents a subquery. // SubqueryExpr represents a subquery.
@ -316,7 +310,9 @@ func Children(node Node) []Node {
return []Node{n.Expr} return []Node{n.Expr}
case *UnaryExpr: case *UnaryExpr:
return []Node{n.Expr} return []Node{n.Expr}
case *MatrixSelector, *NumberLiteral, *StringLiteral, *VectorSelector: case *MatrixSelector:
return []Node{n.VectorSelector}
case *NumberLiteral, *StringLiteral, *VectorSelector:
// nothing to do // nothing to do
return []Node{} return []Node{}
default: default:

View file

@ -623,8 +623,8 @@ func (ng *Engine) populateSeries(ctx context.Context, q storage.Queryable, s *Ev
if maxOffset < n.Range+subqOffset { if maxOffset < n.Range+subqOffset {
maxOffset = n.Range + subqOffset maxOffset = n.Range + subqOffset
} }
if n.Offset+n.Range+subqOffset > maxOffset { if m := n.VectorSelector.Offset + n.Range + subqOffset; m > maxOffset {
maxOffset = n.Offset + n.Range + subqOffset maxOffset = m
} }
} }
return nil return nil
@ -639,6 +639,11 @@ func (ng *Engine) populateSeries(ctx context.Context, q storage.Queryable, s *Ev
var warnings storage.Warnings var warnings storage.Warnings
// Whenever a MatrixSelector is evaluated this variable is set to the corresponding range.
// The evaluation of the VectorSelector inside then evaluates the given range and unsets
// the variable.
var evalRange time.Duration
Inspect(s.Expr, func(node Node, path []Node) error { Inspect(s.Expr, func(node Node, path []Node) error {
var set storage.SeriesSet var set storage.SeriesSet
var wrn storage.Warnings var wrn storage.Warnings
@ -658,7 +663,16 @@ func (ng *Engine) populateSeries(ctx context.Context, q storage.Queryable, s *Ev
switch n := node.(type) { switch n := node.(type) {
case *VectorSelector: case *VectorSelector:
params.Start = params.Start - durationMilliseconds(LookbackDelta) if evalRange == 0 {
params.Start = params.Start - durationMilliseconds(LookbackDelta)
} else {
params.Range = durationMilliseconds(evalRange)
// For all matrix queries we want to ensure that we have (end-start) + range selected
// this way we have `range` data before the start time
params.Start = params.Start - durationMilliseconds(evalRange)
evalRange = 0
}
params.Func = extractFuncFromPath(path) params.Func = extractFuncFromPath(path)
params.By, params.Grouping = extractGroupsFromPath(path) params.By, params.Grouping = extractGroupsFromPath(path)
if n.Offset > 0 { if n.Offset > 0 {
@ -676,24 +690,7 @@ func (ng *Engine) populateSeries(ctx context.Context, q storage.Queryable, s *Ev
n.unexpandedSeriesSet = set n.unexpandedSeriesSet = set
case *MatrixSelector: case *MatrixSelector:
params.Func = extractFuncFromPath(path) evalRange = n.Range
params.Range = durationMilliseconds(n.Range)
// For all matrix queries we want to ensure that we have (end-start) + range selected
// this way we have `range` data before the start time
params.Start = params.Start - durationMilliseconds(n.Range)
if n.Offset > 0 {
offsetMilliseconds := durationMilliseconds(n.Offset)
params.Start = params.Start - offsetMilliseconds
params.End = params.End - offsetMilliseconds
}
set, wrn, err = querier.Select(params, n.LabelMatchers...)
warnings = append(warnings, wrn...)
if err != nil {
level.Error(ng.logger).Log("msg", "error selecting series set", "err", err)
return err
}
n.unexpandedSeriesSet = set
} }
return nil return nil
}) })
@ -734,14 +731,7 @@ func extractGroupsFromPath(p []Node) (bool, []string) {
func checkForSeriesSetExpansion(ctx context.Context, expr Expr) { func checkForSeriesSetExpansion(ctx context.Context, expr Expr) {
switch e := expr.(type) { switch e := expr.(type) {
case *MatrixSelector: case *MatrixSelector:
if e.series == nil { checkForSeriesSetExpansion(ctx, e.VectorSelector)
series, err := expandSeriesSet(ctx, e.unexpandedSeriesSet)
if err != nil {
panic(err)
} else {
e.series = series
}
}
case *VectorSelector: case *VectorSelector:
if e.series == nil { if e.series == nil {
series, err := expandSeriesSet(ctx, e.unexpandedSeriesSet) series, err := expandSeriesSet(ctx, e.unexpandedSeriesSet)
@ -1000,12 +990,14 @@ func (ev *evaluator) rangeEval(f func([]Value, *EvalNodeHelper) Vector, exprs ..
func (ev *evaluator) evalSubquery(subq *SubqueryExpr) *MatrixSelector { func (ev *evaluator) evalSubquery(subq *SubqueryExpr) *MatrixSelector {
val := ev.eval(subq).(Matrix) val := ev.eval(subq).(Matrix)
ms := &MatrixSelector{ ms := &MatrixSelector{
Range: subq.Range, Range: subq.Range,
Offset: subq.Offset, VectorSelector: &VectorSelector{
series: make([]storage.Series, 0, len(val)), Offset: subq.Offset,
series: make([]storage.Series, 0, len(val)),
},
} }
for _, s := range val { for _, s := range val {
ms.series = append(ms.series, NewStorageSeries(s)) ms.VectorSelector.series = append(ms.VectorSelector.series, NewStorageSeries(s))
} }
return ms return ms
} }
@ -1085,9 +1077,11 @@ func (ev *evaluator) eval(expr Expr) Value {
} }
sel := e.Args[matrixArgIndex].(*MatrixSelector) sel := e.Args[matrixArgIndex].(*MatrixSelector)
selVS := sel.VectorSelector
checkForSeriesSetExpansion(ev.ctx, sel) checkForSeriesSetExpansion(ev.ctx, sel)
mat := make(Matrix, 0, len(sel.series)) // Output matrix. mat := make(Matrix, 0, len(selVS.series)) // Output matrix.
offset := durationMilliseconds(sel.Offset) offset := durationMilliseconds(selVS.Offset)
selRange := durationMilliseconds(sel.Range) selRange := durationMilliseconds(sel.Range)
stepRange := selRange stepRange := selRange
if stepRange > ev.interval { if stepRange > ev.interval {
@ -1100,17 +1094,17 @@ func (ev *evaluator) eval(expr Expr) Value {
enh := &EvalNodeHelper{out: make(Vector, 0, 1)} enh := &EvalNodeHelper{out: make(Vector, 0, 1)}
// Process all the calls for one time series at a time. // Process all the calls for one time series at a time.
it := storage.NewBuffer(selRange) it := storage.NewBuffer(selRange)
for i, s := range sel.series { for i, s := range selVS.series {
points = points[:0] points = points[:0]
it.Reset(s.Iterator()) it.Reset(s.Iterator())
ss := Series{ ss := Series{
// For all range vector functions, the only change to the // For all range vector functions, the only change to the
// output labels is dropping the metric name so just do // output labels is dropping the metric name so just do
// it once here. // it once here.
Metric: dropMetricName(sel.series[i].Labels()), Metric: dropMetricName(selVS.series[i].Labels()),
Points: getPointSlice(numSteps), Points: getPointSlice(numSteps),
} }
inMatrix[0].Metric = sel.series[i].Labels() inMatrix[0].Metric = selVS.series[i].Labels()
for ts, step := ev.startTimestamp, -1; ts <= ev.endTimestamp; ts += ev.interval { for ts, step := ev.startTimestamp, -1; ts <= ev.endTimestamp; ts += ev.interval {
step++ step++
// Set the non-matrix arguments. // Set the non-matrix arguments.
@ -1409,20 +1403,22 @@ func (ev *evaluator) matrixSelector(node *MatrixSelector) Matrix {
checkForSeriesSetExpansion(ev.ctx, node) checkForSeriesSetExpansion(ev.ctx, node)
var ( var (
offset = durationMilliseconds(node.Offset) offset = durationMilliseconds(node.VectorSelector.Offset)
maxt = ev.startTimestamp - offset maxt = ev.startTimestamp - offset
mint = maxt - durationMilliseconds(node.Range) mint = maxt - durationMilliseconds(node.Range)
matrix = make(Matrix, 0, len(node.series)) matrix = make(Matrix, 0, len(node.VectorSelector.series))
) )
it := storage.NewBuffer(durationMilliseconds(node.Range)) it := storage.NewBuffer(durationMilliseconds(node.Range))
for i, s := range node.series { series := node.VectorSelector.series
for i, s := range series {
if err := contextDone(ev.ctx, "expression evaluation"); err != nil { if err := contextDone(ev.ctx, "expression evaluation"); err != nil {
ev.error(err) ev.error(err)
} }
it.Reset(s.Iterator()) it.Reset(s.Iterator())
ss := Series{ ss := Series{
Metric: node.series[i].Labels(), Metric: series[i].Labels(),
} }
ss.Points = ev.matrixIterSlice(it, mint, maxt, getPointSlice(16)) ss.Points = ev.matrixIterSlice(it, mint, maxt, getPointSlice(16))

View file

@ -67,8 +67,8 @@ func extrapolatedRate(vals []Value, args Expressions, enh *EvalNodeHelper, isCou
var ( var (
samples = vals[0].(Matrix)[0] samples = vals[0].(Matrix)[0]
rangeStart = enh.ts - durationMilliseconds(ms.Range+ms.Offset) rangeStart = enh.ts - durationMilliseconds(ms.Range+ms.VectorSelector.Offset)
rangeEnd = enh.ts - durationMilliseconds(ms.Offset) rangeEnd = enh.ts - durationMilliseconds(ms.VectorSelector.Offset)
) )
// No sense in trying to compute a rate without at least two points. Drop // No sense in trying to compute a rate without at least two points. Drop
@ -1243,7 +1243,7 @@ func createLabelsForAbsentFunction(expr Expr) labels.Labels {
case *VectorSelector: case *VectorSelector:
lm = n.LabelMatchers lm = n.LabelMatchers
case *MatrixSelector: case *MatrixSelector:
lm = n.LabelMatchers lm = n.VectorSelector.LabelMatchers
default: default:
return m return m
} }

View file

@ -384,9 +384,7 @@ matrix_selector : expr LEFT_BRACKET duration RIGHT_BRACKET
yylex.(*parser).errorf("no offset modifiers allowed before range") yylex.(*parser).errorf("no offset modifiers allowed before range")
} }
$$ = &MatrixSelector{ $$ = &MatrixSelector{
Name: vs.Name, VectorSelector: vs,
Offset: vs.Offset,
LabelMatchers: vs.LabelMatchers,
Range: $3, Range: $3,
} }
} }

View file

@ -184,7 +184,7 @@ const yyEofCode = 1
const yyErrCode = 2 const yyErrCode = 2
const yyInitialStackSize = 16 const yyInitialStackSize = 16
//line promql/generated_parser.y:641 //line promql/generated_parser.y:639
//line yacctab:1 //line yacctab:1
var yyExca = [...]int{ var yyExca = [...]int{
@ -1119,15 +1119,13 @@ yydefault:
yylex.(*parser).errorf("no offset modifiers allowed before range") yylex.(*parser).errorf("no offset modifiers allowed before range")
} }
yyVAL.node = &MatrixSelector{ yyVAL.node = &MatrixSelector{
Name: vs.Name, VectorSelector: vs,
Offset: vs.Offset, Range: yyDollar[3].duration,
LabelMatchers: vs.LabelMatchers,
Range: yyDollar[3].duration,
} }
} }
case 67: case 67:
yyDollar = yyS[yypt-6 : yypt+1] yyDollar = yyS[yypt-6 : yypt+1]
//line promql/generated_parser.y:396 //line promql/generated_parser.y:394
{ {
yyVAL.node = &SubqueryExpr{ yyVAL.node = &SubqueryExpr{
Expr: yyDollar[1].node.(Expr), Expr: yyDollar[1].node.(Expr),
@ -1137,31 +1135,31 @@ yydefault:
} }
case 68: case 68:
yyDollar = yyS[yypt-6 : yypt+1] yyDollar = yyS[yypt-6 : yypt+1]
//line promql/generated_parser.y:404 //line promql/generated_parser.y:402
{ {
yylex.(*parser).unexpected("subquery selector", "\"]\"") yylex.(*parser).unexpected("subquery selector", "\"]\"")
} }
case 69: case 69:
yyDollar = yyS[yypt-5 : yypt+1] yyDollar = yyS[yypt-5 : yypt+1]
//line promql/generated_parser.y:406 //line promql/generated_parser.y:404
{ {
yylex.(*parser).unexpected("subquery selector", "duration or \"]\"") yylex.(*parser).unexpected("subquery selector", "duration or \"]\"")
} }
case 70: case 70:
yyDollar = yyS[yypt-4 : yypt+1] yyDollar = yyS[yypt-4 : yypt+1]
//line promql/generated_parser.y:408 //line promql/generated_parser.y:406
{ {
yylex.(*parser).unexpected("subquery or range", "\":\" or \"]\"") yylex.(*parser).unexpected("subquery or range", "\":\" or \"]\"")
} }
case 71: case 71:
yyDollar = yyS[yypt-3 : yypt+1] yyDollar = yyS[yypt-3 : yypt+1]
//line promql/generated_parser.y:410 //line promql/generated_parser.y:408
{ {
yylex.(*parser).unexpected("subquery selector", "duration") yylex.(*parser).unexpected("subquery selector", "duration")
} }
case 72: case 72:
yyDollar = yyS[yypt-2 : yypt+1] yyDollar = yyS[yypt-2 : yypt+1]
//line promql/generated_parser.y:420 //line promql/generated_parser.y:418
{ {
if nl, ok := yyDollar[2].node.(*NumberLiteral); ok { if nl, ok := yyDollar[2].node.(*NumberLiteral); ok {
if yyDollar[1].item.Typ == SUB { if yyDollar[1].item.Typ == SUB {
@ -1174,164 +1172,164 @@ yydefault:
} }
case 73: case 73:
yyDollar = yyS[yypt-2 : yypt+1] yyDollar = yyS[yypt-2 : yypt+1]
//line promql/generated_parser.y:437 //line promql/generated_parser.y:435
{ {
yyVAL.node = yylex.(*parser).newVectorSelector(yyDollar[1].item.Val, yyDollar[2].matchers) yyVAL.node = yylex.(*parser).newVectorSelector(yyDollar[1].item.Val, yyDollar[2].matchers)
} }
case 74: case 74:
yyDollar = yyS[yypt-1 : yypt+1] yyDollar = yyS[yypt-1 : yypt+1]
//line promql/generated_parser.y:439 //line promql/generated_parser.y:437
{ {
yyVAL.node = yylex.(*parser).newVectorSelector(yyDollar[1].item.Val, nil) yyVAL.node = yylex.(*parser).newVectorSelector(yyDollar[1].item.Val, nil)
} }
case 75: case 75:
yyDollar = yyS[yypt-1 : yypt+1] yyDollar = yyS[yypt-1 : yypt+1]
//line promql/generated_parser.y:441 //line promql/generated_parser.y:439
{ {
yyVAL.node = yylex.(*parser).newVectorSelector("", yyDollar[1].matchers) yyVAL.node = yylex.(*parser).newVectorSelector("", yyDollar[1].matchers)
} }
case 76: case 76:
yyDollar = yyS[yypt-3 : yypt+1] yyDollar = yyS[yypt-3 : yypt+1]
//line promql/generated_parser.y:445 //line promql/generated_parser.y:443
{ {
yyVAL.matchers = yyDollar[2].matchers yyVAL.matchers = yyDollar[2].matchers
} }
case 77: case 77:
yyDollar = yyS[yypt-4 : yypt+1] yyDollar = yyS[yypt-4 : yypt+1]
//line promql/generated_parser.y:447 //line promql/generated_parser.y:445
{ {
yyVAL.matchers = yyDollar[2].matchers yyVAL.matchers = yyDollar[2].matchers
} }
case 78: case 78:
yyDollar = yyS[yypt-2 : yypt+1] yyDollar = yyS[yypt-2 : yypt+1]
//line promql/generated_parser.y:449 //line promql/generated_parser.y:447
{ {
yyVAL.matchers = []*labels.Matcher{} yyVAL.matchers = []*labels.Matcher{}
} }
case 79: case 79:
yyDollar = yyS[yypt-3 : yypt+1] yyDollar = yyS[yypt-3 : yypt+1]
//line promql/generated_parser.y:454 //line promql/generated_parser.y:452
{ {
yyVAL.matchers = append(yyDollar[1].matchers, yyDollar[3].matcher) yyVAL.matchers = append(yyDollar[1].matchers, yyDollar[3].matcher)
} }
case 80: case 80:
yyDollar = yyS[yypt-1 : yypt+1] yyDollar = yyS[yypt-1 : yypt+1]
//line promql/generated_parser.y:456 //line promql/generated_parser.y:454
{ {
yyVAL.matchers = []*labels.Matcher{yyDollar[1].matcher} yyVAL.matchers = []*labels.Matcher{yyDollar[1].matcher}
} }
case 81: case 81:
yyDollar = yyS[yypt-2 : yypt+1] yyDollar = yyS[yypt-2 : yypt+1]
//line promql/generated_parser.y:458 //line promql/generated_parser.y:456
{ {
yylex.(*parser).unexpected("label matching", "\",\" or \"}\"") yylex.(*parser).unexpected("label matching", "\",\" or \"}\"")
} }
case 82: case 82:
yyDollar = yyS[yypt-3 : yypt+1] yyDollar = yyS[yypt-3 : yypt+1]
//line promql/generated_parser.y:462 //line promql/generated_parser.y:460
{ {
yyVAL.matcher = yylex.(*parser).newLabelMatcher(yyDollar[1].item, yyDollar[2].item, yyDollar[3].item) yyVAL.matcher = yylex.(*parser).newLabelMatcher(yyDollar[1].item, yyDollar[2].item, yyDollar[3].item)
} }
case 83: case 83:
yyDollar = yyS[yypt-3 : yypt+1] yyDollar = yyS[yypt-3 : yypt+1]
//line promql/generated_parser.y:464 //line promql/generated_parser.y:462
{ {
yylex.(*parser).unexpected("label matching", "string") yylex.(*parser).unexpected("label matching", "string")
} }
case 84: case 84:
yyDollar = yyS[yypt-2 : yypt+1] yyDollar = yyS[yypt-2 : yypt+1]
//line promql/generated_parser.y:466 //line promql/generated_parser.y:464
{ {
yylex.(*parser).unexpected("label matching", "label matching operator") yylex.(*parser).unexpected("label matching", "label matching operator")
} }
case 85: case 85:
yyDollar = yyS[yypt-1 : yypt+1] yyDollar = yyS[yypt-1 : yypt+1]
//line promql/generated_parser.y:468 //line promql/generated_parser.y:466
{ {
yylex.(*parser).unexpected("label matching", "identifier or \"}\"") yylex.(*parser).unexpected("label matching", "identifier or \"}\"")
} }
case 86: case 86:
yyDollar = yyS[yypt-2 : yypt+1] yyDollar = yyS[yypt-2 : yypt+1]
//line promql/generated_parser.y:476 //line promql/generated_parser.y:474
{ {
yyVAL.labels = append(yyDollar[2].labels, labels.Label{Name: labels.MetricName, Value: yyDollar[1].item.Val}) yyVAL.labels = append(yyDollar[2].labels, labels.Label{Name: labels.MetricName, Value: yyDollar[1].item.Val})
sort.Sort(yyVAL.labels) sort.Sort(yyVAL.labels)
} }
case 87: case 87:
yyDollar = yyS[yypt-1 : yypt+1] yyDollar = yyS[yypt-1 : yypt+1]
//line promql/generated_parser.y:478 //line promql/generated_parser.y:476
{ {
yyVAL.labels = yyDollar[1].labels yyVAL.labels = yyDollar[1].labels
} }
case 90: case 90:
yyDollar = yyS[yypt-3 : yypt+1] yyDollar = yyS[yypt-3 : yypt+1]
//line promql/generated_parser.y:485 //line promql/generated_parser.y:483
{ {
yyVAL.labels = labels.New(yyDollar[2].labels...) yyVAL.labels = labels.New(yyDollar[2].labels...)
} }
case 91: case 91:
yyDollar = yyS[yypt-4 : yypt+1] yyDollar = yyS[yypt-4 : yypt+1]
//line promql/generated_parser.y:487 //line promql/generated_parser.y:485
{ {
yyVAL.labels = labels.New(yyDollar[2].labels...) yyVAL.labels = labels.New(yyDollar[2].labels...)
} }
case 92: case 92:
yyDollar = yyS[yypt-2 : yypt+1] yyDollar = yyS[yypt-2 : yypt+1]
//line promql/generated_parser.y:489 //line promql/generated_parser.y:487
{ {
yyVAL.labels = labels.New() yyVAL.labels = labels.New()
} }
case 93: case 93:
yyDollar = yyS[yypt-0 : yypt+1] yyDollar = yyS[yypt-0 : yypt+1]
//line promql/generated_parser.y:491 //line promql/generated_parser.y:489
{ {
yyVAL.labels = labels.New() yyVAL.labels = labels.New()
} }
case 94: case 94:
yyDollar = yyS[yypt-3 : yypt+1] yyDollar = yyS[yypt-3 : yypt+1]
//line promql/generated_parser.y:495 //line promql/generated_parser.y:493
{ {
yyVAL.labels = append(yyDollar[1].labels, yyDollar[3].label) yyVAL.labels = append(yyDollar[1].labels, yyDollar[3].label)
} }
case 95: case 95:
yyDollar = yyS[yypt-1 : yypt+1] yyDollar = yyS[yypt-1 : yypt+1]
//line promql/generated_parser.y:497 //line promql/generated_parser.y:495
{ {
yyVAL.labels = []labels.Label{yyDollar[1].label} yyVAL.labels = []labels.Label{yyDollar[1].label}
} }
case 96: case 96:
yyDollar = yyS[yypt-2 : yypt+1] yyDollar = yyS[yypt-2 : yypt+1]
//line promql/generated_parser.y:499 //line promql/generated_parser.y:497
{ {
yylex.(*parser).unexpected("label set", "\",\" or \"}\"") yylex.(*parser).unexpected("label set", "\",\" or \"}\"")
} }
case 97: case 97:
yyDollar = yyS[yypt-3 : yypt+1] yyDollar = yyS[yypt-3 : yypt+1]
//line promql/generated_parser.y:504 //line promql/generated_parser.y:502
{ {
yyVAL.label = labels.Label{Name: yyDollar[1].item.Val, Value: yylex.(*parser).unquoteString(yyDollar[3].item.Val)} yyVAL.label = labels.Label{Name: yyDollar[1].item.Val, Value: yylex.(*parser).unquoteString(yyDollar[3].item.Val)}
} }
case 98: case 98:
yyDollar = yyS[yypt-3 : yypt+1] yyDollar = yyS[yypt-3 : yypt+1]
//line promql/generated_parser.y:506 //line promql/generated_parser.y:504
{ {
yylex.(*parser).unexpected("label set", "string") yylex.(*parser).unexpected("label set", "string")
} }
case 99: case 99:
yyDollar = yyS[yypt-2 : yypt+1] yyDollar = yyS[yypt-2 : yypt+1]
//line promql/generated_parser.y:508 //line promql/generated_parser.y:506
{ {
yylex.(*parser).unexpected("label set", "\"=\"") yylex.(*parser).unexpected("label set", "\"=\"")
} }
case 100: case 100:
yyDollar = yyS[yypt-1 : yypt+1] yyDollar = yyS[yypt-1 : yypt+1]
//line promql/generated_parser.y:510 //line promql/generated_parser.y:508
{ {
yylex.(*parser).unexpected("label set", "identifier or \"}\"") yylex.(*parser).unexpected("label set", "identifier or \"}\"")
} }
case 101: case 101:
yyDollar = yyS[yypt-2 : yypt+1] yyDollar = yyS[yypt-2 : yypt+1]
//line promql/generated_parser.y:518 //line promql/generated_parser.y:516
{ {
yylex.(*parser).generatedParserResult = &seriesDescription{ yylex.(*parser).generatedParserResult = &seriesDescription{
labels: yyDollar[1].labels, labels: yyDollar[1].labels,
@ -1340,37 +1338,37 @@ yydefault:
} }
case 102: case 102:
yyDollar = yyS[yypt-0 : yypt+1] yyDollar = yyS[yypt-0 : yypt+1]
//line promql/generated_parser.y:527 //line promql/generated_parser.y:525
{ {
yyVAL.series = []sequenceValue{} yyVAL.series = []sequenceValue{}
} }
case 103: case 103:
yyDollar = yyS[yypt-3 : yypt+1] yyDollar = yyS[yypt-3 : yypt+1]
//line promql/generated_parser.y:529 //line promql/generated_parser.y:527
{ {
yyVAL.series = append(yyDollar[1].series, yyDollar[3].series...) yyVAL.series = append(yyDollar[1].series, yyDollar[3].series...)
} }
case 104: case 104:
yyDollar = yyS[yypt-2 : yypt+1] yyDollar = yyS[yypt-2 : yypt+1]
//line promql/generated_parser.y:531 //line promql/generated_parser.y:529
{ {
yyVAL.series = yyDollar[1].series yyVAL.series = yyDollar[1].series
} }
case 105: case 105:
yyDollar = yyS[yypt-1 : yypt+1] yyDollar = yyS[yypt-1 : yypt+1]
//line promql/generated_parser.y:533 //line promql/generated_parser.y:531
{ {
yylex.(*parser).unexpected("series values", "") yylex.(*parser).unexpected("series values", "")
} }
case 106: case 106:
yyDollar = yyS[yypt-1 : yypt+1] yyDollar = yyS[yypt-1 : yypt+1]
//line promql/generated_parser.y:537 //line promql/generated_parser.y:535
{ {
yyVAL.series = []sequenceValue{{omitted: true}} yyVAL.series = []sequenceValue{{omitted: true}}
} }
case 107: case 107:
yyDollar = yyS[yypt-3 : yypt+1] yyDollar = yyS[yypt-3 : yypt+1]
//line promql/generated_parser.y:539 //line promql/generated_parser.y:537
{ {
yyVAL.series = []sequenceValue{} yyVAL.series = []sequenceValue{}
for i := uint64(0); i < yyDollar[3].uint; i++ { for i := uint64(0); i < yyDollar[3].uint; i++ {
@ -1379,13 +1377,13 @@ yydefault:
} }
case 108: case 108:
yyDollar = yyS[yypt-1 : yypt+1] yyDollar = yyS[yypt-1 : yypt+1]
//line promql/generated_parser.y:546 //line promql/generated_parser.y:544
{ {
yyVAL.series = []sequenceValue{{value: yyDollar[1].float}} yyVAL.series = []sequenceValue{{value: yyDollar[1].float}}
} }
case 109: case 109:
yyDollar = yyS[yypt-3 : yypt+1] yyDollar = yyS[yypt-3 : yypt+1]
//line promql/generated_parser.y:548 //line promql/generated_parser.y:546
{ {
yyVAL.series = []sequenceValue{} yyVAL.series = []sequenceValue{}
for i := uint64(0); i <= yyDollar[3].uint; i++ { for i := uint64(0); i <= yyDollar[3].uint; i++ {
@ -1394,7 +1392,7 @@ yydefault:
} }
case 110: case 110:
yyDollar = yyS[yypt-4 : yypt+1] yyDollar = yyS[yypt-4 : yypt+1]
//line promql/generated_parser.y:555 //line promql/generated_parser.y:553
{ {
yyVAL.series = []sequenceValue{} yyVAL.series = []sequenceValue{}
for i := uint64(0); i <= yyDollar[4].uint; i++ { for i := uint64(0); i <= yyDollar[4].uint; i++ {
@ -1404,7 +1402,7 @@ yydefault:
} }
case 111: case 111:
yyDollar = yyS[yypt-1 : yypt+1] yyDollar = yyS[yypt-1 : yypt+1]
//line promql/generated_parser.y:565 //line promql/generated_parser.y:563
{ {
if yyDollar[1].item.Val != "stale" { if yyDollar[1].item.Val != "stale" {
yylex.(*parser).unexpected("series values", "number or \"stale\"") yylex.(*parser).unexpected("series values", "number or \"stale\"")
@ -1413,31 +1411,31 @@ yydefault:
} }
case 154: case 154:
yyDollar = yyS[yypt-1 : yypt+1] yyDollar = yyS[yypt-1 : yypt+1]
//line promql/generated_parser.y:595 //line promql/generated_parser.y:593
{ {
yyVAL.node = &NumberLiteral{yyDollar[1].float} yyVAL.node = &NumberLiteral{yyDollar[1].float}
} }
case 155: case 155:
yyDollar = yyS[yypt-1 : yypt+1] yyDollar = yyS[yypt-1 : yypt+1]
//line promql/generated_parser.y:597 //line promql/generated_parser.y:595
{ {
yyVAL.float = yylex.(*parser).number(yyDollar[1].item.Val) yyVAL.float = yylex.(*parser).number(yyDollar[1].item.Val)
} }
case 156: case 156:
yyDollar = yyS[yypt-2 : yypt+1] yyDollar = yyS[yypt-2 : yypt+1]
//line promql/generated_parser.y:599 //line promql/generated_parser.y:597
{ {
yyVAL.float = yyDollar[2].float yyVAL.float = yyDollar[2].float
} }
case 157: case 157:
yyDollar = yyS[yypt-2 : yypt+1] yyDollar = yyS[yypt-2 : yypt+1]
//line promql/generated_parser.y:600 //line promql/generated_parser.y:598
{ {
yyVAL.float = -yyDollar[2].float yyVAL.float = -yyDollar[2].float
} }
case 158: case 158:
yyDollar = yyS[yypt-1 : yypt+1] yyDollar = yyS[yypt-1 : yypt+1]
//line promql/generated_parser.y:604 //line promql/generated_parser.y:602
{ {
var err error var err error
yyVAL.uint, err = strconv.ParseUint(yyDollar[1].item.Val, 10, 64) yyVAL.uint, err = strconv.ParseUint(yyDollar[1].item.Val, 10, 64)
@ -1447,7 +1445,7 @@ yydefault:
} }
case 159: case 159:
yyDollar = yyS[yypt-1 : yypt+1] yyDollar = yyS[yypt-1 : yypt+1]
//line promql/generated_parser.y:614 //line promql/generated_parser.y:612
{ {
var err error var err error
yyVAL.duration, err = parseDuration(yyDollar[1].item.Val) yyVAL.duration, err = parseDuration(yyDollar[1].item.Val)
@ -1457,25 +1455,25 @@ yydefault:
} }
case 160: case 160:
yyDollar = yyS[yypt-1 : yypt+1] yyDollar = yyS[yypt-1 : yypt+1]
//line promql/generated_parser.y:624 //line promql/generated_parser.y:622
{ {
yyVAL.node = &StringLiteral{yyDollar[1].string} yyVAL.node = &StringLiteral{yyDollar[1].string}
} }
case 161: case 161:
yyDollar = yyS[yypt-1 : yypt+1] yyDollar = yyS[yypt-1 : yypt+1]
//line promql/generated_parser.y:626 //line promql/generated_parser.y:624
{ {
yyVAL.string = yylex.(*parser).unquoteString(yyDollar[1].item.Val) yyVAL.string = yylex.(*parser).unquoteString(yyDollar[1].item.Val)
} }
case 162: case 162:
yyDollar = yyS[yypt-0 : yypt+1] yyDollar = yyS[yypt-0 : yypt+1]
//line promql/generated_parser.y:633 //line promql/generated_parser.y:631
{ {
yyVAL.duration = 0 yyVAL.duration = 0
} }
case 164: case 164:
yyDollar = yyS[yypt-0 : yypt+1] yyDollar = yyS[yypt-0 : yypt+1]
//line promql/generated_parser.y:637 //line promql/generated_parser.y:635
{ {
yyVAL.strings = nil yyVAL.strings = nil
} }

View file

@ -504,8 +504,10 @@ func (p *parser) checkType(node Node) (typ ValueType) {
if ty != ValueTypeVector { if ty != ValueTypeVector {
p.errorf("subquery is only allowed on instant vector, got %s in %q instead", ty, n.String()) p.errorf("subquery is only allowed on instant vector, got %s in %q instead", ty, n.String())
} }
case *MatrixSelector:
p.checkType(n.VectorSelector)
case *NumberLiteral, *MatrixSelector, *StringLiteral, *VectorSelector: case *NumberLiteral, *StringLiteral, *VectorSelector:
// Nothing to do for terminals. // Nothing to do for terminals.
default: default:
@ -581,7 +583,7 @@ func (p *parser) addOffset(e Node, offset time.Duration) {
case *VectorSelector: case *VectorSelector:
offsetp = &s.Offset offsetp = &s.Offset
case *MatrixSelector: case *MatrixSelector:
offsetp = &s.Offset offsetp = &s.VectorSelector.Offset
case *SubqueryExpr: case *SubqueryExpr:
offsetp = &s.Offset offsetp = &s.Offset
default: default:

View file

@ -1028,63 +1028,76 @@ var testExpr = []struct {
{ {
input: "test[5s]", input: "test[5s]",
expected: &MatrixSelector{ expected: &MatrixSelector{
Name: "test", VectorSelector: &VectorSelector{
Offset: 0, Name: "test",
Range: 5 * time.Second, Offset: 0,
LabelMatchers: []*labels.Matcher{ LabelMatchers: []*labels.Matcher{
mustLabelMatcher(labels.MatchEqual, string(model.MetricNameLabel), "test"), mustLabelMatcher(labels.MatchEqual, string(model.MetricNameLabel), "test"),
},
}, },
Range: 5 * time.Second,
}, },
}, { }, {
input: "test[5m]", input: "test[5m]",
expected: &MatrixSelector{ expected: &MatrixSelector{
Name: "test", VectorSelector: &VectorSelector{
Offset: 0, Name: "test",
Range: 5 * time.Minute, Offset: 0,
LabelMatchers: []*labels.Matcher{ LabelMatchers: []*labels.Matcher{
mustLabelMatcher(labels.MatchEqual, string(model.MetricNameLabel), "test"), mustLabelMatcher(labels.MatchEqual, string(model.MetricNameLabel), "test"),
},
}, },
Range: 5 * time.Minute,
}, },
}, { }, {
input: "test[5h] OFFSET 5m", input: "test[5h] OFFSET 5m",
expected: &MatrixSelector{ expected: &MatrixSelector{
Name: "test", VectorSelector: &VectorSelector{
Offset: 5 * time.Minute, Name: "test",
Range: 5 * time.Hour, Offset: 5 * time.Minute,
LabelMatchers: []*labels.Matcher{ LabelMatchers: []*labels.Matcher{
mustLabelMatcher(labels.MatchEqual, string(model.MetricNameLabel), "test"), mustLabelMatcher(labels.MatchEqual, string(model.MetricNameLabel), "test"),
},
}, },
Range: 5 * time.Hour,
}, },
}, { }, {
input: "test[5d] OFFSET 10s", input: "test[5d] OFFSET 10s",
expected: &MatrixSelector{ expected: &MatrixSelector{
Name: "test", VectorSelector: &VectorSelector{
Offset: 10 * time.Second, Name: "test",
Range: 5 * 24 * time.Hour, Offset: 10 * time.Second,
LabelMatchers: []*labels.Matcher{ LabelMatchers: []*labels.Matcher{
mustLabelMatcher(labels.MatchEqual, string(model.MetricNameLabel), "test"), mustLabelMatcher(labels.MatchEqual, string(model.MetricNameLabel), "test"),
},
}, },
Range: 5 * 24 * time.Hour,
}, },
}, { }, {
input: "test[5w] offset 2w", input: "test[5w] offset 2w",
expected: &MatrixSelector{ expected: &MatrixSelector{
Name: "test", VectorSelector: &VectorSelector{
Offset: 14 * 24 * time.Hour, Name: "test",
Range: 5 * 7 * 24 * time.Hour, Offset: 14 * 24 * time.Hour,
LabelMatchers: []*labels.Matcher{ LabelMatchers: []*labels.Matcher{
mustLabelMatcher(labels.MatchEqual, string(model.MetricNameLabel), "test"), mustLabelMatcher(labels.MatchEqual, string(model.MetricNameLabel), "test"),
},
}, },
Range: 5 * 7 * 24 * time.Hour,
}, },
}, { }, {
input: `test{a="b"}[5y] OFFSET 3d`, input: `test{a="b"}[5y] OFFSET 3d`,
expected: &MatrixSelector{ expected: &MatrixSelector{
Name: "test", VectorSelector: &VectorSelector{
Offset: 3 * 24 * time.Hour, Name: "test",
Range: 5 * 365 * 24 * time.Hour, Offset: 3 * 24 * time.Hour,
LabelMatchers: []*labels.Matcher{ LabelMatchers: []*labels.Matcher{
mustLabelMatcher(labels.MatchEqual, "a", "b"), mustLabelMatcher(labels.MatchEqual, "a", "b"),
mustLabelMatcher(labels.MatchEqual, string(model.MetricNameLabel), "test"), mustLabelMatcher(labels.MatchEqual, string(model.MetricNameLabel), "test"),
},
}, },
Range: 5 * 365 * 24 * time.Hour,
}, },
}, { }, {
input: `foo[5mm]`, input: `foo[5mm]`,
@ -1378,9 +1391,11 @@ var testExpr = []struct {
Func: mustGetFunction("rate"), Func: mustGetFunction("rate"),
Args: Expressions{ Args: Expressions{
&MatrixSelector{ &MatrixSelector{
Name: "some_metric", VectorSelector: &VectorSelector{
LabelMatchers: []*labels.Matcher{ Name: "some_metric",
mustLabelMatcher(labels.MatchEqual, string(model.MetricNameLabel), "some_metric"), LabelMatchers: []*labels.Matcher{
mustLabelMatcher(labels.MatchEqual, string(model.MetricNameLabel), "some_metric"),
},
}, },
Range: 5 * time.Minute, Range: 5 * time.Minute,
}, },
@ -1535,12 +1550,14 @@ var testExpr = []struct {
Func: mustGetFunction("rate"), Func: mustGetFunction("rate"),
Args: Expressions{ Args: Expressions{
&MatrixSelector{ &MatrixSelector{
Name: "foo", VectorSelector: &VectorSelector{
Range: 2 * time.Second, Name: "foo",
LabelMatchers: []*labels.Matcher{ LabelMatchers: []*labels.Matcher{
mustLabelMatcher(labels.MatchEqual, "bar", "baz"), mustLabelMatcher(labels.MatchEqual, "bar", "baz"),
mustLabelMatcher(labels.MatchEqual, string(model.MetricNameLabel), "foo"), mustLabelMatcher(labels.MatchEqual, string(model.MetricNameLabel), "foo"),
},
}, },
Range: 2 * time.Second,
}, },
}, },
}, },
@ -1560,12 +1577,14 @@ var testExpr = []struct {
Func: mustGetFunction("rate"), Func: mustGetFunction("rate"),
Args: Expressions{ Args: Expressions{
&MatrixSelector{ &MatrixSelector{
Name: "foo", VectorSelector: &VectorSelector{
Range: 2 * time.Second, Name: "foo",
LabelMatchers: []*labels.Matcher{ LabelMatchers: []*labels.Matcher{
mustLabelMatcher(labels.MatchEqual, "bar", "baz"), mustLabelMatcher(labels.MatchEqual, "bar", "baz"),
mustLabelMatcher(labels.MatchEqual, string(model.MetricNameLabel), "foo"), mustLabelMatcher(labels.MatchEqual, string(model.MetricNameLabel), "foo"),
},
}, },
Range: 2 * time.Second,
}, },
}, },
}, },
@ -1587,12 +1606,14 @@ var testExpr = []struct {
Func: mustGetFunction("rate"), Func: mustGetFunction("rate"),
Args: Expressions{ Args: Expressions{
&MatrixSelector{ &MatrixSelector{
Name: "foo", VectorSelector: &VectorSelector{
Range: 2 * time.Second, Name: "foo",
LabelMatchers: []*labels.Matcher{ LabelMatchers: []*labels.Matcher{
mustLabelMatcher(labels.MatchEqual, "bar", "baz"), mustLabelMatcher(labels.MatchEqual, "bar", "baz"),
mustLabelMatcher(labels.MatchEqual, string(model.MetricNameLabel), "foo"), mustLabelMatcher(labels.MatchEqual, string(model.MetricNameLabel), "foo"),
},
}, },
Range: 2 * time.Second,
}, },
}, },
}, },

View file

@ -112,14 +112,16 @@ func (node *Call) String() string {
} }
func (node *MatrixSelector) String() string { func (node *MatrixSelector) String() string {
vecSelector := &VectorSelector{ // Copy the Vector selector before changing the offset
Name: node.Name, var vecSelector VectorSelector = *node.VectorSelector
LabelMatchers: node.LabelMatchers,
}
offset := "" offset := ""
if node.Offset != time.Duration(0) { if vecSelector.Offset != time.Duration(0) {
offset = fmt.Sprintf(" offset %s", model.Duration(node.Offset)) offset = fmt.Sprintf(" offset %s", model.Duration(vecSelector.Offset))
} }
// Do not print the offset twice.
vecSelector.Offset = 0
return fmt.Sprintf("%s[%s]%s", vecSelector.String(), model.Duration(node.Range), offset) return fmt.Sprintf("%s[%s]%s", vecSelector.String(), model.Duration(node.Range), offset)
} }