Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

planner: refactor a few code of plan cache #54075

Merged
merged 10 commits into from
Jun 18, 2024
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
4 changes: 0 additions & 4 deletions pkg/planner/core/BUILD.bazel
Original file line number Diff line number Diff line change
Expand Up @@ -168,7 +168,6 @@ go_library(
"//pkg/util/mock",
"//pkg/util/paging",
"//pkg/util/parser",
"//pkg/util/plancache",
"//pkg/util/plancodec",
"//pkg/util/ranger",
"//pkg/util/ranger/context",
Expand Down Expand Up @@ -292,12 +291,9 @@ go_test(
"//pkg/util/context",
"//pkg/util/dbterror",
"//pkg/util/dbterror/plannererrors",
"//pkg/util/hack",
"//pkg/util/hint",
"//pkg/util/kvcache",
"//pkg/util/logutil",
"//pkg/util/mock",
"//pkg/util/plancache",
"//pkg/util/plancodec",
"//pkg/util/ranger",
"//pkg/util/set",
Expand Down
11 changes: 5 additions & 6 deletions pkg/planner/core/plan_cache.go
Original file line number Diff line number Diff line change
Expand Up @@ -37,7 +37,6 @@ import (
contextutil "github.com/pingcap/tidb/pkg/util/context"
"github.com/pingcap/tidb/pkg/util/dbterror/plannererrors"
"github.com/pingcap/tidb/pkg/util/kvcache"
utilpc "github.com/pingcap/tidb/pkg/util/plancache"
)

// PlanCacheKeyTestIssue43667 is only for test.
Expand Down Expand Up @@ -174,7 +173,7 @@ func GetPlanFromSessionPlanCache(ctx context.Context, sctx sessionctx.Context,
return nil, nil, err
}

var cacheKey kvcache.Key
var cacheKey string
sessVars := sctx.GetSessionVars()
stmtCtx := sessVars.StmtCtx
cacheEnabled := false
Expand Down Expand Up @@ -218,7 +217,7 @@ func GetPlanFromSessionPlanCache(ctx context.Context, sctx sessionctx.Context,
}
}

var matchOpts *utilpc.PlanCacheMatchOpts
var matchOpts *PlanCacheMatchOpts
if stmtCtx.UseCache() {
var cacheVal kvcache.Value
var hit, isPointPlan bool
Expand Down Expand Up @@ -247,7 +246,7 @@ func GetPlanFromSessionPlanCache(ctx context.Context, sctx sessionctx.Context,
}

func adjustCachedPlan(sctx sessionctx.Context, cachedVal *PlanCacheValue, isNonPrepared, isPointPlan bool,
cacheKey kvcache.Key, bindSQL string, is infoschema.InfoSchema, stmt *PlanCacheStmt) (base.Plan,
cacheKey string, bindSQL string, is infoschema.InfoSchema, stmt *PlanCacheStmt) (base.Plan,
[]*types.FieldName, bool, error) {
sessVars := sctx.GetSessionVars()
stmtCtx := sessVars.StmtCtx
Expand Down Expand Up @@ -286,8 +285,8 @@ func adjustCachedPlan(sctx sessionctx.Context, cachedVal *PlanCacheValue, isNonP
// generateNewPlan call the optimizer to generate a new plan for current statement
// and try to add it to cache
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) (base.Plan, []*types.FieldName, error) {
stmt *PlanCacheStmt, cacheKey string, latestSchemaVersion int64, bindSQL string,
matchOpts *PlanCacheMatchOpts) (base.Plan, []*types.FieldName, error) {
stmtAst := stmt.PreparedAst
sessVars := sctx.GetSessionVars()
stmtCtx := sessVars.StmtCtx
Expand Down
44 changes: 18 additions & 26 deletions pkg/planner/core/plan_cache_lru.go
Original file line number Diff line number Diff line change
Expand Up @@ -19,17 +19,15 @@ import (
"github.com/pingcap/errors"
core_metrics "github.com/pingcap/tidb/pkg/planner/core/metrics"
"github.com/pingcap/tidb/pkg/sessionctx"
"github.com/pingcap/tidb/pkg/util/hack"
"github.com/pingcap/tidb/pkg/util/kvcache"
"github.com/pingcap/tidb/pkg/util/logutil"
"github.com/pingcap/tidb/pkg/util/memory"
utilpc "github.com/pingcap/tidb/pkg/util/plancache"
"github.com/pingcap/tidb/pkg/util/syncutil"
)

// planCacheEntry wraps Key and Value. It's the value of list.Element.
type planCacheEntry struct {
PlanKey kvcache.Key
PlanKey string
PlanValue kvcache.Value
}

Expand All @@ -39,7 +37,7 @@ func (e *planCacheEntry) MemoryUsage() (sum int64) {
return
}

return e.PlanKey.(*planCacheKey).MemoryUsage() + e.PlanValue.(*PlanCacheValue).MemoryUsage()
return int64(len(e.PlanKey)) + e.PlanValue.(*PlanCacheValue).MemoryUsage()
}

// LRUPlanCache is a dedicated least recently used cache, Only used for plan cache.
Expand All @@ -52,7 +50,7 @@ type LRUPlanCache struct {
// lock make cache thread safe
lock syncutil.RWMutex
// onEvict will be called if any eviction happened, only for test use now
onEvict func(kvcache.Key, kvcache.Value)
onEvict func(string, any)

// 0 indicates no quota
quota uint64
Expand Down Expand Up @@ -80,20 +78,12 @@ func NewLRUPlanCache(capacity uint, guard float64, quota uint64, sctx sessionctx
}
}

// strHashKey control deep or Shallow copy of string
func strHashKey(key kvcache.Key, deepCopy bool) string {
if deepCopy {
return string(key.Hash())
}
return string(hack.String(key.Hash()))
}

// Get tries to find the corresponding value according to the given key.
func (l *LRUPlanCache) Get(key kvcache.Key, opts *utilpc.PlanCacheMatchOpts) (value kvcache.Value, ok bool) {
func (l *LRUPlanCache) Get(key string, opts any) (value any, ok bool) {
l.lock.RLock()
defer l.lock.RUnlock()

bucket, bucketExist := l.buckets[strHashKey(key, false)]
bucket, bucketExist := l.buckets[key]
if bucketExist {
if element, exist := l.pickFromBucket(bucket, opts); exist {
l.lruList.MoveToFront(element)
Expand All @@ -104,12 +94,11 @@ func (l *LRUPlanCache) Get(key kvcache.Key, opts *utilpc.PlanCacheMatchOpts) (va
}

// Put puts the (key, value) pair into the LRU Cache.
func (l *LRUPlanCache) Put(key kvcache.Key, value kvcache.Value, opts *utilpc.PlanCacheMatchOpts) {
func (l *LRUPlanCache) Put(key string, value, opts any) {
l.lock.Lock()
defer l.lock.Unlock()

hash := strHashKey(key, true)
bucket, bucketExist := l.buckets[hash]
bucket, bucketExist := l.buckets[key]
if bucketExist {
if element, exist := l.pickFromBucket(bucket, opts); exist {
l.updateInstanceMetric(&planCacheEntry{PlanKey: key, PlanValue: value}, element.Value.(*planCacheEntry))
Expand All @@ -118,15 +107,15 @@ func (l *LRUPlanCache) Put(key kvcache.Key, value kvcache.Value, opts *utilpc.Pl
return
}
} else {
l.buckets[hash] = make(map[*list.Element]struct{}, 1)
l.buckets[key] = make(map[*list.Element]struct{}, 1)
}

newCacheEntry := &planCacheEntry{
PlanKey: key,
PlanValue: value,
}
element := l.lruList.PushFront(newCacheEntry)
l.buckets[hash][element] = struct{}{}
l.buckets[key][element] = struct{}{}
l.size++
l.updateInstanceMetric(newCacheEntry, nil)
if l.size > l.capacity {
Expand All @@ -136,19 +125,18 @@ func (l *LRUPlanCache) Put(key kvcache.Key, value kvcache.Value, opts *utilpc.Pl
}

// Delete deletes the multi-values from the LRU Cache.
func (l *LRUPlanCache) Delete(key kvcache.Key) {
func (l *LRUPlanCache) Delete(key string) {
l.lock.Lock()
defer l.lock.Unlock()

hash := strHashKey(key, false)
bucket, bucketExist := l.buckets[hash]
bucket, bucketExist := l.buckets[key]
if bucketExist {
for element := range bucket {
l.updateInstanceMetric(nil, element.Value.(*planCacheEntry))
l.lruList.Remove(element)
l.size--
}
delete(l.buckets, hash)
delete(l.buckets, key)
}
}

Expand Down Expand Up @@ -229,7 +217,7 @@ func (l *LRUPlanCache) removeOldest() {

// removeFromBucket remove element from bucket
func (l *LRUPlanCache) removeFromBucket(element *list.Element) {
hash := strHashKey(element.Value.(*planCacheEntry).PlanKey, false)
hash := element.Value.(*planCacheEntry).PlanKey
bucket := l.buckets[hash]
delete(bucket, element)
if len(bucket) == 0 {
Expand All @@ -251,7 +239,11 @@ func (l *LRUPlanCache) memoryControl() {
}

// PickPlanFromBucket pick one plan from bucket
func (l *LRUPlanCache) pickFromBucket(bucket map[*list.Element]struct{}, matchOpts *utilpc.PlanCacheMatchOpts) (*list.Element, bool) {
func (l *LRUPlanCache) pickFromBucket(bucket map[*list.Element]struct{}, opts any) (*list.Element, bool) {
var matchOpts *PlanCacheMatchOpts
if opts != nil {
matchOpts = opts.(*PlanCacheMatchOpts)
}
for k := range bucket {
if matchCachedPlan(l.sctx, k.Value.(*planCacheEntry).PlanValue.(*PlanCacheValue), matchOpts) {
return k, true
Expand Down
Loading