From 9ee4937c7651c96e6aa6ba14f0495dd10ad440d5 Mon Sep 17 00:00:00 2001 From: Ti Chi Robot Date: Thu, 18 May 2023 18:25:36 +0800 Subject: [PATCH] txn: Add test for BatchResolveLock meeting pessimistic lock whose primary has changed (#43898) (#43947) ref pingcap/tidb#43243 --- .../realtikvtest/pessimistictest/BUILD.bazel | 2 + .../pessimistictest/pessimistic_test.go | 89 +++++++++++++++++++ 2 files changed, 91 insertions(+) diff --git a/tests/realtikvtest/pessimistictest/BUILD.bazel b/tests/realtikvtest/pessimistictest/BUILD.bazel index 201a27a3c26c..2d6ed2f9cda2 100644 --- a/tests/realtikvtest/pessimistictest/BUILD.bazel +++ b/tests/realtikvtest/pessimistictest/BUILD.bazel @@ -24,6 +24,7 @@ go_test( "//sessionctx/variable", "//sessiontxn", "//store/driver/error", + "//store/gcworker", "//store/mockstore", "//tablecodec", "//testkit", @@ -37,6 +38,7 @@ go_test( "@com_github_stretchr_testify//require", "@com_github_tikv_client_go_v2//oracle", "@com_github_tikv_client_go_v2//testutils", + "@com_github_tikv_client_go_v2//tikv", "@com_github_tikv_client_go_v2//txnkv/transaction", ], ) diff --git a/tests/realtikvtest/pessimistictest/pessimistic_test.go b/tests/realtikvtest/pessimistictest/pessimistic_test.go index bcde6d9cbe19..b08da77f6c9f 100644 --- a/tests/realtikvtest/pessimistictest/pessimistic_test.go +++ b/tests/realtikvtest/pessimistictest/pessimistic_test.go @@ -41,6 +41,7 @@ import ( "github.com/pingcap/tidb/sessionctx/variable" "github.com/pingcap/tidb/sessiontxn" storeerr "github.com/pingcap/tidb/store/driver/error" + "github.com/pingcap/tidb/store/gcworker" "github.com/pingcap/tidb/store/mockstore" "github.com/pingcap/tidb/tablecodec" "github.com/pingcap/tidb/testkit" @@ -52,6 +53,7 @@ import ( "github.com/stretchr/testify/require" "github.com/tikv/client-go/v2/oracle" "github.com/tikv/client-go/v2/testutils" + "github.com/tikv/client-go/v2/tikv" "github.com/tikv/client-go/v2/txnkv/transaction" ) @@ -3385,3 +3387,90 @@ func TestPointLockNonExistentKeyWithFairLockingUnderRC(t *testing.T) { require.Equal(t, lockedWithConflictCounter, 0) tk.MustExec("commit") } + +func TestIssue43243(t *testing.T) { + store, domain := realtikvtest.CreateMockStoreAndDomainAndSetup(t) + + if *realtikvtest.WithRealTiKV { + // Disable in-memory pessimistic lock since it cannot be scanned in current implementation. + // TODO: Remove this after supporting scan lock for in-memory pessimistic lock. + tkcfg := testkit.NewTestKit(t, store) + res := tkcfg.MustQuery("show config where name = 'pessimistic-txn.in-memory' and type = 'tikv'").Rows() + if len(res) > 0 && res[0][3].(string) == "true" { + tkcfg.MustExec("set config tikv `pessimistic-txn.in-memory`=\"false\"") + tkcfg.MustQuery("show warnings").Check(testkit.Rows()) + defer func() { + tkcfg.MustExec("set config tikv `pessimistic-txn.in-memory`=\"true\"") + }() + time.Sleep(time.Second) + } else { + t.Log("skip disabling in-memory pessimistic lock, current config:", res) + } + } + + tk := testkit.NewTestKit(t, store) + tk.MustExec("use test") + tk.MustExec("create table t1 (id int primary key, v int)") + tk.MustExec("create table t2 (id int primary key, v int)") + tk.MustExec("insert into t1 values (1, 1), (2, 2)") + tk.MustExec("insert into t2 values (1, 1), (2, 2), (3, 3), (4, 4), (5, 5)") + tk.MustExec("set @@tidb_enable_async_commit=0") + tk.MustExec("set @@tidb_enable_1pc=0") + + // Split region + { + tableID, err := strconv.ParseInt(tk.MustQuery(`select tidb_table_id from information_schema.tables where table_schema = "test" and table_name = "t2"`).Rows()[0][0].(string), 10, 64) + require.NoError(t, err) + key := tablecodec.EncodeTablePrefix(tableID) + _, err = domain.GetPDClient().SplitRegions(context.Background(), [][]byte{key}) + require.NoError(t, err) + } + + tk2 := testkit.NewTestKit(t, store) + tk2.MustExec("use test") + tk3 := testkit.NewTestKit(t, store) + tk3.MustExec("use test") + + require.NoError(t, failpoint.Enable("tikvclient/beforeAsyncPessimisticRollback", `return("skip")`)) + require.NoError(t, failpoint.Enable("tikvclient/beforeCommitSecondaries", `return("skip")`)) + require.NoError(t, failpoint.Enable("tikvclient/twoPCRequestBatchSizeLimit", `return`)) + defer func() { + require.NoError(t, failpoint.Disable("tikvclient/beforeAsyncPessimisticRollback")) + require.NoError(t, failpoint.Disable("tikvclient/beforeCommitSecondaries")) + require.NoError(t, failpoint.Disable("tikvclient/twoPCRequestBatchSizeLimit")) + }() + + tk.MustExec("begin pessimistic") + tk2.MustExec("begin pessimistic") + tk2.MustExec("update t2 set v = v + 1 where id = 2") + ch := make(chan struct{}) + go func() { + tk.MustExec(` + with + c as (select /*+ MERGE() */ v from t1 where id in (1, 2)) + update c join t2 on c.v = t2.id set t2.v = t2.v + 10`) + ch <- struct{}{} + }() + // tk blocked on row 2 + mustTimeout(t, ch, time.Millisecond*100) + // Change the rows that should be locked by tk. + tk3.MustExec("update t1 set v = v + 3") + // Release row 2 and resume tk. + tk2.MustExec("commit") + mustRecv(t, ch) + + // tk should have updated row 4 and row 5, and 4 should be the primary. + // At the same time row 1 should be the old primary, row2 points to row 1. + // Add another secondary that's smaller than the current primary. + tk.MustExec("update t2 set v = v + 10 where id = 3") + tk.MustExec("commit") + + // Simulate a later GC that should resolve all stale lock produced in above steps. + currentTS, err := store.CurrentVersion(kv.GlobalTxnScope) + require.NoError(t, err) + _, err = gcworker.RunResolveLocks(context.Background(), store.(tikv.Storage), domain.GetPDClient(), currentTS.Ver, "gc-worker-test-issue43243", 1, false) + require.NoError(t, err) + + // Check data consistency + tk.MustQuery("select * from t2 order by id").Check(testkit.Rows("1 1", "2 3", "3 13", "4 14", "5 15")) +}