From 1ff1342283ba1f8db3d634d94bce45562ac3b2d9 Mon Sep 17 00:00:00 2001 From: tangenta Date: Sat, 10 Dec 2022 12:05:41 +0800 Subject: [PATCH] ddl: mark the writes from delete-only and drop them on merge (#39796) close pingcap/tidb#39731 --- ddl/index_merge_tmp.go | 5 +++-- ddl/index_merge_tmp_test.go | 45 +++++++++++++++++++++++++++++++++++++ table/tables/index.go | 7 +++++- 3 files changed, 54 insertions(+), 3 deletions(-) diff --git a/ddl/index_merge_tmp.go b/ddl/index_merge_tmp.go index b33111119facc..8f430ccce355f 100644 --- a/ddl/index_merge_tmp.go +++ b/ddl/index_merge_tmp.go @@ -186,8 +186,9 @@ func (w *mergeIndexWorker) fetchTempIndexVals(txn kv.Transaction, taskRange reor unique := false length := len(rawValue) keyVer := rawValue[length-1] - if keyVer == tables.TempIndexKeyTypeMerge { - // The kv is written in the merging state. It has been written to the origin index, we can skip it. + if keyVer == tables.TempIndexKeyTypeMerge || keyVer == tables.TempIndexKeyTypeDelete { + // For 'm' version kvs, they are double-written. + // For 'd' version kvs, they are written in the delete-only state and can be dropped safely. return true, nil } rawValue = rawValue[:length-1] diff --git a/ddl/index_merge_tmp_test.go b/ddl/index_merge_tmp_test.go index 389339ac15ad4..431e4791f4aeb 100644 --- a/ddl/index_merge_tmp_test.go +++ b/ddl/index_merge_tmp_test.go @@ -331,3 +331,48 @@ func TestCreateUniqueIndexKeyExist(t *testing.T) { tk.MustExec("admin check table t") tk.MustQuery("select * from t order by a, b").Check(testkit.Rows("0 9", "1 7", "2 7", "5 7", "8 8", "10 10")) } + +func TestAddIndexMergeIndexUpdateOnDeleteOnly(t *testing.T) { + store, dom := testkit.CreateMockStoreAndDomain(t) + tk := testkit.NewTestKit(t, store) + tk.MustExec("use test") + tk2 := testkit.NewTestKit(t, store) + tk2.MustExec("use test") + tk.MustExec(`CREATE TABLE t (a DATE NULL DEFAULT '1619-01-18', b BOOL NULL DEFAULT '0') CHARACTER SET 'utf8mb4' COLLATE 'utf8mb4_bin';`) + tk.MustExec(`INSERT INTO t SET b = '1';`) + + updateSQLs := []string{ + "UPDATE t SET a = '9432-05-10', b = '0';", + "UPDATE t SET a = '9432-05-10', b = '1';", + } + + // Force onCreateIndex use the txn-merge process. + ingest.LitInitialized = false + tk.MustExec("set @@global.tidb_ddl_enable_fast_reorg = 1;") + tk.MustExec("set @@global.tidb_enable_mutation_checker = 1;") + tk.MustExec("set @@global.tidb_txn_assertion_level = 'STRICT';") + + var checkErrs []error + originHook := dom.DDL().GetHook() + callback := &ddl.TestDDLCallback{ + Do: dom, + } + onJobUpdatedBefore := func(job *model.Job) { + if job.SchemaState == model.StateDeleteOnly { + for _, sql := range updateSQLs { + _, err := tk2.Exec(sql) + if err != nil { + checkErrs = append(checkErrs, err) + } + } + } + } + callback.OnJobUpdatedExported.Store(&onJobUpdatedBefore) + dom.DDL().SetHook(callback) + tk.MustExec("alter table t add index idx(b);") + dom.DDL().SetHook(originHook) + for _, err := range checkErrs { + require.NoError(t, err) + } + tk.MustExec("admin check table t;") +} diff --git a/table/tables/index.go b/table/tables/index.go index b3a481efba29f..1193f9e251758 100644 --- a/table/tables/index.go +++ b/table/tables/index.go @@ -130,7 +130,7 @@ func (c *index) Create(sctx sessionctx.Context, txn kv.Transaction, indexedValue ) if !opt.FromBackFill { key, tempKey, keyVer = GenTempIdxKeyByState(c.idxInfo, key) - if keyVer == TempIndexKeyTypeBackfill { + if keyVer == TempIndexKeyTypeBackfill || keyVer == TempIndexKeyTypeDelete { key, tempKey = tempKey, nil keyIsTempIdxKey = true } @@ -347,6 +347,8 @@ func (c *index) Delete(sc *stmtctx.StatementContext, txn kv.Transaction, indexed const ( // TempIndexKeyTypeNone means the key is not a temporary index key. TempIndexKeyTypeNone byte = 0 + // TempIndexKeyTypeDelete indicates this value is written in the delete-only stage. + TempIndexKeyTypeDelete byte = 'd' // TempIndexKeyTypeBackfill indicates this value is written in the backfill stage. TempIndexKeyTypeBackfill byte = 'b' // TempIndexKeyTypeMerge indicates this value is written in the merge stage. @@ -363,6 +365,9 @@ func GenTempIdxKeyByState(indexInfo *model.IndexInfo, indexKey kv.Key) (key, tem case model.BackfillStateRunning: // Write to the temporary index. tablecodec.IndexKey2TempIndexKey(indexInfo.ID, indexKey) + if indexInfo.State == model.StateDeleteOnly { + return nil, indexKey, TempIndexKeyTypeDelete + } return nil, indexKey, TempIndexKeyTypeBackfill case model.BackfillStateReadyToMerge, model.BackfillStateMerging: // Double write