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: fix incorrectly using the schema for plan cache #57964

Merged
merged 5 commits into from
Dec 9, 2024
Merged
Show file tree
Hide file tree
Changes from 3 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: 3 additions & 1 deletion pkg/ddl/tests/metadatalock/BUILD.bazel
Original file line number Diff line number Diff line change
Expand Up @@ -8,16 +8,18 @@ go_test(
"mdl_test.go",
],
flaky = True,
shard_count = 36,
shard_count = 37,
deps = [
"//pkg/config",
"//pkg/ddl",
"//pkg/ddl/ingest/testutil",
"//pkg/errno",
"//pkg/meta/model",
"//pkg/server",
"//pkg/testkit",
"//pkg/testkit/testfailpoint",
"//pkg/testkit/testsetup",
"@com_github_pingcap_failpoint//:failpoint",
"@com_github_stretchr_testify//require",
"@org_uber_go_goleak//:goleak",
],
Expand Down
102 changes: 102 additions & 0 deletions pkg/ddl/tests/metadatalock/mdl_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -15,13 +15,17 @@
package metadatalocktest

import (
"context"
"fmt"
"sync"
"testing"
"time"

"github.com/pingcap/failpoint"
"github.com/pingcap/tidb/pkg/ddl"
ingesttestutil "github.com/pingcap/tidb/pkg/ddl/ingest/testutil"
mysql "github.com/pingcap/tidb/pkg/errno"
"github.com/pingcap/tidb/pkg/meta/model"
"github.com/pingcap/tidb/pkg/server"
"github.com/pingcap/tidb/pkg/testkit"
"github.com/pingcap/tidb/pkg/testkit/testfailpoint"
Expand Down Expand Up @@ -997,6 +1001,104 @@ func TestMDLPreparePlanCacheExecute2(t *testing.T) {
tk.MustExec("admin check table t")
}

func TestMDLPreparePlanCacheExecuteInsert(t *testing.T) {
zimulala marked this conversation as resolved.
Show resolved Hide resolved
store, dom := testkit.CreateMockStoreAndDomain(t)
defer ingesttestutil.InjectMockBackendMgr(t, store)()

sv := server.CreateMockServer(t, store)

sv.SetDomain(dom)
dom.InfoSyncer().SetSessionManager(sv)
defer sv.Close()

conn1 := server.CreateMockConn(t, sv)
tk := testkit.NewTestKitWithSession(t, store, conn1.Context().Session)
conn2 := server.CreateMockConn(t, sv)
tkDDL := testkit.NewTestKitWithSession(t, store, conn2.Context().Session)
conn3 := server.CreateMockConn(t, sv)
tk3 := testkit.NewTestKitWithSession(t, store, conn3.Context().Session)
tk.MustExec("use test")
tk.MustExec("set global tidb_enable_metadata_lock=1")
tk.MustExec("create table t(a int primary key, b int);")
tk.MustExec("create table t2(a int);")
tk.MustExec("insert into t values(1, 1), (2, 2), (3, 3), (4, 4);")

tk.MustExec(`begin`)
tk.MustExec(`prepare delete_stmt from 'delete from t where a = ?'`)
tk.MustExec(`prepare insert_stmt from 'insert into t values (?, ?)'`)
tk.MustExec(`commit`)

tk.MustExec(`begin`)
tk.MustExec(`set @a = 4, @b= 4;`)
tk.MustExec(`execute delete_stmt using @a;`)
tk.MustExec(`execute insert_stmt using @a, @b;`)
tk.MustExec(`commit`)

tk.MustExec("begin")

ch := make(chan struct{})

first := true
testfailpoint.EnableCall(t, "github.com/pingcap/tidb/pkg/ddl/onJobUpdated", func(job *model.Job) {
switch job.SchemaState {
case model.StateWriteReorganization:
tbl, _ := dom.InfoSchema().TableByID(context.Background(), job.TableID)
idx := tbl.Meta().FindIndexByName("idx")
switch idx.BackfillState {
case model.BackfillStateRunning:
if first {
tk.MustExec(`begin`)
tk.MustExec(`set @a=9;`)
tk.MustExec(`execute delete_stmt using @a;`)
tk.MustQuery("select @@last_plan_from_cache;").Check(testkit.Rows("0"))
tk.MustExec(`set @a=6, @b=4;`)
tk.MustExec(`execute insert_stmt using @a, @b;`)
tk.MustQuery("select @@last_plan_from_cache;").Check(testkit.Rows("0"))
tk.MustExec(`commit`)
tk.MustExec(`begin`)
tk.MustExec(`set @a=4;`)
tk.MustExec(`set @a=4;`)
tk.MustExec(`execute delete_stmt using @a;`)
tk.MustQuery("select @@last_plan_from_cache;").Check(testkit.Rows("1"))
tk.MustExec(`set @a=4, @b=4;`)
tk.MustExec(`execute insert_stmt using @a, @b;`)
tk.MustQuery("select @@last_plan_from_cache;").Check(testkit.Rows("0"))
tk.MustExec(`commit`)

tk.MustExec("begin")
tk.MustExec("select * from t2")
first = false
tk3.MustExec("insert into test.t values(10000, 1000)")
return
}
}
}
})

ddl.MockDMLExecutionMerging = func() {
tk.MustExec(`execute delete_stmt using @a;`)
tk.MustQuery("select @@last_plan_from_cache;").Check(testkit.Rows("0"))
tk.MustExec(`execute insert_stmt using @a, @b;`)
//tk.MustQuery("select @@last_plan_from_cache;").Check(testkit.Rows("0"))
tk.MustExec("commit")
}
require.NoError(t, failpoint.Enable("github.com/pingcap/tidb/pkg/ddl/mockDMLExecutionMerging", "1*return(true)->return(false)"))

var wg sync.WaitGroup
wg.Add(1)
go func() {
<-ch
tkDDL.MustExec("alter table test.t add index idx(a);")
wg.Done()
}()

ch <- struct{}{}

wg.Wait()

tk.MustExec("admin check table t")
}

func TestMDLDisable2Enable(t *testing.T) {
store, dom := testkit.CreateMockStoreAndDomain(t)
sv := server.CreateMockServer(t, store)
Expand Down
5 changes: 3 additions & 2 deletions pkg/planner/core/plan_cache.go
Original file line number Diff line number Diff line change
Expand Up @@ -116,10 +116,11 @@ func planCachePreprocess(ctx context.Context, sctx sessionctx.Context, isNonPrep
return plannererrors.ErrSchemaChanged.GenWithStack("Schema change caused error: %s", err.Error())
}
delete(stmt.RelateVersion, stmt.tbls[i].Meta().ID)
tbl = tblByName
stmt.tbls[i] = tblByName
stmt.RelateVersion[tblByName.Meta().ID] = tblByName.Meta().Revision
}
newTbl, err := tryLockMDLAndUpdateSchemaIfNecessary(ctx, sctx.GetPlanCtx(), stmt.dbName[i], stmt.tbls[i], is)
newTbl, err := tryLockMDLAndUpdateSchemaIfNecessary(ctx, sctx.GetPlanCtx(), stmt.dbName[i], tbl, is)
zimulala marked this conversation as resolved.
Show resolved Hide resolved
if err != nil {
schemaNotMatch = true
continue
Expand All @@ -129,7 +130,7 @@ func planCachePreprocess(ctx context.Context, sctx sessionctx.Context, isNonPrep
// The version of stmt.tbls[i] is taken from the prepare statement and is revision v1.
// When stmt.tbls[i] is locked in MDL, the revision of newTbl is also v1.
// The revision of tbl is v2. The reason may have other statements trigger "tryLockMDLAndUpdateSchemaIfNecessary" before, leading to tbl revision update.
if stmt.tbls[i].Meta().Revision != newTbl.Meta().Revision || (tbl != nil && tbl.Meta().Revision != newTbl.Meta().Revision) {
if stmt.tbls[i].Meta().Revision != newTbl.Meta().Revision {
zimulala marked this conversation as resolved.
Show resolved Hide resolved
schemaNotMatch = true
}
stmt.tbls[i] = newTbl
Expand Down