Skip to content

Commit

Permalink
新增 ExpressionEngineLexer缓存机制,进一步提升性能
Browse files Browse the repository at this point in the history
  • Loading branch information
zhuxiujia committed Jan 20, 2019
1 parent e04ba48 commit 5292f63
Show file tree
Hide file tree
Showing 13 changed files with 252 additions and 26 deletions.
5 changes: 4 additions & 1 deletion ExpressionEngine.go
Original file line number Diff line number Diff line change
Expand Up @@ -8,10 +8,13 @@ type ExpressionEngine interface {
//编译一个表达式
//参数:lexerArg 表达式内容
//返回:interface{} 编译结果,error 错误
Lexer(expression string) (interface{}, error)
Lexer(lexerArg string) (interface{}, error)

//执行一个表达式
//参数:lexerResult=编译结果,arg=参数
//返回:执行结果,错误
Eval(lexerResult interface{}, arg interface{}, operation int) (interface{}, error)

//取Lexer缓存,可不提供。需要提供单例
LexerCache() ExpressionEngineLexerCache
}
24 changes: 17 additions & 7 deletions ExpressionEngineExpr.go
Original file line number Diff line number Diff line change
Expand Up @@ -6,30 +6,31 @@ import (
)

type ExpressionEngineExpr struct {
mapCache *ExpressionEngineLexerMapCache
}


//引擎名称
func (this *ExpressionEngineExpr)Name() string{
func (this *ExpressionEngineExpr) Name() string {
return "ExpressionEngineExpr"
}

//编译一个表达式
//参数:lexerArg 表达式内容
//返回:interface{} 编译结果,error 错误
func (this *ExpressionEngineExpr)Lexer(expression string) (interface{}, error){
func (this *ExpressionEngineExpr) Lexer(expression string) (interface{}, error) {
expression = this.repleaceExpression(expression)
return expr.Parse(expression)
var result, err = expr.Parse(expression)
return result, err
}

//执行一个表达式
//参数:lexerResult=编译结果,arg=参数
//返回:执行结果,错误
func (this *ExpressionEngineExpr)Eval(lexerResult interface{}, arg interface{}, operation int) (interface{}, error){
func (this *ExpressionEngineExpr) Eval(lexerResult interface{}, arg interface{}, operation int) (interface{}, error) {
output, err := expr.Run(lexerResult.(expr.Node), arg)
return output,err
return output, err
}


//替换表达式中的值 and,or,参数 替换为实际值
func (this *ExpressionEngineExpr) repleaceExpression(expression string) string {
if expression == "" {
Expand Down Expand Up @@ -66,3 +67,12 @@ func (this *ExpressionEngineExpr) split(str string) (stringItems []string) {
}
return newStrings
}

//Lexer缓存,可不提供。
func (this *ExpressionEngineExpr) LexerCache() ExpressionEngineLexerCache {
if this.mapCache==nil{
var cache= ExpressionEngineLexerMapCache{}.New()
this.mapCache=&cache
}
return this.mapCache
}
5 changes: 5 additions & 0 deletions ExpressionEngineGovaluate.go
Original file line number Diff line number Diff line change
Expand Up @@ -63,3 +63,8 @@ func (this *ExpressionEngineGovaluate) split(str string) (stringItems []string)
}
return newStrings
}

//Lexer缓存,可不提供。
func (this *ExpressionEngineGovaluate) LexerCache() ExpressionEngineLexerCache{
return nil
}
5 changes: 5 additions & 0 deletions ExpressionEngineJee.go
Original file line number Diff line number Diff line change
Expand Up @@ -116,3 +116,8 @@ func (this *ExpressionEngineJee) LexerAndOrSupport(lexerArg string) string {
}
return lexerArg
}

//Lexer缓存,可不提供。
func (this *ExpressionEngineJee) LexerCache() ExpressionEngineLexerCache{
return nil
}
7 changes: 7 additions & 0 deletions ExpressionEngineLexerCache.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,7 @@
package GoMybatis

//Lexer 结果缓存
type ExpressionEngineLexerCache interface {
Set(expression string,lexer interface{}) error
Get(expression string) (interface{}, error)
}
6 changes: 6 additions & 0 deletions ExpressionEngineLexerCacheable.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,6 @@
package GoMybatis

type ExpressionEngineLexerCacheable interface {
SetUseLexerCache(use bool) error
LexerCacheable() bool
}
27 changes: 27 additions & 0 deletions ExpressionEngineLexerMapCache.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,27 @@
package GoMybatis

import (
"github.com/zhuxiujia/GoMybatis/utils"
)

type ExpressionEngineLexerMapCache struct {
mapCache map[string]interface{}
}

func (this ExpressionEngineLexerMapCache) New() ExpressionEngineLexerMapCache {
if this.mapCache == nil {
this.mapCache = make(map[string]interface{})
}
return this
}

func (this *ExpressionEngineLexerMapCache) Set(expression string, lexer interface{}) error {
if expression == "" {
return utils.NewError("ExpressionEngineLexerMapCache", "set lexerMap chache key can not be ''!")
}
this.mapCache[expression] = lexer
return nil
}
func (this *ExpressionEngineLexerMapCache) Get(expression string) (interface{}, error) {
return this.mapCache[expression], nil
}
27 changes: 27 additions & 0 deletions ExpressionEngineLexerMapCache_test.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,27 @@
package GoMybatis

import (
"fmt"
"testing"
)

func TestExpressionEngineLexerMapCache_Get(t *testing.T) {
engine := ExpressionEngineLexerMapCache{}.New()
err := engine.Set("foo", 1)
if err != nil {
t.Fatal(err)
}
}

func TestExpressionEngineLexerMapCache_Set(t *testing.T) {
engine := ExpressionEngineLexerMapCache{}.New()
err := engine.Set("foo", 1)
if err != nil {
t.Fatal(err)
}
result, err := engine.Get("foo")
if err != nil {
t.Fatal(err)
}
fmt.Println(result)
}
74 changes: 74 additions & 0 deletions ExpressionEngineProxy.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,74 @@
package GoMybatis

import "github.com/zhuxiujia/GoMybatis/utils"

type ExpressionEngineProxy struct {
expressionEngine ExpressionEngine
lexerCacheable bool //是否使用lexer缓存,默认false
}

//engine :表达式引擎,useLexerCache:是否缓存Lexer表达式编译结果
func (ExpressionEngineProxy) New(engine ExpressionEngine, useLexerCache bool) ExpressionEngineProxy {
return ExpressionEngineProxy{
expressionEngine: engine,
lexerCacheable: useLexerCache,
}
}

//引擎名称
func (this ExpressionEngineProxy) Name() string {
if this.expressionEngine == nil {
return ""
}
return this.expressionEngine.Name()
}

//编译一个表达式
//参数:lexerArg 表达式内容
//返回:interface{} 编译结果,error 错误
func (this *ExpressionEngineProxy) Lexer(expression string) (interface{}, error) {
if this.expressionEngine == nil {
return nil, utils.NewError("ExpressionEngineProxy", "ExpressionEngineProxy not init for ExpressionEngineProxy{}.New(...)")
}
if this.expressionEngine.LexerCache() != nil && this.lexerCacheable {
//如果 提供缓存,则使用缓存
cacheResult, cacheErr := this.expressionEngine.LexerCache().Get(expression)
if cacheErr != nil {
return nil, cacheErr
}
if cacheResult != nil {
return cacheResult, nil
}
}
var result, err = this.expressionEngine.Lexer(expression)
if this.expressionEngine.LexerCache() != nil && this.lexerCacheable {
//如果 提供缓存,则使用缓存
this.expressionEngine.LexerCache().Set(expression, result)
}
return result, err
}

//执行一个表达式
//参数:lexerResult=编译结果,arg=参数
//返回:执行结果,错误
func (this *ExpressionEngineProxy) Eval(lexerResult interface{}, arg interface{}, operation int) (interface{}, error) {
if this.expressionEngine == nil {
return nil, utils.NewError("ExpressionEngineProxy", "ExpressionEngineProxy not init for ExpressionEngineProxy{}.New(...)")
}
return this.expressionEngine.Eval(lexerResult, arg, operation)
}

func (this *ExpressionEngineProxy) LexerCache() ExpressionEngineLexerCache {
if this.expressionEngine == nil {
return nil
}
return this.expressionEngine.LexerCache()
}

func (this *ExpressionEngineProxy) SetUseLexerCache(isUseCache bool) error {
this.lexerCacheable = isUseCache
return nil
}
func (this *ExpressionEngineProxy) LexerCacheable() bool {
return this.lexerCacheable
}
62 changes: 62 additions & 0 deletions ExpressionEngineProxy_test.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,62 @@
package GoMybatis

import (
"fmt"
"github.com/zhuxiujia/GoMybatis/example"
"testing"
)

func TestExpressionEngineProxy_Eval(t *testing.T) {
var engine=ExpressionEngineProxy{}.New(&ExpressionEngineExpr{},false)
var lexer,err=engine.Lexer("foo")
if err!= nil{
t.Fatal(err)
}
var arg=make(map[string]interface{})
arg["foo"]="Bar"
result,err:=engine.Eval(lexer,arg,0)
if err!= nil{
t.Fatal(err)
}
if result.(string) != "Bar"{
t.Fatal("result != 'Bar'")
}
fmt.Println(result)
}

func TestExpressionEngineProxy_Lexer(t *testing.T) {
var engine=ExpressionEngineProxy{}.New(&ExpressionEngineExpr{},false)
var _,err=engine.Lexer("foo")
if err!= nil{
t.Fatal(err)
}
}

func BenchmarkExpressionEngineProxy_Eval(b *testing.B) {
b.StopTimer()
var activity = example.Activity{
Id: "1",
DeleteFlag: 1,
}

var engine = ExpressionEngineProxy{}.New(&ExpressionEngineExpr{},false)
var evaluateParameters = make(map[string]interface{})

evaluateParameters["activity"] = &activity

b.StartTimer()
for i := 0; i < b.N; i++ {
var expression = "activity.DeleteFlag == 1 and activity.DeleteFlag != 0 "
evalExpression, err := engine.Lexer(expression)
if err != nil {
b.Fatal(err)
}
result, err := engine.Eval(evalExpression, evaluateParameters, 0)
if err != nil {
b.Fatal(err)
}
if result.(bool) {

}
}
}
4 changes: 2 additions & 2 deletions GoMybatis.go
Original file line number Diff line number Diff line change
Expand Up @@ -19,7 +19,7 @@ func WriteMapperByEngine(value reflect.Value, xml []byte, sessionEngine *Session
if DefaultSessionFactory == nil {
DefaultSessionFactory = &factory
}
WriteMapper(value, xml, DefaultSessionFactory, GoMybatisSqlResultDecoder{}, GoMybatisSqlBuilder{}.New(GoMybatisExpressionTypeConvert{}, GoMybatisSqlArgTypeConvert{}, &ExpressionEngineExpr{}), enableLog)
WriteMapper(value, xml, DefaultSessionFactory, GoMybatisSqlResultDecoder{}, GoMybatisSqlBuilder{}.New(GoMybatisExpressionTypeConvert{}, GoMybatisSqlArgTypeConvert{}, ExpressionEngineProxy{}.New(&ExpressionEngineExpr{},true)), enableLog)
}

//根据sessionEngine写入到mapperPtr
Expand Down Expand Up @@ -100,7 +100,7 @@ func beanCheck(value reflect.Value,builder SqlBuilder) {
var customLen = 0
for argIndex := 0; argIndex < fieldItem.Type.NumIn(); argIndex++ {
var inType = fieldItem.Type.In(argIndex)
if builder.ExpressionEngine().Name()=="ExpressionEngineGovaluate" && inType.Kind() == reflect.Ptr && inType.String() != GoMybatis_Session_Ptr {
if builder.ExpressionEngineProxy().Name()=="ExpressionEngineGovaluate" && inType.Kind() == reflect.Ptr && inType.String() != GoMybatis_Session_Ptr {
panic(`[GoMybats] ` + fieldItem.Name + `() arg = ` + inType.String() + ` can not be a ptr ! must delete '*'!`)
}
if isCustomStruct(inType) {
Expand Down
Loading

0 comments on commit 5292f63

Please sign in to comment.