Skip to content

Commit 6f9db8d

Browse files
authored
planner: fix incorrectly using the schema for plan cache (#57964) (#58090)
close #56733
1 parent ce76011 commit 6f9db8d

File tree

3 files changed

+116
-10
lines changed

3 files changed

+116
-10
lines changed

pkg/ddl/tests/metadatalock/BUILD.bazel

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -8,16 +8,18 @@ go_test(
88
"mdl_test.go",
99
],
1010
flaky = True,
11-
shard_count = 36,
11+
shard_count = 37,
1212
deps = [
1313
"//pkg/config",
1414
"//pkg/ddl",
1515
"//pkg/ddl/ingest/testutil",
1616
"//pkg/errno",
17+
"//pkg/meta/model",
1718
"//pkg/server",
1819
"//pkg/testkit",
1920
"//pkg/testkit/testfailpoint",
2021
"//pkg/testkit/testsetup",
22+
"@com_github_pingcap_failpoint//:failpoint",
2123
"@com_github_stretchr_testify//require",
2224
"@org_uber_go_goleak//:goleak",
2325
],

pkg/ddl/tests/metadatalock/mdl_test.go

Lines changed: 101 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -15,13 +15,17 @@
1515
package metadatalocktest
1616

1717
import (
18+
"context"
1819
"fmt"
1920
"sync"
2021
"testing"
2122
"time"
2223

24+
"github.com/pingcap/failpoint"
25+
"github.com/pingcap/tidb/pkg/ddl"
2326
ingesttestutil "github.com/pingcap/tidb/pkg/ddl/ingest/testutil"
2427
mysql "github.com/pingcap/tidb/pkg/errno"
28+
"github.com/pingcap/tidb/pkg/meta/model"
2529
"github.com/pingcap/tidb/pkg/server"
2630
"github.com/pingcap/tidb/pkg/testkit"
2731
"github.com/pingcap/tidb/pkg/testkit/testfailpoint"
@@ -997,6 +1001,103 @@ func TestMDLPreparePlanCacheExecute2(t *testing.T) {
9971001
tk.MustExec("admin check table t")
9981002
}
9991003

1004+
// TestMDLPreparePlanCacheExecuteInsert makes sure the insert statement handle the schema correctly in plan cache.
1005+
func TestMDLPreparePlanCacheExecuteInsert(t *testing.T) {
1006+
store, dom := testkit.CreateMockStoreAndDomain(t)
1007+
defer ingesttestutil.InjectMockBackendMgr(t, store)()
1008+
1009+
sv := server.CreateMockServer(t, store)
1010+
1011+
sv.SetDomain(dom)
1012+
dom.InfoSyncer().SetSessionManager(sv)
1013+
defer sv.Close()
1014+
1015+
conn1 := server.CreateMockConn(t, sv)
1016+
tk := testkit.NewTestKitWithSession(t, store, conn1.Context().Session)
1017+
conn2 := server.CreateMockConn(t, sv)
1018+
tkDDL := testkit.NewTestKitWithSession(t, store, conn2.Context().Session)
1019+
conn3 := server.CreateMockConn(t, sv)
1020+
tk3 := testkit.NewTestKitWithSession(t, store, conn3.Context().Session)
1021+
tk.MustExec("use test")
1022+
tk.MustExec("set global tidb_enable_metadata_lock=1")
1023+
tk.MustExec("create table t(a int primary key, b int);")
1024+
tk.MustExec("create table t2(a int);")
1025+
tk.MustExec("insert into t values(1, 1), (2, 2), (3, 3), (4, 4);")
1026+
1027+
tk.MustExec(`begin`)
1028+
tk.MustExec(`prepare delete_stmt from 'delete from t where a = ?'`)
1029+
tk.MustExec(`prepare insert_stmt from 'insert into t values (?, ?)'`)
1030+
tk.MustExec(`commit`)
1031+
1032+
tk.MustExec(`begin`)
1033+
tk.MustExec(`set @a = 4, @b= 4;`)
1034+
tk.MustExec(`execute delete_stmt using @a;`)
1035+
tk.MustExec(`execute insert_stmt using @a, @b;`)
1036+
tk.MustExec(`commit`)
1037+
1038+
tk.MustExec("begin")
1039+
1040+
ch := make(chan struct{})
1041+
1042+
first := true
1043+
testfailpoint.EnableCall(t, "github.com/pingcap/tidb/pkg/ddl/onJobUpdated", func(job *model.Job) {
1044+
switch job.SchemaState {
1045+
case model.StateWriteReorganization:
1046+
tbl, _ := dom.InfoSchema().TableByID(context.Background(), job.TableID)
1047+
idx := tbl.Meta().FindIndexByName("idx")
1048+
switch idx.BackfillState {
1049+
case model.BackfillStateRunning:
1050+
if first {
1051+
tk.MustExec(`begin`)
1052+
tk.MustExec(`set @a=9;`)
1053+
tk.MustExec(`execute delete_stmt using @a;`)
1054+
tk.MustQuery("select @@last_plan_from_cache;").Check(testkit.Rows("0"))
1055+
tk.MustExec(`set @a=6, @b=4;`)
1056+
tk.MustExec(`execute insert_stmt using @a, @b;`)
1057+
tk.MustQuery("select @@last_plan_from_cache;").Check(testkit.Rows("0"))
1058+
tk.MustExec(`commit`)
1059+
tk.MustExec(`begin`)
1060+
tk.MustExec(`set @a=4;`)
1061+
tk.MustExec(`execute delete_stmt using @a;`)
1062+
tk.MustQuery("select @@last_plan_from_cache;").Check(testkit.Rows("1"))
1063+
tk.MustExec(`set @a=4, @b=4;`)
1064+
tk.MustExec(`execute insert_stmt using @a, @b;`)
1065+
tk.MustQuery("select @@last_plan_from_cache;").Check(testkit.Rows("0"))
1066+
tk.MustExec(`commit`)
1067+
1068+
tk.MustExec("begin")
1069+
// Activate txn.
1070+
tk.MustExec("select * from t2")
1071+
first = false
1072+
tk3.MustExec("insert into test.t values(10000, 1000)")
1073+
return
1074+
}
1075+
}
1076+
}
1077+
})
1078+
1079+
ddl.MockDMLExecutionMerging = func() {
1080+
tk.MustExec(`execute delete_stmt using @a;`)
1081+
tk.MustQuery("select @@last_plan_from_cache;").Check(testkit.Rows("0"))
1082+
tk.MustExec(`execute insert_stmt using @a, @b;`)
1083+
tk.MustExec("commit")
1084+
}
1085+
require.NoError(t, failpoint.Enable("github.com/pingcap/tidb/pkg/ddl/mockDMLExecutionMerging", "1*return(true)->return(false)"))
1086+
1087+
var wg sync.WaitGroup
1088+
wg.Add(1)
1089+
go func() {
1090+
<-ch
1091+
tkDDL.MustExec("alter table test.t add index idx(a);")
1092+
wg.Done()
1093+
}()
1094+
1095+
ch <- struct{}{}
1096+
wg.Wait()
1097+
1098+
tk.MustExec("admin check table t")
1099+
}
1100+
10001101
func TestMDLDisable2Enable(t *testing.T) {
10011102
store, dom := testkit.CreateMockStoreAndDomain(t)
10021103
sv := server.CreateMockServer(t, store)

pkg/planner/core/plan_cache.go

Lines changed: 12 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -16,6 +16,7 @@ package core
1616

1717
import (
1818
"context"
19+
"math"
1920

2021
"github.com/pingcap/errors"
2122
"github.com/pingcap/tidb/pkg/domain"
@@ -37,6 +38,8 @@ import (
3738
contextutil "github.com/pingcap/tidb/pkg/util/context"
3839
"github.com/pingcap/tidb/pkg/util/dbterror/plannererrors"
3940
"github.com/pingcap/tidb/pkg/util/intest"
41+
"github.com/pingcap/tidb/pkg/util/logutil"
42+
"go.uber.org/zap"
4043
)
4144

4245
// PlanCacheKeyTestIssue43667 is only for test.
@@ -113,23 +116,23 @@ func planCachePreprocess(ctx context.Context, sctx sessionctx.Context, isNonPrep
113116
if err != nil {
114117
return plannererrors.ErrSchemaChanged.GenWithStack("Schema change caused error: %s", err.Error())
115118
}
119+
// Table ID is changed, for example, drop & create table, truncate table.
116120
delete(stmt.RelateVersion, stmt.tbls[i].Meta().ID)
117-
stmt.tbls[i] = tblByName
118-
stmt.RelateVersion[tblByName.Meta().ID] = tblByName.Meta().Revision
121+
tbl = tblByName
119122
}
120-
newTbl, err := tryLockMDLAndUpdateSchemaIfNecessary(ctx, sctx.GetPlanCtx(), stmt.dbName[i], stmt.tbls[i], is)
123+
// newTbl is the 'should be used' table info for this execution.
124+
newTbl, err := tryLockMDLAndUpdateSchemaIfNecessary(ctx, sctx.GetPlanCtx(), stmt.dbName[i], tbl, is)
121125
if err != nil {
126+
logutil.BgLogger().Warn("meet error during tryLockMDLAndUpdateSchemaIfNecessary", zap.String("table name", tbl.Meta().Name.String()), zap.Error(err))
127+
// Invalid the cache key related fields to avoid using plan cache.
128+
stmt.RelateVersion[tbl.Meta().ID] = math.MaxUint64
122129
schemaNotMatch = true
123130
continue
124131
}
125-
// The revision of tbl and newTbl may not be the same.
126-
// Example:
127-
// The version of stmt.tbls[i] is taken from the prepare statement and is revision v1.
128-
// When stmt.tbls[i] is locked in MDL, the revision of newTbl is also v1.
129-
// The revision of tbl is v2. The reason may have other statements trigger "tryLockMDLAndUpdateSchemaIfNecessary" before, leading to tbl revision update.
130-
if stmt.tbls[i].Meta().Revision != newTbl.Meta().Revision || (tbl != nil && tbl.Meta().Revision != newTbl.Meta().Revision) {
132+
if stmt.tbls[i].Meta().Revision != newTbl.Meta().Revision {
131133
schemaNotMatch = true
132134
}
135+
// Update the cache key related fields.
133136
stmt.tbls[i] = newTbl
134137
stmt.RelateVersion[newTbl.Meta().ID] = newTbl.Meta().Revision
135138
}

0 commit comments

Comments
 (0)