Skip to content

Commit

Permalink
enhance: optimize plan parser pool to avoid unnessary recycle (#32869)
Browse files Browse the repository at this point in the history
fix #32868
plan parser takes too much cpu on high qps,this pr try to avoid create
lexer and parser too freequent

Signed-off-by: xiaofanluan <xiaofan.luan@zilliz.com>
  • Loading branch information
xiaofan-luan committed May 11, 2024
1 parent b044e55 commit 36f1ea9
Show file tree
Hide file tree
Showing 4 changed files with 89 additions and 15 deletions.
1 change: 1 addition & 0 deletions go.mod
Original file line number Diff line number Diff line change
Expand Up @@ -137,6 +137,7 @@ require (
github.com/gsterjov/go-libsecret v0.0.0-20161001094733-a6f4afe4910c // indirect
github.com/hashicorp/hcl v1.0.0 // indirect
github.com/ianlancetaylor/cgosymbolizer v0.0.0-20221217025313-27d3c9f66b6a // indirect
github.com/jolestar/go-commons-pool/v2 v2.1.2 // indirect
github.com/jonboulle/clockwork v0.2.2 // indirect
github.com/json-iterator/go v1.1.12 // indirect
github.com/klauspost/asmfmt v1.3.2 // indirect
Expand Down
5 changes: 5 additions & 0 deletions go.sum
Original file line number Diff line number Diff line change
Expand Up @@ -250,6 +250,7 @@ github.com/fogleman/gg v1.2.1-0.20190220221249-0403632d5b90/go.mod h1:R/bRT+9gY/
github.com/fogleman/gg v1.3.0/go.mod h1:R/bRT+9gY/C5z7JzPU0zXsXHKM4/ayA+zqcVNZzPa1k=
github.com/form3tech-oss/jwt-go v3.2.3+incompatible h1:7ZaBxOI7TMoYBfyA3cQHErNNyAWIKUMIwqxEtgHOs5c=
github.com/form3tech-oss/jwt-go v3.2.3+incompatible/go.mod h1:pbq4aXjuKjdthFRnoDwaVPLA+WlJuPGy+QneDUgJi2k=
github.com/fortytw2/leaktest v1.3.0/go.mod h1:jDsjWgpAGjm2CA7WthBh/CdZYEPF31XHquHwclZch5g=
github.com/frankban/quicktest v1.2.2/go.mod h1:Qh/WofXFeiAFII1aEBu529AtJo6Zg2VHscnEsbBnJ20=
github.com/frankban/quicktest v1.7.2/go.mod h1:jaStnuzAqU1AJdCO0l53JDCJrVDKcS03DbaAcR7Ks/o=
github.com/frankban/quicktest v1.10.0/go.mod h1:ui7WezCLWMWxVWr1GETZY3smRy0G4KWq9vcPtJmFl7Y=
Expand Down Expand Up @@ -288,6 +289,7 @@ github.com/go-latex/latex v0.0.0-20210118124228-b3d85cf34e07/go.mod h1:CO1AlKB2C
github.com/go-logfmt/logfmt v0.3.0/go.mod h1:Qt1PoO58o5twSAckw1HlFXLmHsOX5/0LbT9GBnD5lWE=
github.com/go-logfmt/logfmt v0.4.0/go.mod h1:3RMwSq7FuexP4Kalkev3ejPJsZTpXXBr9+V4qmtdjCk=
github.com/go-logfmt/logfmt v0.5.0/go.mod h1:wCYkCAKZfumFQihp8CzCvQ3paCTfi41vtzG1KdI/P7A=
github.com/go-logfmt/logfmt v0.5.1/go.mod h1:WYhtIu8zTZfxdn5+rREduYbwxfcBr/Vr6KEVveWlfTs=
github.com/go-logr/logr v1.2.2/go.mod h1:jdQByPbusPIv2/zmleS9BjJVeZ6kBagPoEUsqbVz/1A=
github.com/go-logr/logr v1.3.0 h1:2y3SDp0ZXuc6/cjLSZ+Q3ir+QB9T/iG5yYRXqsagWSY=
github.com/go-logr/logr v1.3.0/go.mod h1:9T104GzyrTigFIr8wt5mBrctHMim0Nb2HLGrmQ40KvY=
Expand Down Expand Up @@ -488,6 +490,8 @@ github.com/jhump/goprotoc v0.5.0/go.mod h1:VrbvcYrQOrTi3i0Vf+m+oqQWk9l72mjkJCYo7
github.com/jhump/protoreflect v1.11.0/go.mod h1:U7aMIjN0NWq9swDP7xDdoMfRHb35uiuTd3Z9nFXJf5E=
github.com/jhump/protoreflect v1.12.0/go.mod h1:JytZfP5d0r8pVNLZvai7U/MCuTWITgrI4tTg7puQFKI=
github.com/jmespath/go-jmespath v0.3.0/go.mod h1:9QtRXoHjLGCJ5IBSaohpXITPlowMeeYCZ7fLUTSywik=
github.com/jolestar/go-commons-pool/v2 v2.1.2 h1:E+XGo58F23t7HtZiC/W6jzO2Ux2IccSH/yx4nD+J1CM=
github.com/jolestar/go-commons-pool/v2 v2.1.2/go.mod h1:r4NYccrkS5UqP1YQI1COyTZ9UjPJAAGTUxzcsK1kqhY=
github.com/jonboulle/clockwork v0.1.0/go.mod h1:Ii8DK3G1RaLaWxj9trq07+26W01tbo22gdxWY5EU2bo=
github.com/jonboulle/clockwork v0.2.2 h1:UOGuzwb1PwsrDAObMuhUnj0p5ULPj8V/xJ7Kx9qUBdQ=
github.com/jonboulle/clockwork v0.2.2/go.mod h1:Pkfl5aHPm1nk2H9h0bjmnJD/BcgbGXUBGnn1kMkgxc8=
Expand All @@ -512,6 +516,7 @@ github.com/kataras/iris/v12 v12.1.8/go.mod h1:LMYy4VlP67TQ3Zgriz8RE2h2kMZV2SgMYb
github.com/kataras/neffos v0.0.14/go.mod h1:8lqADm8PnbeFfL7CLXh1WHw53dG27MC3pgi2R1rmoTE=
github.com/kataras/pio v0.0.2/go.mod h1:hAoW0t9UmXi4R5Oyq5Z4irTbaTsOemSrDGUtaTl7Dro=
github.com/kataras/sitemap v0.0.5/go.mod h1:KY2eugMKiPwsJgx7+U103YZehfvNGOXURubcGyk0Bz8=
github.com/keybase/go-keychain v0.0.0-20190712205309-48d3d31d256d/go.mod h1:JJNrCn9otv/2QP4D7SMJBgaleKpOf66PnW6F5WGNRIc=
github.com/kisielk/errcheck v1.1.0/go.mod h1:EZBBE59ingxPouuu3KfxchcWSUPOHkagtvWXihfKN4Q=
github.com/kisielk/errcheck v1.2.0/go.mod h1:/BMXB+zMLi60iA8Vv6Ksmxu/1UDYcXs4uQLJ+jE2L00=
github.com/kisielk/errcheck v1.5.0/go.mod h1:pFxgyoBC7bSaBwPgfKdkLd5X25qrDl4LWUI2bnpBCr8=
Expand Down
79 changes: 65 additions & 14 deletions internal/parser/planparserv2/pool.go
Original file line number Diff line number Diff line change
@@ -1,28 +1,50 @@
package planparserv2

import (
"sync"
"context"

"github.com/antlr/antlr4/runtime/Go/antlr"
pool "github.com/jolestar/go-commons-pool/v2"

antlrparser "github.com/milvus-io/milvus/internal/parser/planparserv2/generated"
"github.com/milvus-io/milvus/pkg/util/hardware"
)

var (
lexerPool = sync.Pool{
New: func() interface{} {
return antlrparser.NewPlanLexer(nil)
},
}
parserPool = sync.Pool{
New: func() interface{} {
return antlrparser.NewPlanParser(nil)
},
config = &pool.ObjectPoolConfig{
LIFO: pool.DefaultLIFO,
MaxTotal: hardware.GetCPUNum() * 8,
MaxIdle: hardware.GetCPUNum() * 8,
MinIdle: pool.DefaultMinIdle,
MinEvictableIdleTime: pool.DefaultMinEvictableIdleTime,
SoftMinEvictableIdleTime: pool.DefaultSoftMinEvictableIdleTime,
NumTestsPerEvictionRun: pool.DefaultNumTestsPerEvictionRun,
EvictionPolicyName: pool.DefaultEvictionPolicyName,
EvictionContext: context.Background(),
TestOnCreate: pool.DefaultTestOnCreate,
TestOnBorrow: pool.DefaultTestOnBorrow,
TestOnReturn: pool.DefaultTestOnReturn,
TestWhileIdle: pool.DefaultTestWhileIdle,
TimeBetweenEvictionRuns: pool.DefaultTimeBetweenEvictionRuns,
BlockWhenExhausted: false,
}
ctx = context.Background()
lexerPoolFactory = pool.NewPooledObjectFactorySimple(
func(context.Context) (interface{}, error) {
return antlrparser.NewPlanLexer(nil), nil
})
lexerPool = pool.NewObjectPool(ctx, lexerPoolFactory, config)

parserPoolFactory = pool.NewPooledObjectFactorySimple(
func(context.Context) (interface{}, error) {
return antlrparser.NewPlanParser(nil), nil
})
parserPool = pool.NewObjectPool(ctx, parserPoolFactory, config)
)

func getLexer(stream *antlr.InputStream, listeners ...antlr.ErrorListener) *antlrparser.PlanLexer {
lexer, ok := lexerPool.Get().(*antlrparser.PlanLexer)
cached, _ := lexerPool.BorrowObject(context.Background())
lexer, ok := cached.(*antlrparser.PlanLexer)
if !ok {
lexer = antlrparser.NewPlanLexer(nil)
}
Expand All @@ -35,7 +57,8 @@ func getLexer(stream *antlr.InputStream, listeners ...antlr.ErrorListener) *antl

func getParser(lexer *antlrparser.PlanLexer, listeners ...antlr.ErrorListener) *antlrparser.PlanParser {
tokenStream := antlr.NewCommonTokenStream(lexer, antlr.TokenDefaultChannel)
parser, ok := parserPool.Get().(*antlrparser.PlanParser)
cached, _ := parserPool.BorrowObject(context.Background())
parser, ok := cached.(*antlrparser.PlanParser)
if !ok {
parser = antlrparser.NewPlanParser(nil)
}
Expand All @@ -49,10 +72,38 @@ func getParser(lexer *antlrparser.PlanLexer, listeners ...antlr.ErrorListener) *

func putLexer(lexer *antlrparser.PlanLexer) {
lexer.SetInputStream(nil)
lexerPool.Put(lexer)
lexerPool.ReturnObject(context.TODO(), lexer)
}

func putParser(parser *antlrparser.PlanParser) {
parser.SetInputStream(nil)
parserPool.Put(parser)
parserPool.ReturnObject(context.TODO(), parser)
}

func getLexerPool() *pool.ObjectPool {
return lexerPool
}

// only for test
func resetLexerPool() {
ctx = context.Background()
lexerPoolFactory = pool.NewPooledObjectFactorySimple(
func(context.Context) (interface{}, error) {
return antlrparser.NewPlanLexer(nil), nil
})
lexerPool = pool.NewObjectPool(ctx, lexerPoolFactory, config)
}

func getParserPool() *pool.ObjectPool {
return parserPool
}

// only for test
func resetParserPool() {
ctx = context.Background()
parserPoolFactory = pool.NewPooledObjectFactorySimple(
func(context.Context) (interface{}, error) {
return antlrparser.NewPlanParser(nil), nil
})
parserPool = pool.NewObjectPool(ctx, parserPoolFactory, config)
}
19 changes: 18 additions & 1 deletion internal/parser/planparserv2/pool_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -15,18 +15,27 @@ func genNaiveInputStream() *antlr.InputStream {

func Test_getLexer(t *testing.T) {
var lexer *antlrparser.PlanLexer

resetLexerPool()
lexer = getLexer(genNaiveInputStream(), &errorListener{})
assert.NotNil(t, lexer)

lexer = getLexer(genNaiveInputStream(), &errorListener{})
assert.NotNil(t, lexer)

pool := getLexerPool()
assert.Equal(t, pool.GetNumActive(), 2)
assert.Equal(t, pool.GetNumIdle(), 0)

putLexer(lexer)
assert.Equal(t, pool.GetNumActive(), 1)
assert.Equal(t, pool.GetNumIdle(), 1)
}

func Test_getParser(t *testing.T) {
var lexer *antlrparser.PlanLexer
var parser *antlrparser.PlanParser

resetParserPool()
lexer = getLexer(genNaiveInputStream(), &errorListener{})
assert.NotNil(t, lexer)

Expand All @@ -35,4 +44,12 @@ func Test_getParser(t *testing.T) {

parser = getParser(lexer, &errorListener{})
assert.NotNil(t, parser)

pool := getParserPool()
assert.Equal(t, pool.GetNumActive(), 2)
assert.Equal(t, pool.GetNumIdle(), 0)

putParser(parser)
assert.Equal(t, pool.GetNumActive(), 1)
assert.Equal(t, pool.GetNumIdle(), 1)
}

0 comments on commit 36f1ea9

Please sign in to comment.