Skip to content

Commit a4a39e1

Browse files
author
AJ Roetker
committed
Optimize vm a bit by reducing unnecessary calls and allocating include stack
1 parent c254802 commit a4a39e1

File tree

1 file changed

+51
-52
lines changed

1 file changed

+51
-52
lines changed

vm/vm.go

Lines changed: 51 additions & 52 deletions
Original file line numberDiff line numberDiff line change
@@ -13,10 +13,11 @@ import (
1313
u "github.com/araddon/gou"
1414
"github.com/mb0/glob"
1515

16+
"slices"
17+
1618
"github.com/lytics/qlbridge/expr"
1719
"github.com/lytics/qlbridge/lex"
1820
"github.com/lytics/qlbridge/value"
19-
"slices"
2021
)
2122

2223
var (
@@ -42,7 +43,8 @@ type EvalBaseContext struct {
4243
// evaluated against. It may be a simple reader of message/data or any
4344
// object whhich implements EvalContext.
4445
func Eval(ctx expr.EvalContext, arg expr.Node) (value.Value, bool) {
45-
return evalDepth(ctx, arg, 0, make([]string, 0))
46+
// Initialize a visited includes stack of 10
47+
return evalDepth(ctx, arg, 0, make([]string, 0, 10))
4648
}
4749

4850
// creates a new Value with a nil group and given value.
@@ -52,12 +54,10 @@ func numberNodeToValue(t *expr.NumberNode) (value.Value, bool) {
5254
} else if t.IsFloat {
5355
fv, ok := value.StringToFloat64(t.Text)
5456
if !ok {
55-
u.Debugf("Could not perform numeric conversion for %q", t.Text)
5657
return value.NilValueVal, false
5758
}
5859
return value.NewNumberValue(fv), true
5960
}
60-
u.Debugf("Could not find numeric conversion for %#v", t)
6161
return value.NilValueVal, false
6262
}
6363

@@ -66,7 +66,7 @@ func numberNodeToValue(t *expr.NumberNode) (value.Value, bool) {
6666
// InlineIncludes alternative in expr pkg which actually re-writes the expression
6767
// to remove includes and embed the expressions they refer to as part of this expression.
6868
func ResolveIncludes(ctx expr.Includer, arg expr.Node) error {
69-
return resolveIncludesDepth(ctx, arg, 0, make([]string, 0))
69+
return resolveIncludesDepth(ctx, arg, 0, make([]string, 0, 10))
7070
}
7171
func resolveIncludesDepth(ctx expr.Includer, arg expr.Node, depth int, visitedIncludes []string) error {
7272
if depth > MaxDepth {
@@ -137,17 +137,17 @@ func evalDepth(ctx expr.EvalContext, arg expr.Node, depth int, visitedIncludes [
137137
case *expr.NumberNode:
138138
return numberNodeToValue(argVal)
139139
case *expr.BinaryNode:
140-
return walkBinary(ctx, argVal, depth, visitedIncludes)
140+
return evalBinary(ctx, argVal, depth, visitedIncludes)
141141
case *expr.BooleanNode:
142142
return walkBoolean(ctx, argVal, depth, visitedIncludes)
143143
case *expr.UnaryNode:
144-
return walkUnary(ctx, argVal)
144+
return walkUnary(ctx, argVal, depth, visitedIncludes)
145145
case *expr.TriNode:
146-
return walkTernary(ctx, argVal)
146+
return walkTernary(ctx, argVal, depth, visitedIncludes)
147147
case *expr.ArrayNode:
148-
return walkArray(ctx, argVal)
148+
return walkArray(ctx, argVal, depth, visitedIncludes)
149149
case *expr.FuncNode:
150-
return walkFunc(ctx, argVal)
150+
return walkFunc(ctx, argVal, depth, visitedIncludes)
151151
case *expr.IdentityNode:
152152
return walkIdentity(ctx, argVal)
153153
case *expr.StringNode:
@@ -196,11 +196,9 @@ func resolveInclude(ctx expr.Includer, inc *expr.IncludeNode, depth int, visited
196196
if err == expr.ErrNoIncluder {
197197
return err
198198
}
199-
u.Debugf("Could not find include for filter:%s err=%v", inc.String(), err)
200199
return err
201200
}
202201
if incExpr == nil {
203-
u.Debugf("Includer %T returned a nil filter statement!", inc)
204202
return expr.ErrIncludeNotFound
205203
}
206204
if err = resolveIncludesDepth(ctx, incExpr, depth+1, visitedIncludes); err != nil {
@@ -355,13 +353,6 @@ func walkBoolean(ctx expr.EvalContext, n *expr.BooleanNode, depth int, visitedIn
355353
// x OR y
356354
// x > y
357355
// x < =
358-
func walkBinary(ctx expr.EvalContext, node *expr.BinaryNode, depth int, visitedIncludes []string) (value.Value, bool) {
359-
val, ok := evalBinary(ctx, node, depth, visitedIncludes)
360-
if !ok {
361-
return nil, ok
362-
}
363-
return val, ok
364-
}
365356
func evalBinary(ctx expr.EvalContext, node *expr.BinaryNode, depth int, visitedIncludes []string) (value.Value, bool) {
366357
ar, aok := evalDepth(ctx, node.Args[0], depth+1, visitedIncludes)
367358
br, bok := evalDepth(ctx, node.Args[1], depth+1, visitedIncludes)
@@ -444,7 +435,6 @@ func evalBinary(ctx expr.EvalContext, node *expr.BinaryNode, depth int, visitedI
444435
}
445436
return value.NewBoolValue(false), true
446437
default:
447-
u.Debugf("unsupported op for SliceValue op:%v rhT:%T", node.Operator, br)
448438
return nil, false
449439
}
450440
case nil, value.NilValue:
@@ -477,7 +467,6 @@ func evalBinary(ctx expr.EvalContext, node *expr.BinaryNode, depth int, visitedI
477467
return value.BoolValueTrue, true
478468
}
479469
default:
480-
u.Debugf("Could not coerce to number: T:%T v:%v", val, val)
481470
}
482471
}
483472
return value.BoolValueFalse, true
@@ -548,7 +537,6 @@ func evalBinary(ctx expr.EvalContext, node *expr.BinaryNode, depth int, visitedI
548537
}
549538
return value.NewBoolValue(true), true
550539
default:
551-
u.Debugf("unsupported op: %v", node.Operator)
552540
return nil, false
553541
}
554542
case value.Slice:
@@ -576,7 +564,6 @@ func evalBinary(ctx expr.EvalContext, node *expr.BinaryNode, depth int, visitedI
576564
}
577565
return value.NewBoolValue(false), true
578566
default:
579-
u.Debugf("unsupported op for SliceValue op:%v rhT:%T", node.Operator, br)
580567
return nil, false
581568
}
582569
case value.BoolValue:
@@ -587,7 +574,6 @@ func evalBinary(ctx expr.EvalContext, node *expr.BinaryNode, depth int, visitedI
587574
case lex.TokenNE:
588575
return value.NewBoolValue(value.BoolStringVal(at.Val()) != bt.Val()), true
589576
default:
590-
u.Debugf("unsupported op: %v", node.Operator)
591577
}
592578
}
593579
switch node.Operator.T {
@@ -596,7 +582,6 @@ func evalBinary(ctx expr.EvalContext, node *expr.BinaryNode, depth int, visitedI
596582
return value.NewBoolValue(false), true
597583
}
598584
// Should we evaluate strings that are non-nil to be = true?
599-
u.Debugf("not handled: boolean %v %T=%v expr: %s", node.Operator, at.Value(), at.Val(), node.String())
600585
return nil, false
601586
case value.Map:
602587
switch node.Operator.T {
@@ -607,7 +592,6 @@ func evalBinary(ctx expr.EvalContext, node *expr.BinaryNode, depth int, visitedI
607592
}
608593
return value.NewBoolValue(false), true
609594
default:
610-
u.Debugf("unsupported op for Map op:%v rhT:%T", node.Operator, br)
611595
return nil, false
612596
}
613597

@@ -786,16 +770,17 @@ func evalBinary(ctx expr.EvalContext, node *expr.BinaryNode, depth int, visitedI
786770
return operateTime(node.Operator.T, lht, rht)
787771

788772
case value.Map:
789-
rhvals := make([]string, 0)
773+
var rhvals []string
790774
switch bv := br.(type) {
791775
case value.StringsValue:
792776
rhvals = bv.Val()
793777
case value.Slice:
794-
for _, arg := range bv.SliceValue() {
795-
rhvals = append(rhvals, arg.ToString())
778+
sliceValue := bv.SliceValue()
779+
rhvals := make([]string, len(sliceValue))
780+
for i, arg := range sliceValue {
781+
rhvals[i] = arg.ToString()
796782
}
797783
default:
798-
u.Debugf("un-handled? %T", bv)
799784
return nil, false
800785
}
801786

@@ -836,7 +821,6 @@ func evalBinary(ctx expr.EvalContext, node *expr.BinaryNode, depth int, visitedI
836821
return nil, false
837822
}
838823
default:
839-
u.Debugf("Unknown op? %T %T %v", ar, at, ar)
840824
return value.NewErrorValue(fmt.Errorf("unsupported left side value: %T in %s", at, node)), false
841825
}
842826

@@ -857,17 +841,16 @@ func walkIdentity(ctx expr.EvalContext, node *expr.IdentityNode) (value.Value, b
857841
return ctx.Get(node.Text)
858842
}
859843

860-
func walkUnary(ctx expr.EvalContext, node *expr.UnaryNode) (value.Value, bool) {
844+
func walkUnary(ctx expr.EvalContext, node *expr.UnaryNode, depth int, visitedIncludes []string) (value.Value, bool) {
861845

862-
a, ok := Eval(ctx, node.Arg)
846+
a, ok := evalDepth(ctx, node.Arg, depth, visitedIncludes)
863847
if !ok {
864848
switch node.Operator.T {
865849
case lex.TokenExists:
866850
return value.NewBoolValue(false), true
867851
case lex.TokenNegate:
868852
return value.NewBoolValue(false), false
869853
}
870-
u.Debugf("unary could not evaluate for[ %s ] and %#v", node.String(), node)
871854
return a, false
872855
}
873856

@@ -879,7 +862,7 @@ func walkUnary(ctx expr.EvalContext, node *expr.UnaryNode) (value.Value, bool) {
879862
case nil, value.NilValue:
880863
return value.NewBoolValue(false), false
881864
default:
882-
u.LogThrottle(u.WARN, 5, "unary type not implemented. Unknonwn node type: %T:%v node=%s", argVal, argVal, node.String())
865+
// u.LogThrottle(u.WARN, 5, "unary type not implemented. Unknonwn node type: %T:%v node=%s", argVal, argVal, node.String())
883866
return value.NewNilValue(), false
884867
}
885868
case lex.TokenMinus:
@@ -905,18 +888,18 @@ func walkUnary(ctx expr.EvalContext, node *expr.UnaryNode) (value.Value, bool) {
905888
// walkTernary ternary evaluator
906889
//
907890
// A BETWEEN B AND C
908-
func walkTernary(ctx expr.EvalContext, node *expr.TriNode) (value.Value, bool) {
891+
func walkTernary(ctx expr.EvalContext, node *expr.TriNode, depth int, visitedIncludes []string) (value.Value, bool) {
909892

910-
a, aok := Eval(ctx, node.Args[0])
911-
b, bok := Eval(ctx, node.Args[1])
912-
c, cok := Eval(ctx, node.Args[2])
913-
if !aok {
893+
a, aok := evalDepth(ctx, node.Args[0], depth, visitedIncludes)
894+
if a == nil || !aok {
914895
return nil, false
915896
}
916-
if !bok || !cok {
897+
b, bok := evalDepth(ctx, node.Args[1], depth, visitedIncludes)
898+
if b == nil || !bok {
917899
return nil, false
918900
}
919-
if a == nil || b == nil || c == nil {
901+
c, cok := evalDepth(ctx, node.Args[2], depth, visitedIncludes)
902+
if c == nil || !cok {
920903
return nil, false
921904
}
922905
switch node.Operator.T {
@@ -944,7 +927,6 @@ func walkTernary(ctx expr.EvalContext, node *expr.TriNode) (value.Value, bool) {
944927
}
945928
return value.NewBoolValue(false), true
946929
case value.NumberValue:
947-
948930
av := at.Val()
949931
bv, ok := value.ValueToFloat64(b)
950932
if !ok {
@@ -966,7 +948,6 @@ func walkTernary(ctx expr.EvalContext, node *expr.TriNode) (value.Value, bool) {
966948
return value.NewBoolValue(false), true
967949

968950
case value.TimeValue:
969-
970951
av := at.Val()
971952
bv, ok := value.ValueToTime(b)
972953
if !ok {
@@ -1000,12 +981,12 @@ func walkTernary(ctx expr.EvalContext, node *expr.TriNode) (value.Value, bool) {
1000981
// walkArray Array evaluator: evaluate multiple values into an array
1001982
//
1002983
// (b,c,d)
1003-
func walkArray(ctx expr.EvalContext, node *expr.ArrayNode) (value.Value, bool) {
984+
func walkArray(ctx expr.EvalContext, node *expr.ArrayNode, depth int, visitedIncludes []string) (value.Value, bool) {
1004985

1005986
vals := make([]value.Value, len(node.Args))
1006987

1007988
for i := range node.Args {
1008-
v, _ := Eval(ctx, node.Args[i])
989+
v, _ := evalDepth(ctx, node.Args[i], depth, visitedIncludes)
1009990
vals[i] = v
1010991
}
1011992

@@ -1014,20 +995,20 @@ func walkArray(ctx expr.EvalContext, node *expr.ArrayNode) (value.Value, bool) {
1014995
}
1015996

1016997
// walkFunc evaluates a function
1017-
func walkFunc(ctx expr.EvalContext, node *expr.FuncNode) (value.Value, bool) {
998+
func walkFunc(ctx expr.EvalContext, node *expr.FuncNode, depth int, visitedIncludes []string) (value.Value, bool) {
1018999

10191000
if node.F.CustomFunc == nil {
10201001
return nil, false
10211002
}
10221003
if node.Eval == nil {
1023-
u.LogThrottle(u.WARN, 10, "No Eval() for %s", node.Name)
1004+
// u.LogThrottle(u.WARN, 10, "No Eval() for %s", node.Name)
10241005
return nil, false
10251006
}
10261007

10271008
args := make([]value.Value, len(node.Args))
10281009

10291010
for i, a := range node.Args {
1030-
v, ok := Eval(ctx, a)
1011+
v, ok := evalDepth(ctx, a, depth, visitedIncludes)
10311012
if !ok {
10321013
v = value.NewNilValue()
10331014
}
@@ -1186,16 +1167,34 @@ func operateTime(op lex.TokenType, lht, rht time.Time) (value.BoolValue, bool) {
11861167
}
11871168
return value.BoolValueFalse, true
11881169
default:
1189-
u.Debugf("unhandled date op %v", op)
11901170
}
11911171
return value.BoolValueFalse, false
11921172
}
11931173

1174+
var globber *glob.Globber
1175+
1176+
func init() {
1177+
defaultConfig := glob.Default()
1178+
defaultConfig.Star = '%'
1179+
var err error
1180+
globber, err = glob.New(defaultConfig)
1181+
if err != nil {
1182+
u.Errorf("failed to create optimized globber: %v", err)
1183+
}
1184+
}
1185+
11941186
// LikeCompare takes two strings and evaluates them for like equality
11951187
func LikeCompare(a, b string) (value.BoolValue, bool) {
11961188
// Do we want to always do this replacement? Or do this at parse time or config?
1197-
b = strings.Replace(b, "%", "*", -1)
1198-
match, err := glob.Match(b, a)
1189+
//
1190+
var match bool
1191+
var err error
1192+
if globber == nil {
1193+
b = strings.Replace(b, "%", "*", -1)
1194+
match, err = glob.Match(b, a)
1195+
} else {
1196+
match, err = globber.Match(b, a)
1197+
}
11991198
if err != nil {
12001199
return value.BoolValueFalse, false
12011200
}

0 commit comments

Comments
 (0)