Skip to content

Commit

Permalink
This is an automated cherry-pick of pingcap#41618
Browse files Browse the repository at this point in the history
Signed-off-by: ti-chi-bot <ti-community-prow-bot@tidb.io>
  • Loading branch information
fzzf678 authored and ti-chi-bot committed Feb 22, 2023
1 parent 2150484 commit 5bcc129
Show file tree
Hide file tree
Showing 9 changed files with 433 additions and 35 deletions.
2 changes: 2 additions & 0 deletions planner/core/BUILD.bazel
Original file line number Diff line number Diff line change
Expand Up @@ -130,6 +130,7 @@ go_library(
"//util/mock",
"//util/paging",
"//util/parser",
"//util/plancache",
"//util/plancodec",
"//util/ranger",
"//util/rowcodec",
Expand Down Expand Up @@ -261,6 +262,7 @@ go_test(
"//util/kvcache",
"//util/logutil",
"//util/mock",
"//util/plancache",
"//util/plancodec",
"//util/ranger",
"//util/set",
Expand Down
51 changes: 51 additions & 0 deletions planner/core/plan_cache.go
Original file line number Diff line number Diff line change
Expand Up @@ -38,6 +38,7 @@ import (
"github.com/pingcap/tidb/util/collate"
"github.com/pingcap/tidb/util/kvcache"
"github.com/pingcap/tidb/util/logutil"
utilpc "github.com/pingcap/tidb/util/plancache"
"github.com/pingcap/tidb/util/ranger"
"go.uber.org/zap"
)
Expand Down Expand Up @@ -151,14 +152,30 @@ func GetPlanFromSessionPlanCache(ctx context.Context, sctx sessionctx.Context,
}
}

<<<<<<< HEAD
paramTypes := parseParamTypes(sctx, params)

if stmtCtx.UseCache && stmtAst.CachedPlan != nil { // for point query plan
if plan, names, ok, err := getPointQueryPlan(stmtAst, sessVars, stmtCtx); ok {
=======
if stmtCtx.UseCache && stmtAst.CachedPlan != nil { // special code path for fast point plan
if plan, names, ok, err := getCachedPointPlan(stmtAst, sessVars, stmtCtx); ok {
return plan, names, err
}
}

matchOpts, err := GetMatchOpts(sctx, stmt.PreparedAst.Stmt, params)
if err != nil {
return nil, nil, err
}
if stmtCtx.UseCache { // for non-point plans
if plan, names, ok, err := getCachedPlan(sctx, isNonPrepared, cacheKey, bindSQL, is, stmt, matchOpts); err != nil || ok {
>>>>>>> 12107e33d3 (planner: refactor plan cache LRU code (#41618))
return plan, names, err
}
}

<<<<<<< HEAD
if stmtCtx.UseCache { // for non-point plans
if plan, names, ok, err := getGeneralPlan(sctx, isGeneralPlanCache, cacheKey, bindSQL, is, stmt,
paramTypes); err != nil || ok {
Expand All @@ -167,6 +184,9 @@ func GetPlanFromSessionPlanCache(ctx context.Context, sctx sessionctx.Context,
}

return generateNewPlan(ctx, sctx, isGeneralPlanCache, is, stmt, cacheKey, latestSchemaVersion, paramTypes, bindSQL)
=======
return generateNewPlan(ctx, sctx, isNonPrepared, is, stmt, cacheKey, latestSchemaVersion, bindSQL, matchOpts)
>>>>>>> 12107e33d3 (planner: refactor plan cache LRU code (#41618))
}

// parseParamTypes get parameters' types in PREPARE statement
Expand Down Expand Up @@ -212,13 +232,22 @@ func getPointQueryPlan(stmt *ast.Prepared, sessVars *variable.SessionVars, stmtC
return plan, names, true, nil
}

<<<<<<< HEAD
func getGeneralPlan(sctx sessionctx.Context, isGeneralPlanCache bool, cacheKey kvcache.Key, bindSQL string,
is infoschema.InfoSchema, stmt *PlanCacheStmt, paramTypes []*types.FieldType) (Plan,
=======
func getCachedPlan(sctx sessionctx.Context, isNonPrepared bool, cacheKey kvcache.Key, bindSQL string,
is infoschema.InfoSchema, stmt *PlanCacheStmt, matchOpts *utilpc.PlanCacheMatchOpts) (Plan,
>>>>>>> 12107e33d3 (planner: refactor plan cache LRU code (#41618))
[]*types.FieldName, bool, error) {
sessVars := sctx.GetSessionVars()
stmtCtx := sessVars.StmtCtx

<<<<<<< HEAD
candidate, exist := sctx.GetPlanCache(isGeneralPlanCache).Get(cacheKey, paramTypes)
=======
candidate, exist := sctx.GetPlanCache(isNonPrepared).Get(cacheKey, matchOpts)
>>>>>>> 12107e33d3 (planner: refactor plan cache LRU code (#41618))
if !exist {
return nil, nil, false, nil
}
Expand Down Expand Up @@ -256,9 +285,15 @@ func getGeneralPlan(sctx sessionctx.Context, isGeneralPlanCache bool, cacheKey k

// generateNewPlan call the optimizer to generate a new plan for current statement
// and try to add it to cache
<<<<<<< HEAD
func generateNewPlan(ctx context.Context, sctx sessionctx.Context, isGeneralPlanCache bool, is infoschema.InfoSchema,
stmt *PlanCacheStmt, cacheKey kvcache.Key, latestSchemaVersion int64, paramTypes []*types.FieldType,
bindSQL string) (Plan, []*types.FieldName, error) {
=======
func generateNewPlan(ctx context.Context, sctx sessionctx.Context, isNonPrepared bool, is infoschema.InfoSchema,
stmt *PlanCacheStmt, cacheKey kvcache.Key, latestSchemaVersion int64, bindSQL string,
matchOpts *utilpc.PlanCacheMatchOpts) (Plan, []*types.FieldName, error) {
>>>>>>> 12107e33d3 (planner: refactor plan cache LRU code (#41618))
stmtAst := stmt.PreparedAst
sessVars := sctx.GetSessionVars()
stmtCtx := sessVars.StmtCtx
Expand All @@ -276,7 +311,15 @@ func generateNewPlan(ctx context.Context, sctx sessionctx.Context, isGeneralPlan
}

// check whether this plan is cacheable.
<<<<<<< HEAD
checkPlanCacheability(sctx, p, len(paramTypes))
=======
if stmtCtx.UseCache {
if cacheable, reason := isPlanCacheable(sctx, p, len(matchOpts.ParamTypes), len(matchOpts.LimitOffsetAndCount)); !cacheable {
stmtCtx.SetSkipPlanCache(errors.Errorf(reason))
}
}
>>>>>>> 12107e33d3 (planner: refactor plan cache LRU code (#41618))

// put this plan into the plan cache.
if stmtCtx.UseCache {
Expand All @@ -289,11 +332,19 @@ func generateNewPlan(ctx context.Context, sctx sessionctx.Context, isGeneralPlan
}
sessVars.IsolationReadEngines[kv.TiFlash] = struct{}{}
}
<<<<<<< HEAD
cached := NewPlanCacheValue(p, names, stmtCtx.TblInfo2UnionScan, paramTypes)
stmt.NormalizedPlan, stmt.PlanDigest = NormalizePlan(p)
stmtCtx.SetPlan(p)
stmtCtx.SetPlanDigest(stmt.NormalizedPlan, stmt.PlanDigest)
sctx.GetPlanCache(isGeneralPlanCache).Put(cacheKey, cached, paramTypes)
=======
cached := NewPlanCacheValue(p, names, stmtCtx.TblInfo2UnionScan, matchOpts)
stmt.NormalizedPlan, stmt.PlanDigest = NormalizePlan(p)
stmtCtx.SetPlan(p)
stmtCtx.SetPlanDigest(stmt.NormalizedPlan, stmt.PlanDigest)
sctx.GetPlanCache(isNonPrepared).Put(cacheKey, cached, matchOpts)
>>>>>>> 12107e33d3 (planner: refactor plan cache LRU code (#41618))
}
sessVars.FoundInPlanCache = false
return p, names, err
Expand Down
40 changes: 39 additions & 1 deletion planner/core/plan_cache_lru.go
Original file line number Diff line number Diff line change
Expand Up @@ -20,11 +20,11 @@ import (
"github.com/pingcap/errors"
"github.com/pingcap/tidb/metrics"
"github.com/pingcap/tidb/sessionctx"
"github.com/pingcap/tidb/types"
"github.com/pingcap/tidb/util/hack"
"github.com/pingcap/tidb/util/kvcache"
"github.com/pingcap/tidb/util/logutil"
"github.com/pingcap/tidb/util/memory"
utilpc "github.com/pingcap/tidb/util/plancache"
)

// planCacheEntry wraps Key and Value. It's the value of list.Element.
Expand Down Expand Up @@ -94,13 +94,21 @@ func strHashKey(key kvcache.Key, deepCopy bool) string {
}

// Get tries to find the corresponding value according to the given key.
<<<<<<< HEAD
func (l *LRUPlanCache) Get(key kvcache.Key, paramTypes []*types.FieldType) (value kvcache.Value, ok bool) {
=======
func (l *LRUPlanCache) Get(key kvcache.Key, opts *utilpc.PlanCacheMatchOpts) (value kvcache.Value, ok bool) {
>>>>>>> 12107e33d3 (planner: refactor plan cache LRU code (#41618))
l.lock.Lock()
defer l.lock.Unlock()

bucket, bucketExist := l.buckets[strHashKey(key, false)]
if bucketExist {
<<<<<<< HEAD
if element, exist := l.pickFromBucket(bucket, paramTypes); exist {
=======
if element, exist := l.pickFromBucket(bucket, opts); exist {
>>>>>>> 12107e33d3 (planner: refactor plan cache LRU code (#41618))
l.lruList.MoveToFront(element)
return element.Value.(*planCacheEntry).PlanValue, true
}
Expand All @@ -109,14 +117,22 @@ func (l *LRUPlanCache) Get(key kvcache.Key, paramTypes []*types.FieldType) (valu
}

// Put puts the (key, value) pair into the LRU Cache.
<<<<<<< HEAD
func (l *LRUPlanCache) Put(key kvcache.Key, value kvcache.Value, paramTypes []*types.FieldType) {
=======
func (l *LRUPlanCache) Put(key kvcache.Key, value kvcache.Value, opts *utilpc.PlanCacheMatchOpts) {
>>>>>>> 12107e33d3 (planner: refactor plan cache LRU code (#41618))
l.lock.Lock()
defer l.lock.Unlock()

hash := strHashKey(key, true)
bucket, bucketExist := l.buckets[hash]
if bucketExist {
<<<<<<< HEAD
if element, exist := l.pickFromBucket(bucket, paramTypes); exist {
=======
if element, exist := l.pickFromBucket(bucket, opts); exist {
>>>>>>> 12107e33d3 (planner: refactor plan cache LRU code (#41618))
l.updateInstanceMetric(&planCacheEntry{PlanKey: key, PlanValue: value}, element.Value.(*planCacheEntry))
element.Value.(*planCacheEntry).PlanValue = value
l.lruList.MoveToFront(element)
Expand Down Expand Up @@ -252,12 +268,34 @@ func (l *LRUPlanCache) memoryControl() {
}

// PickPlanFromBucket pick one plan from bucket
<<<<<<< HEAD
func PickPlanFromBucket(bucket map[*list.Element]struct{}, paramTypes []*types.FieldType) (*list.Element, bool) {
for k := range bucket {
plan := k.Value.(*planCacheEntry).PlanValue.(*PlanCacheValue)
if plan.ParamTypes.CheckTypesCompatibility4PC(paramTypes) {
return k, true
}
=======
func (l *LRUPlanCache) pickFromBucket(bucket map[*list.Element]struct{}, matchOpts *utilpc.PlanCacheMatchOpts) (*list.Element, bool) {
for k := range bucket {
plan := k.Value.(*planCacheEntry).PlanValue.(*PlanCacheValue)
// check param types' compatibility
ok1 := checkTypesCompatibility4PC(plan.matchOpts.ParamTypes, matchOpts.ParamTypes)
if !ok1 {
continue
}

// check limit offset and key if equal and check switch if enabled
ok2 := checkUint64SliceIfEqual(plan.matchOpts.LimitOffsetAndCount, matchOpts.LimitOffsetAndCount)
if !ok2 {
continue
}
if len(plan.matchOpts.LimitOffsetAndCount) > 0 && !l.sctx.GetSessionVars().EnablePlanCacheForParamLimit {
// offset and key slice matched, but it is a plan with param limit and the switch is disabled
continue
}
return k, true
>>>>>>> 12107e33d3 (planner: refactor plan cache LRU code (#41618))
}
return nil, false
}
Expand Down
Loading

0 comments on commit 5bcc129

Please sign in to comment.