Skip to content

Commit 3888866

Browse files
authored
fix(engine): Fix Walk() function implementation on various Expr implementations (#16033)
The `Walk(f WalkFn)` implementation expects to first visit the current node and then invoke `Walk(f)` on all its children if they are not `nil`. This also fixes the `checkIntervalLimit(syntax.SampleExpr, time.Duration)` function, which did not visit the expression if it was a `*ConcatSampleExpr`. Signed-off-by: Christian Haudum <christian.haudum@gmail.com>
1 parent 3a02d64 commit 3888866

File tree

7 files changed

+97
-40
lines changed

7 files changed

+97
-40
lines changed

‎pkg/logql/downstream.go

Lines changed: 30 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -139,7 +139,12 @@ func (d DownstreamLogSelectorExpr) Pretty(level int) string {
139139
return s
140140
}
141141

142-
func (d DownstreamSampleExpr) Walk(f syntax.WalkFn) { f(d) }
142+
func (d DownstreamSampleExpr) Walk(f syntax.WalkFn) {
143+
f(d)
144+
if d.SampleExpr != nil {
145+
d.SampleExpr.Walk(f)
146+
}
147+
}
143148

144149
var defaultMaxDepth = 4
145150

@@ -173,7 +178,12 @@ func (c *ConcatSampleExpr) string(maxDepth int) string {
173178

174179
func (c *ConcatSampleExpr) Walk(f syntax.WalkFn) {
175180
f(c)
176-
f(c.next)
181+
if c.SampleExpr != nil {
182+
c.SampleExpr.Walk(f)
183+
}
184+
if c.next != nil {
185+
c.next.Walk(f)
186+
}
177187
}
178188

179189
// ConcatSampleExpr has no LogQL repretenstation. It is expressed in in the
@@ -271,7 +281,12 @@ func (e QuantileSketchEvalExpr) String() string {
271281

272282
func (e *QuantileSketchEvalExpr) Walk(f syntax.WalkFn) {
273283
f(e)
274-
e.quantileMergeExpr.Walk(f)
284+
if e.SampleExpr != nil {
285+
e.SampleExpr.Walk(f)
286+
}
287+
if e.quantileMergeExpr != nil {
288+
e.quantileMergeExpr.Walk(f)
289+
}
275290
}
276291

277292
type QuantileSketchMergeExpr struct {
@@ -297,6 +312,9 @@ func (e QuantileSketchMergeExpr) String() string {
297312

298313
func (e *QuantileSketchMergeExpr) Walk(f syntax.WalkFn) {
299314
f(e)
315+
if e.SampleExpr != nil {
316+
e.SampleExpr.Walk(f)
317+
}
300318
for _, d := range e.downstreams {
301319
d.Walk(f)
302320
}
@@ -326,6 +344,9 @@ func (e MergeFirstOverTimeExpr) String() string {
326344

327345
func (e *MergeFirstOverTimeExpr) Walk(f syntax.WalkFn) {
328346
f(e)
347+
if e.SampleExpr != nil {
348+
e.SampleExpr.Walk(f)
349+
}
329350
for _, d := range e.downstreams {
330351
d.Walk(f)
331352
}
@@ -355,6 +376,9 @@ func (e MergeLastOverTimeExpr) String() string {
355376

356377
func (e *MergeLastOverTimeExpr) Walk(f syntax.WalkFn) {
357378
f(e)
379+
if e.SampleExpr != nil {
380+
e.SampleExpr.Walk(f)
381+
}
358382
for _, d := range e.downstreams {
359383
d.Walk(f)
360384
}
@@ -383,6 +407,9 @@ func (e CountMinSketchEvalExpr) String() string {
383407

384408
func (e *CountMinSketchEvalExpr) Walk(f syntax.WalkFn) {
385409
f(e)
410+
if e.SampleExpr != nil {
411+
e.SampleExpr.Walk(f)
412+
}
386413
for _, d := range e.downstreams {
387414
d.Walk(f)
388415
}

‎pkg/logql/engine.go

Lines changed: 3 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -489,11 +489,10 @@ func (q *query) checkIntervalLimit(expr syntax.SampleExpr, limit time.Duration)
489489
var err error
490490
expr.Walk(func(e syntax.Expr) {
491491
switch e := e.(type) {
492-
case *syntax.RangeAggregationExpr:
493-
if e.Left == nil || e.Left.Interval <= limit {
494-
return
492+
case *syntax.LogRange:
493+
if e.Interval > limit {
494+
err = fmt.Errorf("%w: [%s] > [%s]", logqlmodel.ErrIntervalLimit, model.Duration(e.Interval), model.Duration(limit))
495495
}
496-
err = fmt.Errorf("%w: [%s] > [%s]", logqlmodel.ErrIntervalLimit, model.Duration(e.Left.Interval), model.Duration(limit))
497496
}
498497
})
499498
return err

‎pkg/logql/engine_test.go

Lines changed: 39 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -38,6 +38,45 @@ var (
3838
ErrMockMultiple = util.MultiError{ErrMock, ErrMock}
3939
)
4040

41+
func TestEngine_checkIntervalLimit(t *testing.T) {
42+
q := &query{}
43+
for _, tc := range []struct {
44+
query string
45+
expErr string
46+
}{
47+
{query: `rate({app="foo"} [1m])`, expErr: ""},
48+
{query: `rate({app="foo"} [10m])`, expErr: ""},
49+
{query: `max(rate({app="foo"} [5m])) - max(rate({app="bar"} [10m]))`, expErr: ""},
50+
{query: `rate({app="foo"} [5m]) - rate({app="bar"} [15m])`, expErr: "[15m] > [10m]"},
51+
{query: `rate({app="foo"} [1h])`, expErr: "[1h] > [10m]"},
52+
{query: `sum(rate({app="foo"} [1h]))`, expErr: "[1h] > [10m]"},
53+
{query: `sum_over_time({app="foo"} |= "foo" | json | unwrap bar [1h])`, expErr: "[1h] > [10m]"},
54+
} {
55+
for _, downstream := range []bool{true, false} {
56+
t.Run(fmt.Sprintf("%v/downstream=%v", tc.query, downstream), func(t *testing.T) {
57+
expr := syntax.MustParseExpr(tc.query).(syntax.SampleExpr)
58+
if downstream {
59+
// Simulate downstream expression
60+
expr = &ConcatSampleExpr{
61+
DownstreamSampleExpr: DownstreamSampleExpr{
62+
shard: nil,
63+
SampleExpr: expr,
64+
},
65+
next: nil,
66+
}
67+
}
68+
err := q.checkIntervalLimit(expr, 10*time.Minute)
69+
if tc.expErr != "" {
70+
require.ErrorContains(t, err, tc.expErr)
71+
} else {
72+
require.NoError(t, err)
73+
}
74+
})
75+
}
76+
77+
}
78+
}
79+
4180
func TestEngine_LogsRateUnwrap(t *testing.T) {
4281
t.Parallel()
4382
for _, test := range []struct {

‎pkg/logql/syntax/ast.go

Lines changed: 23 additions & 23 deletions
Original file line numberDiff line numberDiff line change
@@ -341,16 +341,12 @@ func (e *PipelineExpr) Shardable(topLevel bool) bool {
341341
func (e *PipelineExpr) Walk(f WalkFn) {
342342
f(e)
343343

344-
if e.Left == nil {
345-
return
344+
if e.Left != nil {
345+
e.Left.Walk(f)
346346
}
347-
348-
xs := make([]Walkable, 0, len(e.MultiStages)+1)
349-
xs = append(xs, e.Left)
350347
for _, p := range e.MultiStages {
351-
xs = append(xs, p)
348+
p.Walk(f)
352349
}
353-
walkAll(f, xs...)
354350
}
355351

356352
func (e *PipelineExpr) Accept(v RootVisitor) { v.VisitPipeline(e) }
@@ -501,10 +497,12 @@ func (*LineFilterExpr) isStageExpr() {}
501497

502498
func (e *LineFilterExpr) Walk(f WalkFn) {
503499
f(e)
504-
if e.Left == nil {
505-
return
500+
if e.Left != nil {
501+
e.Left.Walk(f)
502+
}
503+
if e.Or != nil {
504+
e.Or.Walk(f)
506505
}
507-
e.Left.Walk(f)
508506
}
509507

510508
func (e *LineFilterExpr) Accept(v RootVisitor) {
@@ -1153,10 +1151,9 @@ func (r *LogRange) Shardable(topLevel bool) bool { return r.Left.Shardable(topLe
11531151

11541152
func (r *LogRange) Walk(f WalkFn) {
11551153
f(r)
1156-
if r.Left == nil {
1157-
return
1154+
if r.Left != nil {
1155+
r.Left.Walk(f)
11581156
}
1159-
r.Left.Walk(f)
11601157
}
11611158

11621159
func (r *LogRange) Accept(v RootVisitor) {
@@ -1476,10 +1473,9 @@ func (e *RangeAggregationExpr) Shardable(topLevel bool) bool {
14761473

14771474
func (e *RangeAggregationExpr) Walk(f WalkFn) {
14781475
f(e)
1479-
if e.Left == nil {
1480-
return
1476+
if e.Left != nil {
1477+
e.Left.Walk(f)
14811478
}
1482-
e.Left.Walk(f)
14831479
}
14841480

14851481
func (e *RangeAggregationExpr) Accept(v RootVisitor) { v.VisitRangeAggregation(e) }
@@ -1686,10 +1682,9 @@ func (e *VectorAggregationExpr) Shardable(topLevel bool) bool {
16861682

16871683
func (e *VectorAggregationExpr) Walk(f WalkFn) {
16881684
f(e)
1689-
if e.Left == nil {
1690-
return
1685+
if e.Left != nil {
1686+
e.Left.Walk(f)
16911687
}
1692-
e.Left.Walk(f)
16931688
}
16941689

16951690
func (e *VectorAggregationExpr) Accept(v RootVisitor) { v.VisitVectorAggregation(e) }
@@ -1806,7 +1801,13 @@ func (e *BinOpExpr) Shardable(topLevel bool) bool {
18061801
}
18071802

18081803
func (e *BinOpExpr) Walk(f WalkFn) {
1809-
walkAll(f, e.SampleExpr, e.RHS)
1804+
f(e)
1805+
if e.SampleExpr != nil {
1806+
e.SampleExpr.Walk(f)
1807+
}
1808+
if e.RHS != nil {
1809+
e.RHS.Walk(f)
1810+
}
18101811
}
18111812

18121813
func (e *BinOpExpr) Accept(v RootVisitor) { v.VisitBinOp(e) }
@@ -2235,10 +2236,9 @@ func (e *LabelReplaceExpr) Shardable(_ bool) bool {
22352236

22362237
func (e *LabelReplaceExpr) Walk(f WalkFn) {
22372238
f(e)
2238-
if e.Left == nil {
2239-
return
2239+
if e.Left != nil {
2240+
e.Left.Walk(f)
22402241
}
2241-
e.Left.Walk(f)
22422242
}
22432243

22442244
func (e *LabelReplaceExpr) Accept(v RootVisitor) { v.VisitLabelReplace(e) }

‎pkg/logql/syntax/walk.go

Lines changed: 0 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -2,12 +2,6 @@ package syntax
22

33
type WalkFn = func(e Expr)
44

5-
func walkAll(f WalkFn, xs ...Walkable) {
6-
for _, x := range xs {
7-
x.Walk(f)
8-
}
9-
}
10-
115
type Walkable interface {
126
Walk(f WalkFn)
137
}

‎pkg/logql/syntax/walk_test.go

Lines changed: 1 addition & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -22,7 +22,7 @@ func Test_Walkable(t *testing.T) {
2222
{
2323
desc: "bin op query",
2424
expr: `(sum by(cluster)(rate({job="foo"} |= "bar" | logfmt | bazz="buzz"[5m])) / sum by(cluster)(rate({job="foo"} |= "bar" | logfmt | bazz="buzz"[5m])))`,
25-
want: 16,
25+
want: 17,
2626
},
2727
}
2828
for _, test := range tests {
@@ -79,8 +79,6 @@ func Test_AppendMatchers(t *testing.T) {
7979
switch me := e.(type) {
8080
case *MatchersExpr:
8181
me.AppendMatchers(test.matchers)
82-
default:
83-
// Do nothing
8482
}
8583
})
8684
require.Equal(t, test.want, expr.String())

‎pkg/querier/queryrange/roundtrip_test.go

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1464,7 +1464,7 @@ func (f fakeLimits) MaxQueryLength(context.Context, string) time.Duration {
14641464
}
14651465

14661466
func (f fakeLimits) MaxQueryRange(context.Context, string) time.Duration {
1467-
return time.Second
1467+
return time.Hour
14681468
}
14691469

14701470
func (f fakeLimits) MaxQueryParallelism(context.Context, string) int {

0 commit comments

Comments
 (0)