-
Notifications
You must be signed in to change notification settings - Fork 56
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
- Loading branch information
Showing
15 changed files
with
857 additions
and
0 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,7 @@ | ||
package cost | ||
|
||
type Cost interface{} | ||
|
||
type CostModel interface { | ||
IsBetter(currentCost Cost, newCost Cost) bool | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,74 @@ | ||
package logicalplan | ||
|
||
import "github.com/thanos-io/promql-engine/parser" | ||
|
||
func NewLogicalPlan(expr *parser.Expr) LogicalPlan { | ||
switch node := (*expr).(type) { | ||
case *parser.StepInvariantExpr: | ||
return &StepInvariantExpr{Expr: NewLogicalPlan(&node.Expr)} | ||
case *parser.VectorSelector: | ||
return &VectorSelector{ | ||
Name: node.Name, | ||
OriginalOffset: node.OriginalOffset, | ||
Offset: node.Offset, | ||
Timestamp: node.Timestamp, | ||
StartOrEnd: node.StartOrEnd, | ||
LabelMatchers: node.LabelMatchers, | ||
} | ||
case *parser.MatrixSelector: | ||
return &MatrixSelector{ | ||
VectorSelector: NewLogicalPlan(&node.VectorSelector), | ||
Range: node.Range, | ||
} | ||
case *parser.AggregateExpr: | ||
return &AggregateExpr{ | ||
Op: node.Op, | ||
Expr: NewLogicalPlan(&node.Expr), | ||
Param: NewLogicalPlan(&node.Param), | ||
Grouping: node.Grouping, | ||
Without: node.Without, | ||
} | ||
case *parser.Call: | ||
var args []LogicalPlan | ||
for i := range node.Args { | ||
args = append(args, NewLogicalPlan(&node.Args[i])) | ||
} | ||
return &Call{ | ||
Func: node.Func, | ||
Args: args, | ||
} | ||
case *parser.BinaryExpr: | ||
return &BinaryExpr{ | ||
Op: node.Op, | ||
LHS: NewLogicalPlan(&node.LHS), | ||
RHS: NewLogicalPlan(&node.RHS), | ||
VectorMatching: node.VectorMatching, | ||
ReturnBool: node.ReturnBool, | ||
} | ||
case *parser.UnaryExpr: | ||
return &UnaryExpr{ | ||
Op: node.Op, | ||
Expr: NewLogicalPlan(&node.Expr), | ||
} | ||
case *parser.ParenExpr: | ||
return &ParenExpr{ | ||
Expr: NewLogicalPlan(&node.Expr), | ||
} | ||
case *parser.SubqueryExpr: | ||
return &SubqueryExpr{ | ||
Expr: NewLogicalPlan(&node.Expr), | ||
Range: node.Range, | ||
OriginalOffset: node.OriginalOffset, | ||
Offset: node.Offset, | ||
Timestamp: node.Timestamp, | ||
StartOrEnd: node.StartOrEnd, | ||
Step: node.Step, | ||
} | ||
// literal types | ||
case *parser.NumberLiteral: | ||
return &NumberLiteral{Val: node.Val} | ||
case *parser.StringLiteral: | ||
return &StringLiteral{Val: node.Val} | ||
} | ||
return nil // should never reach here | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,81 @@ | ||
package logicalplan | ||
|
||
import ( | ||
"github.com/stretchr/testify/require" | ||
"github.com/thanos-io/promql-engine/parser" | ||
"math" | ||
"testing" | ||
) | ||
|
||
var ast2planTestCases = []struct { | ||
input parser.Expr // The AST input. | ||
expected LogicalPlan // The expected logical plan. | ||
}{ | ||
{ | ||
input: &parser.NumberLiteral{Val: 1}, | ||
expected: &NumberLiteral{Val: 1}, | ||
}, | ||
{ | ||
input: &parser.NumberLiteral{Val: math.Inf(1)}, | ||
expected: &NumberLiteral{Val: math.Inf(1)}, | ||
}, | ||
{ | ||
input: &parser.NumberLiteral{Val: math.Inf(-1)}, | ||
expected: &NumberLiteral{Val: math.Inf(-1)}, | ||
}, | ||
{ | ||
input: &parser.BinaryExpr{ | ||
Op: parser.ADD, | ||
LHS: &parser.NumberLiteral{Val: 1}, | ||
RHS: &parser.NumberLiteral{Val: 1}, | ||
}, | ||
expected: &BinaryExpr{ | ||
Op: parser.ADD, | ||
LHS: &NumberLiteral{Val: 1}, | ||
RHS: &NumberLiteral{Val: 1}, | ||
}, | ||
}, | ||
{ | ||
input: &parser.BinaryExpr{ | ||
Op: parser.ADD, | ||
LHS: &parser.NumberLiteral{Val: 1}, | ||
RHS: &parser.BinaryExpr{ | ||
Op: parser.DIV, | ||
LHS: &parser.NumberLiteral{Val: 2}, | ||
RHS: &parser.ParenExpr{ | ||
Expr: &parser.BinaryExpr{ | ||
Op: parser.MUL, | ||
LHS: &parser.NumberLiteral{Val: 3}, | ||
RHS: &parser.NumberLiteral{Val: 1}, | ||
}, | ||
}, | ||
}, | ||
}, | ||
expected: &BinaryExpr{ | ||
Op: parser.ADD, | ||
LHS: &NumberLiteral{Val: 1}, | ||
RHS: &BinaryExpr{ | ||
Op: parser.DIV, | ||
LHS: &NumberLiteral{Val: 2}, | ||
RHS: &ParenExpr{ | ||
Expr: &BinaryExpr{ | ||
Op: parser.MUL, | ||
LHS: &NumberLiteral{Val: 3}, | ||
RHS: &NumberLiteral{Val: 1}, | ||
}, | ||
}, | ||
}, | ||
}, | ||
}, | ||
// TODO add tests | ||
} | ||
|
||
func TestAST2Plan(t *testing.T) { | ||
for _, test := range ast2planTestCases { | ||
t.Run(test.input.String(), func(t *testing.T) { | ||
plan := NewLogicalPlan(&test.input) | ||
require.True(t, plan != nil, "could not convert AST to logical plan") | ||
require.Equal(t, test.expected, plan, "error on input '%s'", test.input.String()) | ||
}) | ||
} | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,156 @@ | ||
package logicalplan | ||
|
||
import ( | ||
"github.com/prometheus/prometheus/model/labels" | ||
"github.com/thanos-io/promql-engine/parser" | ||
"time" | ||
) | ||
|
||
type LogicalPlan interface { | ||
Children() LogicalPlans | ||
} | ||
|
||
type LogicalPlans []LogicalPlan | ||
|
||
// StepInvariantExpr represents a query which evaluates to the same result | ||
// irrespective of the evaluation time given the raw samples from TSDB remain unchanged. | ||
// Currently this is only used for engine optimisations and the parser does not produce this. | ||
type StepInvariantExpr struct { | ||
Expr LogicalPlan | ||
} | ||
|
||
func (l *StepInvariantExpr) Children() LogicalPlans { | ||
return []LogicalPlan{l.Expr} | ||
} | ||
|
||
// VectorSelector represents a Vector selection. | ||
type VectorSelector struct { | ||
Name string | ||
// OriginalOffset is the actual offset that was set in the query. | ||
// This never changes. | ||
OriginalOffset time.Duration | ||
// Offset is the offset used during the query execution | ||
// which is calculated using the original offset, at modifier time, | ||
// eval time, and subquery offsets in the AST tree. | ||
Offset time.Duration | ||
Timestamp *int64 | ||
StartOrEnd parser.ItemType // Set when @ is used with start() or end() | ||
LabelMatchers []*labels.Matcher | ||
} | ||
|
||
func (l *VectorSelector) Children() LogicalPlans { | ||
return []LogicalPlan{} | ||
} | ||
|
||
// MatrixSelector represents a Matrix selection. | ||
type MatrixSelector struct { | ||
// It is safe to assume that this is an VectorSelector | ||
// if the parser hasn't returned an error. | ||
VectorSelector LogicalPlan | ||
Range time.Duration | ||
} | ||
|
||
func (l *MatrixSelector) Children() LogicalPlans { | ||
return []LogicalPlan{l.VectorSelector} | ||
} | ||
|
||
// AggregateExpr represents an aggregation operation on a Vector. | ||
type AggregateExpr struct { | ||
Op parser.ItemType // The used aggregation operation. | ||
Expr LogicalPlan // The Vector expression over which is aggregated. | ||
Param LogicalPlan // Parameter used by some aggregators. | ||
Grouping []string // The labels by which to group the Vector. | ||
Without bool // Whether to drop the given labels rather than keep them. | ||
} | ||
|
||
func (l *AggregateExpr) Children() LogicalPlans { | ||
return []LogicalPlan{l.Expr, l.Param} | ||
} | ||
|
||
// Call represents a function call. | ||
type Call struct { | ||
Func *parser.Function // The function that was called. | ||
Args LogicalPlans // Arguments used in the call. | ||
} | ||
|
||
func (l *Call) Children() LogicalPlans { | ||
return l.Args | ||
} | ||
|
||
// BinaryExpr represents a binary expression between two child expressions. | ||
type BinaryExpr struct { | ||
Op parser.ItemType // The operation of the expression. | ||
LHS, RHS LogicalPlan // The operands on the respective sides of the operator. | ||
|
||
// The matching behavior for the operation if both operands are Vectors. | ||
// If they are not this field is nil. | ||
VectorMatching *parser.VectorMatching | ||
|
||
// If a comparison operator, return 0/1 rather than filtering. | ||
ReturnBool bool | ||
} | ||
|
||
func (l *BinaryExpr) Children() LogicalPlans { | ||
return []LogicalPlan{l.LHS, l.RHS} | ||
} | ||
|
||
// UnaryExpr represents a unary operation on another expression. | ||
// Currently unary operations are only supported for Scalars. | ||
type UnaryExpr struct { | ||
Op parser.ItemType | ||
Expr LogicalPlan | ||
} | ||
|
||
func (l *UnaryExpr) Children() LogicalPlans { | ||
return []LogicalPlan{l.Expr} | ||
} | ||
|
||
// ParenExpr wraps an expression so it cannot be disassembled as a consequence | ||
// of operator precedence. | ||
type ParenExpr struct { | ||
Expr LogicalPlan | ||
} | ||
|
||
func (l *ParenExpr) Children() LogicalPlans { | ||
return []LogicalPlan{l.Expr} | ||
} | ||
|
||
// SubqueryExpr represents a subquery. | ||
type SubqueryExpr struct { | ||
Expr LogicalPlan | ||
Range time.Duration | ||
// OriginalOffset is the actual offset that was set in the query. | ||
// This never changes. | ||
OriginalOffset time.Duration | ||
// Offset is the offset used during the query execution | ||
// which is calculated using the original offset, at modifier time, | ||
// eval time, and subquery offsets in the AST tree. | ||
Offset time.Duration | ||
Timestamp *int64 | ||
StartOrEnd parser.ItemType // Set when @ is used with start() or end() | ||
Step time.Duration | ||
} | ||
|
||
func (l *SubqueryExpr) Children() LogicalPlans { | ||
return []LogicalPlan{l.Expr} | ||
} | ||
|
||
// literal types | ||
|
||
// NumberLiteral represents a number. | ||
type NumberLiteral struct { | ||
Val float64 | ||
} | ||
|
||
func (l *NumberLiteral) Children() LogicalPlans { | ||
return []LogicalPlan{} | ||
} | ||
|
||
// StringLiteral represents a string. | ||
type StringLiteral struct { | ||
Val string | ||
} | ||
|
||
func (l *StringLiteral) Children() LogicalPlans { | ||
return []LogicalPlan{} | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,20 @@ | ||
package memo | ||
|
||
const ( | ||
InitialExplorationRound ExplorationRound = 0 | ||
) | ||
|
||
type ExplorationRound int // The exploration round. | ||
type ExplorationMark int // The exploration mark, if i-th bit of the mark is set, then i-th round is explored. | ||
|
||
func (e *ExplorationMark) IsExplored(round ExplorationRound) bool { | ||
return (*e & (1 << round)) != 0 | ||
} | ||
|
||
func (e *ExplorationMark) SetExplore(round ExplorationRound, explored bool) { | ||
if explored { | ||
*e |= 1 << round | ||
} else { | ||
*e &= ^(1 << round) | ||
} | ||
} |
Oops, something went wrong.