working commit

This commit is contained in:
Thomas Jackson 2021-01-14 22:02:16 -08:00 committed by Rishabh Kumar
parent 106542a1fe
commit 07f178a4be
6 changed files with 123 additions and 37 deletions

View file

@ -1259,7 +1259,7 @@ func labelsSetPromQL(query, labelMatchType, name, value string) error {
return fmt.Errorf("invalid label match type: %s", labelMatchType) return fmt.Errorf("invalid label match type: %s", labelMatchType)
} }
parser.Inspect(expr, func(node parser.Node, path []parser.Node) error { parser.Inspect(context.TODO(), &parser.EvalStmt{Expr: expr}, func(node parser.Node, path []parser.Node) error {
if n, ok := node.(*parser.VectorSelector); ok { if n, ok := node.(*parser.VectorSelector); ok {
var found bool var found bool
for i, l := range n.LabelMatchers { for i, l := range n.LabelMatchers {
@ -1278,7 +1278,7 @@ func labelsSetPromQL(query, labelMatchType, name, value string) error {
} }
} }
return nil return nil
}) }, nil)
fmt.Println(expr.Pretty(0)) fmt.Println(expr.Pretty(0))
return nil return nil
@ -1290,7 +1290,7 @@ func labelsDeletePromQL(query, name string) error {
return err return err
} }
parser.Inspect(expr, func(node parser.Node, path []parser.Node) error { parser.Inspect(context.TODO(), &parser.EvalStmt{Expr: expr}, func(node parser.Node, path []parser.Node) error {
if n, ok := node.(*parser.VectorSelector); ok { if n, ok := node.(*parser.VectorSelector); ok {
for i, l := range n.LabelMatchers { for i, l := range n.LabelMatchers {
if l.Name == name { if l.Name == name {
@ -1299,7 +1299,7 @@ func labelsDeletePromQL(query, name string) error {
} }
} }
return nil return nil
}) }, nil)
fmt.Println(expr.Pretty(0)) fmt.Println(expr.Pretty(0))
return nil return nil

View file

@ -344,6 +344,7 @@ type Engine struct {
enableNegativeOffset bool enableNegativeOffset bool
enablePerStepStats bool enablePerStepStats bool
enableDelayedNameRemoval bool enableDelayedNameRemoval bool
NodeReplacer parser.NodeReplacer
} }
// NewEngine returns a new engine. // NewEngine returns a new engine.
@ -485,10 +486,11 @@ func (ng *Engine) NewInstantQuery(ctx context.Context, q storage.Queryable, opts
if err != nil { if err != nil {
return nil, err return nil, err
} }
if err := ng.validateOpts(expr); err != nil {
if err := ng.validateOpts(pExpr); err != nil {
return nil, err return nil, err
} }
*pExpr = PreprocessExpr(expr, ts, ts) pExpr.Expr = PreprocessExpr(expr, ts, ts)
return qry, nil return qry, nil
} }
@ -506,18 +508,24 @@ func (ng *Engine) NewRangeQuery(ctx context.Context, q storage.Queryable, opts Q
if err != nil { if err != nil {
return nil, err return nil, err
} }
if err := ng.validateOpts(expr); err != nil {
lookbackDelta := opts.LookbackDelta()
if lookbackDelta <= 0 {
lookbackDelta = ng.lookbackDelta
}
if err := ng.validateOpts(pExpr); err != nil {
return nil, err return nil, err
} }
if expr.Type() != parser.ValueTypeVector && expr.Type() != parser.ValueTypeScalar { if expr.Type() != parser.ValueTypeVector && expr.Type() != parser.ValueTypeScalar {
return nil, fmt.Errorf("invalid expression type %q for range query, must be Scalar or instant Vector", parser.DocumentedType(expr.Type())) return nil, fmt.Errorf("invalid expression type %q for range query, must be Scalar or instant Vector", parser.DocumentedType(expr.Type()))
} }
*pExpr = PreprocessExpr(expr, start, end) pExpr.Expr = PreprocessExpr(expr, start, end)
return qry, nil return qry, nil
} }
func (ng *Engine) newQuery(q storage.Queryable, qs string, opts QueryOpts, start, end time.Time, interval time.Duration) (*parser.Expr, *query) { func (ng *Engine) newQuery(q storage.Queryable, qs string, opts QueryOpts, start, end time.Time, interval time.Duration) (*parser.EvalStmt, *query) {
if opts == nil { if opts == nil {
opts = NewPrometheusQueryOpts(false, 0) opts = NewPrometheusQueryOpts(false, 0)
} }
@ -541,7 +549,7 @@ func (ng *Engine) newQuery(q storage.Queryable, qs string, opts QueryOpts, start
sampleStats: stats.NewQuerySamples(ng.enablePerStepStats && opts.EnablePerStepStats()), sampleStats: stats.NewQuerySamples(ng.enablePerStepStats && opts.EnablePerStepStats()),
queryable: q, queryable: q,
} }
return &es.Expr, qry return es, qry
} }
var ( var (
@ -549,7 +557,7 @@ var (
ErrValidationNegativeOffsetDisabled = errors.New("negative offset is disabled") ErrValidationNegativeOffsetDisabled = errors.New("negative offset is disabled")
) )
func (ng *Engine) validateOpts(expr parser.Expr) error { func (ng *Engine) validateOpts(expr *parser.EvalStmt) error {
if ng.enableAtModifier && ng.enableNegativeOffset { if ng.enableAtModifier && ng.enableNegativeOffset {
return nil return nil
} }
@ -557,7 +565,7 @@ func (ng *Engine) validateOpts(expr parser.Expr) error {
var atModifierUsed, negativeOffsetUsed bool var atModifierUsed, negativeOffsetUsed bool
var validationErr error var validationErr error
parser.Inspect(expr, func(node parser.Node, path []parser.Node) error { parser.Inspect(context.TODO(), expr, func(node parser.Node, path []parser.Node) error {
switch n := node.(type) { switch n := node.(type) {
case *parser.VectorSelector: case *parser.VectorSelector:
if n.Timestamp != nil || n.StartOrEnd == parser.START || n.StartOrEnd == parser.END { if n.Timestamp != nil || n.StartOrEnd == parser.START || n.StartOrEnd == parser.END {
@ -595,7 +603,7 @@ func (ng *Engine) validateOpts(expr parser.Expr) error {
} }
return nil return nil
}) }, nil)
return validationErr return validationErr
} }
@ -869,7 +877,7 @@ func FindMinMaxTime(s *parser.EvalStmt) (int64, int64) {
// The evaluation of the VectorSelector inside then evaluates the given range and unsets // The evaluation of the VectorSelector inside then evaluates the given range and unsets
// the variable. // the variable.
var evalRange time.Duration var evalRange time.Duration
parser.Inspect(s.Expr, func(node parser.Node, path []parser.Node) error { parser.Inspect(context.TODO(), s, func(node parser.Node, path []parser.Node) error {
switch n := node.(type) { switch n := node.(type) {
case *parser.VectorSelector: case *parser.VectorSelector:
start, end := getTimeRangesForSelector(s, n, path, evalRange) start, end := getTimeRangesForSelector(s, n, path, evalRange)
@ -884,7 +892,7 @@ func FindMinMaxTime(s *parser.EvalStmt) (int64, int64) {
evalRange = n.Range evalRange = n.Range
} }
return nil return nil
}) }, nil)
if maxTimestamp == math.MinInt64 { if maxTimestamp == math.MinInt64 {
// This happens when there was no selector. Hence no time range to select. // This happens when there was no selector. Hence no time range to select.
@ -954,8 +962,11 @@ func (ng *Engine) populateSeries(ctx context.Context, querier storage.Querier, s
// The evaluation of the VectorSelector inside then evaluates the given range and unsets // The evaluation of the VectorSelector inside then evaluates the given range and unsets
// the variable. // the variable.
var evalRange time.Duration var evalRange time.Duration
l := sync.Mutex{}
parser.Inspect(s.Expr, func(node parser.Node, path []parser.Node) error { n, err := parser.Inspect(context.TODO(), s, func(node parser.Node, path []parser.Node) error {
l.Lock()
defer l.Unlock()
switch n := node.(type) { switch n := node.(type) {
case *parser.VectorSelector: case *parser.VectorSelector:
start, end := getTimeRangesForSelector(s, n, path, evalRange) start, end := getTimeRangesForSelector(s, n, path, evalRange)
@ -978,7 +989,15 @@ func (ng *Engine) populateSeries(ctx context.Context, querier storage.Querier, s
evalRange = n.Range evalRange = n.Range
} }
return nil return nil
}) }, ng.NodeReplacer)
if err != nil {
panic(err)
}
if nTyped, ok := n.(parser.Expr); ok {
s.Expr = nTyped
}
} }
// extractFuncFromPath walks up the path and searches for the first instance of // extractFuncFromPath walks up the path and searches for the first instance of
@ -3600,7 +3619,7 @@ func setOffsetForAtModifier(evalTime int64, expr parser.Expr) {
return originalOffset + offsetDiff return originalOffset + offsetDiff
} }
parser.Inspect(expr, func(node parser.Node, path []parser.Node) error { parser.Inspect(context.TODO(), &parser.EvalStmt{Expr: expr}, func(node parser.Node, path []parser.Node) error {
switch n := node.(type) { switch n := node.(type) {
case *parser.VectorSelector: case *parser.VectorSelector:
n.Offset = getOffset(n.Timestamp, n.OriginalOffset, path) n.Offset = getOffset(n.Timestamp, n.OriginalOffset, path)
@ -3613,7 +3632,7 @@ func setOffsetForAtModifier(evalTime int64, expr parser.Expr) {
n.Offset = getOffset(n.Timestamp, n.OriginalOffset, path) n.Offset = getOffset(n.Timestamp, n.OriginalOffset, path)
} }
return nil return nil
}) }, nil)
} }
// detectHistogramStatsDecoding modifies the expression by setting the // detectHistogramStatsDecoding modifies the expression by setting the
@ -3622,7 +3641,7 @@ func setOffsetForAtModifier(evalTime int64, expr parser.Expr) {
// and buckets. The function can be treated as an optimization and is not // and buckets. The function can be treated as an optimization and is not
// required for correctness. // required for correctness.
func detectHistogramStatsDecoding(expr parser.Expr) { func detectHistogramStatsDecoding(expr parser.Expr) {
parser.Inspect(expr, func(node parser.Node, path []parser.Node) error { parser.Inspect(context.TODO(), &parser.EvalStmt{Expr: expr}, func(node parser.Node, path []parser.Node) error {
if n, ok := node.(*parser.BinaryExpr); ok { if n, ok := node.(*parser.BinaryExpr); ok {
detectHistogramStatsDecoding(n.LHS) detectHistogramStatsDecoding(n.LHS)
detectHistogramStatsDecoding(n.RHS) detectHistogramStatsDecoding(n.RHS)
@ -3649,7 +3668,7 @@ func detectHistogramStatsDecoding(expr parser.Expr) {
} }
} }
return fmt.Errorf("stop") return fmt.Errorf("stop")
}) }, nil)
} }
func makeInt64Pointer(val int64) *int64 { func makeInt64Pointer(val int64) *int64 {

View file

@ -83,7 +83,7 @@ loop:
func (ev *evaluator) infoSelectHints(expr parser.Expr) storage.SelectHints { func (ev *evaluator) infoSelectHints(expr parser.Expr) storage.SelectHints {
var nodeTimestamp *int64 var nodeTimestamp *int64
var offset int64 var offset int64
parser.Inspect(expr, func(node parser.Node, path []parser.Node) error { parser.Inspect(context.TODO(), &parser.EvalStmt{Expr: expr}, func(node parser.Node, path []parser.Node) error {
switch n := node.(type) { switch n := node.(type) {
case *parser.VectorSelector: case *parser.VectorSelector:
if n.Timestamp != nil { if n.Timestamp != nil {
@ -94,7 +94,7 @@ func (ev *evaluator) infoSelectHints(expr parser.Expr) storage.SelectHints {
default: default:
return nil return nil
} }
}) }, nil)
start := ev.startTimestamp start := ev.startTimestamp
end := ev.endTimestamp end := ev.endTimestamp

View file

@ -313,32 +313,53 @@ type Visitor interface {
// invoked recursively with visitor w for each of the non-nil children of node, // invoked recursively with visitor w for each of the non-nil children of node,
// followed by a call of w.Visit(nil), returning an error // followed by a call of w.Visit(nil), returning an error
// As the tree is descended the path of previous nodes is provided. // As the tree is descended the path of previous nodes is provided.
func Walk(v Visitor, node Node, path []Node) error { func Walk(ctx context.Context, v Visitor, s *EvalStmt, node Node, path []Node, nr NodeReplacer) (Node, error) {
// Check if the context is closed already
select {
case <-ctx.Done():
return nil, ctx.Err()
default:
}
if nr != nil {
replacement, err := nr(ctx, s, node)
if replacement != nil {
node = replacement
}
if err != nil {
return node, err
}
}
var err error var err error
if v, err = v.Visit(node, path); v == nil || err != nil { if v, err = v.Visit(node, path); v == nil || err != nil {
return err return node, err
} }
path = append(path, node) path = append(path, node)
for _, e := range Children(node) { // TODO: parallel execution of children
if err := Walk(v, e, path); err != nil { for i, e := range Children(node) {
return err if childNode, err := Walk(ctx, v, s, e, path, nr); err != nil {
return node, err
} else {
SetChild(node, i, childNode)
} }
} }
_, err = v.Visit(nil, nil) _, err = v.Visit(nil, nil)
return err return node, err
} }
func ExtractSelectors(expr Expr) [][]*labels.Matcher { func ExtractSelectors(expr Expr) [][]*labels.Matcher {
var selectors [][]*labels.Matcher var selectors [][]*labels.Matcher
Inspect(expr, func(node Node, _ []Node) error { Inspect(context.TODO(), &EvalStmt{Expr: expr}, func(node Node, _ []Node) error {
vs, ok := node.(*VectorSelector) vs, ok := node.(*VectorSelector)
if ok { if ok {
selectors = append(selectors, vs.LabelMatchers) selectors = append(selectors, vs.LabelMatchers)
} }
return nil return nil
}) }, nil)
return selectors return selectors
} }
@ -355,8 +376,52 @@ func (f inspector) Visit(node Node, path []Node) (Visitor, error) {
// Inspect traverses an AST in depth-first order: It starts by calling // Inspect traverses an AST in depth-first order: It starts by calling
// f(node, path); node must not be nil. If f returns a nil error, Inspect invokes f // f(node, path); node must not be nil. If f returns a nil error, Inspect invokes f
// for all the non-nil children of node, recursively. // for all the non-nil children of node, recursively.
func Inspect(node Node, f inspector) { func Inspect(ctx context.Context, s *EvalStmt, f inspector, nr NodeReplacer) (Node, error) {
Walk(f, node, nil) //nolint:errcheck //nolint: errcheck
return Walk(ctx, inspector(f), s, s.Expr, nil, nr)
}
func SetChild(node Node, i int, child Node) {
// For some reasons these switches have significantly better performance than interfaces
switch n := node.(type) {
case *EvalStmt:
n.Expr = child.(Expr)
case Expressions:
n[i] = child.(Expr)
case *AggregateExpr:
// While this does not look nice, it should avoid unnecessary allocations
// caused by slice resizing
if n.Expr == nil && n.Param == nil {
} else if n.Expr == nil {
n.Param = child.(Expr)
} else if n.Param == nil {
n.Expr = child.(Expr)
} else {
switch i {
case 0:
n.Expr = child.(Expr)
case 1:
n.Param = child.(Expr)
}
}
case *BinaryExpr:
switch i {
case 0:
n.LHS = child.(Expr)
case 1:
n.RHS = child.(Expr)
}
case *Call:
n.Args[i] = child.(Expr)
case *SubqueryExpr:
n.Expr = child.(Expr)
case *ParenExpr:
n.Expr = child.(Expr)
case *UnaryExpr:
n.Expr = child.(Expr)
case *MatrixSelector:
case *NumberLiteral, *StringLiteral, *VectorSelector:
}
} }
// Children returns a list of all child nodes of a syntax tree node. // Children returns a list of all child nodes of a syntax tree node.
@ -494,3 +559,5 @@ func (e *UnaryExpr) PositionRange() posrange.PositionRange {
func (e *VectorSelector) PositionRange() posrange.PositionRange { func (e *VectorSelector) PositionRange() posrange.PositionRange {
return e.PosRange return e.PosRange
} }
type NodeReplacer func(context.Context, *EvalStmt, Node) (Node, error)

View file

@ -996,7 +996,7 @@ func atModifierTestCases(exprStr string, evalTime time.Time) ([]atModifierTestCa
// Setting the @ timestamp for all selectors to be evalTime. // Setting the @ timestamp for all selectors to be evalTime.
// If there is a subquery, then the selectors inside it don't get the @ timestamp. // If there is a subquery, then the selectors inside it don't get the @ timestamp.
// If any selector already has the @ timestamp set, then it is untouched. // If any selector already has the @ timestamp set, then it is untouched.
parser.Inspect(expr, func(node parser.Node, path []parser.Node) error { parser.Inspect(context.TODO(), &parser.EvalStmt{Expr: expr}, func(node parser.Node, path []parser.Node) error {
if hasAtModifier(path) { if hasAtModifier(path) {
// There is a subquery with timestamp in the path, // There is a subquery with timestamp in the path,
// hence don't change any timestamps further. // hence don't change any timestamps further.
@ -1023,7 +1023,7 @@ func atModifierTestCases(exprStr string, evalTime time.Time) ([]atModifierTestCa
containsNonStepInvariant = containsNonStepInvariant || ok containsNonStepInvariant = containsNonStepInvariant || ok
} }
return nil return nil
}) }, nil)
if containsNonStepInvariant { if containsNonStepInvariant {
// Expression contains a function whose result can vary with evaluation // Expression contains a function whose result can vary with evaluation

View file

@ -1064,7 +1064,7 @@ func buildDependencyMap(rules []Rule) dependencyMap {
name := rule.Name() name := rule.Name()
outputs[name] = append(outputs[name], rule) outputs[name] = append(outputs[name], rule)
parser.Inspect(rule.Query(), func(node parser.Node, path []parser.Node) error { parser.Inspect(context.TODO(), &parser.EvalStmt{Expr: rule.Query()}, func(node parser.Node, path []parser.Node) error {
if n, ok := node.(*parser.VectorSelector); ok { if n, ok := node.(*parser.VectorSelector); ok {
// A wildcard metric expression means we cannot reliably determine if this rule depends on any other, // A wildcard metric expression means we cannot reliably determine if this rule depends on any other,
// which means we cannot safely run any rules concurrently. // which means we cannot safely run any rules concurrently.
@ -1083,7 +1083,7 @@ func buildDependencyMap(rules []Rule) dependencyMap {
inputs[n.Name] = append(inputs[n.Name], rule) inputs[n.Name] = append(inputs[n.Name], rule)
} }
return nil return nil
}) }, nil)
} }
if indeterminate { if indeterminate {