From 6508f5dc8863da88ae5395e4fcfb58abf14e9d0d Mon Sep 17 00:00:00 2001 From: Hangjie Mo Date: Thu, 2 Feb 2023 14:57:01 +0800 Subject: [PATCH 1/4] update --- meta/meta.go | 25 ++++++++++++++++++++++++- session/session.go | 41 ++++++++++++++++++++++++----------------- 2 files changed, 48 insertions(+), 18 deletions(-) diff --git a/meta/meta.go b/meta/meta.go index 41a8231130be0..d92bdc14b2d41 100644 --- a/meta/meta.go +++ b/meta/meta.go @@ -630,6 +630,12 @@ func (m *Meta) SetMDLTables() error { return errors.Trace(err) } +// SetBackfillTables write a key into storage. +func (m *Meta) SetBackfillTables() error { + err := m.txn.Set(mDDLTableVersion, []byte("3")) + return errors.Trace(err) +} + // CreateMySQLDatabaseIfNotExists creates mysql schema and return its DB ID. func (m *Meta) CreateMySQLDatabaseIfNotExists() (int64, error) { id, err := m.GetSystemDBID() @@ -681,7 +687,24 @@ func (m *Meta) CheckMDLTableExists() (bool, error) { if err != nil { return false, errors.Trace(err) } - return bytes.Equal(v, []byte("2")), nil + ver, err := strconv.ParseUint(string(v), 10, 64) + if err != nil { + return false, errors.Trace(err) + } + return ver >= 2, nil +} + +// CheckBackfillTableExists check if the tables related to concurrent DDL exists. +func (m *Meta) CheckBackfillTableExists() (bool, error) { + v, err := m.txn.Get(mDDLTableVersion) + if err != nil { + return false, errors.Trace(err) + } + ver, err := strconv.ParseUint(string(v), 10, 64) + if err != nil { + return false, errors.Trace(err) + } + return ver >= 3, nil } // SetMetadataLock sets the metadata lock. diff --git a/session/session.go b/session/session.go index 624315fe8fc72..e41dc0c9b520c 100644 --- a/session/session.go +++ b/session/session.go @@ -3108,36 +3108,20 @@ func InitDDLJobTables(store kv.Storage) error { return kv.RunInNewTxn(kv.WithInternalSourceType(context.Background(), kv.InternalTxnDDL), store, true, func(ctx context.Context, txn kv.Transaction) error { t := meta.NewMeta(txn) exists, err := t.CheckDDLTableExists() - if err != nil { + if err != nil || exists { return errors.Trace(err) } dbID, err := t.CreateMySQLDatabaseIfNotExists() if err != nil { return err } - if exists { - return initBackfillJobTables(store, t, dbID) - } - if err = createAndSplitTables(store, t, dbID, DDLJobTables); err != nil { return err } - if err = initBackfillJobTables(store, t, dbID); err != nil { - return err - } return t.SetDDLTables() }) } -// initBackfillJobTables is to create tidb_ddl_backfill and tidb_ddl_backfill_history. -func initBackfillJobTables(store kv.Storage, t *meta.Meta, dbID int64) error { - tblExist, err := t.CheckTableExists(dbID, BackfillTables[0].id) - if err != nil || tblExist { - return errors.Trace(err) - } - return createAndSplitTables(store, t, dbID, BackfillTables) -} - func createAndSplitTables(store kv.Storage, t *meta.Meta, dbID int64, tables []tableBasicInfo) error { tableIDs := make([]int64, 0, len(tables)) for _, tbl := range tables { @@ -3199,6 +3183,25 @@ func InitMDLTable(store kv.Storage) error { }) } +// InitBackfillTable is to create tidb_ddl_backfill and tidb_ddl_backfill_history, which is used for distreorg. +func InitBackfillTable(store kv.Storage) error { + return kv.RunInNewTxn(kv.WithInternalSourceType(context.Background(), kv.InternalTxnDDL), store, true, func(ctx context.Context, txn kv.Transaction) error { + t := meta.NewMeta(txn) + exists, err := t.CheckBackfillTableExists() + if err != nil || exists { + return errors.Trace(err) + } + dbID, err := t.CreateMySQLDatabaseIfNotExists() + if err != nil { + return err + } + if err = createAndSplitTables(store, t, dbID, BackfillTables); err != nil { + return err + } + return t.SetBackfillTables() + }) +} + // InitMDLVariableForBootstrap initializes the metadata lock variable. func InitMDLVariableForBootstrap(store kv.Storage) error { err := kv.RunInNewTxn(kv.WithInternalSourceType(context.Background(), kv.InternalTxnDDL), store, true, func(ctx context.Context, txn kv.Transaction) error { @@ -3280,6 +3283,10 @@ func BootstrapSession(store kv.Storage) (*domain.Domain, error) { if err != nil { return nil, err } + err = InitBackfillTable(store) + if err != nil { + return nil, err + } ver := getStoreBootstrapVersion(store) if ver == notBootstrapped { runInBootstrapSession(store, bootstrap) From de358328c9720a741b477c25434b0c7f6a3d2049 Mon Sep 17 00:00:00 2001 From: Hangjie Mo Date: Thu, 2 Feb 2023 15:09:29 +0800 Subject: [PATCH 2/4] add test --- session/session_test.go | 12 +++++++++--- 1 file changed, 9 insertions(+), 3 deletions(-) diff --git a/session/session_test.go b/session/session_test.go index 530aee66d4ead..2d1c9669445c5 100644 --- a/session/session_test.go +++ b/session/session_test.go @@ -37,10 +37,16 @@ func TestInitMetaTable(t *testing.T) { tk.MustExec(sql.SQL) } + for _, sql := range session.BackfillTables { + tk.MustExec(sql.SQL) + } + tbls := map[string]struct{}{ - "tidb_ddl_job": {}, - "tidb_ddl_reorg": {}, - "tidb_ddl_history": {}, + "tidb_ddl_job": {}, + "tidb_ddl_reorg": {}, + "tidb_ddl_history": {}, + "tidb_ddl_backfill": {}, + "tidb_ddl_backfill_history": {}, } for tbl := range tbls { From 932d2302bd0a05cae20b8e048a0930359e116f5d Mon Sep 17 00:00:00 2001 From: Jason Mo Date: Fri, 3 Feb 2023 10:37:31 +0800 Subject: [PATCH 3/4] follow comments --- meta/meta.go | 81 ++++++++++++++++----------------------- session/bootstrap_test.go | 37 +++++++++++++++++- session/session.go | 45 ++++++++-------------- 3 files changed, 85 insertions(+), 78 deletions(-) diff --git a/meta/meta.go b/meta/meta.go index d92bdc14b2d41..0dec9dd4831eb 100644 --- a/meta/meta.go +++ b/meta/meta.go @@ -122,6 +122,24 @@ var ( ErrInvalidString = dbterror.ClassMeta.NewStd(errno.ErrInvalidCharacterString) ) +type DDLTableVersion int + +const ( + // InitDDLTableVersion is the original version. + InitDDLTableVersion DDLTableVersion = 0 + // BaseDDLTableVersion is for support concurrent DDL, it added tidb_ddl_job, tidb_ddl_reorg and tidb_ddl_history. + BaseDDLTableVersion DDLTableVersion = 1 + // MDLTableVersion is for support MDL tables. + MDLTableVersion DDLTableVersion = 2 + // BackfillTableVersion is for support distributed reorg stage, it added tidb_ddl_backfill, tidb_ddl_backfill_history. + BackfillTableVersion DDLTableVersion = 3 +) + +// Bytes returns the byte slice. +func (ver DDLTableVersion) Bytes() []byte { + return []byte(strconv.Itoa(int(ver))) +} + // Meta is for handling meta information in a transaction. type Meta struct { txn *structure.TxStructure @@ -619,21 +637,25 @@ func (m *Meta) CreateTableOrView(dbID int64, tableInfo *model.TableInfo) error { } // SetDDLTables write a key into storage. -func (m *Meta) SetDDLTables() error { - err := m.txn.Set(mDDLTableVersion, []byte("1")) +func (m *Meta) SetDDLTables(ddlTableVersion DDLTableVersion) error { + err := m.txn.Set(mDDLTableVersion, ddlTableVersion.Bytes()) return errors.Trace(err) } -// SetMDLTables write a key into storage. -func (m *Meta) SetMDLTables() error { - err := m.txn.Set(mDDLTableVersion, []byte("2")) - return errors.Trace(err) -} - -// SetBackfillTables write a key into storage. -func (m *Meta) SetBackfillTables() error { - err := m.txn.Set(mDDLTableVersion, []byte("3")) - return errors.Trace(err) +// CheckDDLTableVersion check if the tables related to concurrent DDL exists. +func (m *Meta) CheckDDLTableVersion() (DDLTableVersion, error) { + v, err := m.txn.Get(mDDLTableVersion) + if err != nil { + return -1, errors.Trace(err) + } + if string(v) == "" { + return InitDDLTableVersion, nil + } + ver, err := strconv.Atoi(string(v)) + if err != nil { + return -1, errors.Trace(err) + } + return DDLTableVersion(ver), nil } // CreateMySQLDatabaseIfNotExists creates mysql schema and return its DB ID. @@ -672,41 +694,6 @@ func (m *Meta) GetSystemDBID() (int64, error) { return 0, nil } -// CheckDDLTableExists check if the tables related to concurrent DDL exists. -func (m *Meta) CheckDDLTableExists() (bool, error) { - v, err := m.txn.Get(mDDLTableVersion) - if err != nil { - return false, errors.Trace(err) - } - return len(v) != 0, nil -} - -// CheckMDLTableExists check if the tables related to concurrent DDL exists. -func (m *Meta) CheckMDLTableExists() (bool, error) { - v, err := m.txn.Get(mDDLTableVersion) - if err != nil { - return false, errors.Trace(err) - } - ver, err := strconv.ParseUint(string(v), 10, 64) - if err != nil { - return false, errors.Trace(err) - } - return ver >= 2, nil -} - -// CheckBackfillTableExists check if the tables related to concurrent DDL exists. -func (m *Meta) CheckBackfillTableExists() (bool, error) { - v, err := m.txn.Get(mDDLTableVersion) - if err != nil { - return false, errors.Trace(err) - } - ver, err := strconv.ParseUint(string(v), 10, 64) - if err != nil { - return false, errors.Trace(err) - } - return ver >= 3, nil -} - // SetMetadataLock sets the metadata lock. func (m *Meta) SetMetadataLock(b bool) error { var data []byte diff --git a/session/bootstrap_test.go b/session/bootstrap_test.go index a010daf32b14c..e6013d8b150ce 100644 --- a/session/bootstrap_test.go +++ b/session/bootstrap_test.go @@ -152,10 +152,12 @@ func TestBootstrapWithError(t *testing.T) { se.txn.init() se.mu.values = make(map[fmt.Stringer]interface{}) se.SetValue(sessionctx.Initing, true) - err := InitDDLJobTables(store) + err := InitDDLJobTables(store, meta.BaseDDLTableVersion) require.NoError(t, err) err = InitMDLTable(store) require.NoError(t, err) + err = InitDDLJobTables(store, meta.BackfillTableVersion) + require.NoError(t, err) dom, err := domap.Get(store) require.NoError(t, err) domain.BindDomain(se, dom) @@ -215,10 +217,43 @@ func TestBootstrapWithError(t *testing.T) { require.Equal(t, []byte("True"), row.GetBytes(0)) require.NoError(t, r.Close()) + mustExec(t, se, "SELECT * from mysql.tidb_ddl_backfill") + mustExec(t, se, "SELECT * from mysql.tidb_ddl_backfill_history") + // Check tidb_ttl_table_status table mustExec(t, se, "SELECT * from mysql.tidb_ttl_table_status") } +func TestDDLTableCreateBackfillTable(t *testing.T) { + store, dom := createStoreAndBootstrap(t) + defer func() { require.NoError(t, store.Close()) }() + se := createSessionAndSetID(t, store) + + txn, err := store.Begin() + require.NoError(t, err) + m := meta.NewMeta(txn) + ver, err := m.CheckDDLTableVersion() + require.NoError(t, err) + require.GreaterOrEqual(t, ver, meta.BackfillTableVersion) + + // downgrade `mDDLTableVersion` + m.SetDDLTables(meta.MDLTableVersion) + mustExec(t, se, "drop table mysql.tidb_ddl_backfill") + mustExec(t, se, "drop table mysql.tidb_ddl_backfill_history") + err = txn.Commit(context.Background()) + require.NoError(t, err) + + // to upgrade session for create ddl related tables + dom.Close() + dom, err = BootstrapSession(store) + require.NoError(t, err) + + se = createSessionAndSetID(t, store) + mustExec(t, se, "select * from mysql.tidb_ddl_backfill") + mustExec(t, se, "select * from mysql.tidb_ddl_backfill_history") + dom.Close() +} + // TestUpgrade tests upgrading func TestUpgrade(t *testing.T) { ctx := context.Background() diff --git a/session/session.go b/session/session.go index e41dc0c9b520c..901c4dc4e17f7 100644 --- a/session/session.go +++ b/session/session.go @@ -3103,22 +3103,26 @@ func splitAndScatterTable(store kv.Storage, tableIDs []int64) { } } -// InitDDLJobTables is to create tidb_ddl_job, tidb_ddl_reorg, tidb_ddl_history, tidb_ddl_backfill and tidb_ddl_backfill_history. -func InitDDLJobTables(store kv.Storage) error { +// InitDDLJobTables is to create tidb_ddl_job, tidb_ddl_reorg and tidb_ddl_history, or tidb_ddl_backfill and tidb_ddl_backfill_history. +func InitDDLJobTables(store kv.Storage, targetVer meta.DDLTableVersion) error { + targetTables := DDLJobTables + if targetVer == meta.BackfillTableVersion { + targetTables = BackfillTables + } return kv.RunInNewTxn(kv.WithInternalSourceType(context.Background(), kv.InternalTxnDDL), store, true, func(ctx context.Context, txn kv.Transaction) error { t := meta.NewMeta(txn) - exists, err := t.CheckDDLTableExists() - if err != nil || exists { + tableVer, err := t.CheckDDLTableVersion() + if err != nil || tableVer >= targetVer { return errors.Trace(err) } dbID, err := t.CreateMySQLDatabaseIfNotExists() if err != nil { return err } - if err = createAndSplitTables(store, t, dbID, DDLJobTables); err != nil { + if err = createAndSplitTables(store, t, dbID, targetTables); err != nil { return err } - return t.SetDDLTables() + return t.SetDDLTables(targetVer) }) } @@ -3153,8 +3157,8 @@ func createAndSplitTables(store kv.Storage, t *meta.Meta, dbID int64, tables []t func InitMDLTable(store kv.Storage) error { return kv.RunInNewTxn(kv.WithInternalSourceType(context.Background(), kv.InternalTxnDDL), store, true, func(ctx context.Context, txn kv.Transaction) error { t := meta.NewMeta(txn) - exists, err := t.CheckMDLTableExists() - if err != nil || exists { + ver, err := t.CheckDDLTableVersion() + if err != nil || ver >= meta.MDLTableVersion { return errors.Trace(err) } dbID, err := t.CreateMySQLDatabaseIfNotExists() @@ -3179,26 +3183,7 @@ func InitMDLTable(store kv.Storage) error { return errors.Trace(err) } - return t.SetMDLTables() - }) -} - -// InitBackfillTable is to create tidb_ddl_backfill and tidb_ddl_backfill_history, which is used for distreorg. -func InitBackfillTable(store kv.Storage) error { - return kv.RunInNewTxn(kv.WithInternalSourceType(context.Background(), kv.InternalTxnDDL), store, true, func(ctx context.Context, txn kv.Transaction) error { - t := meta.NewMeta(txn) - exists, err := t.CheckBackfillTableExists() - if err != nil || exists { - return errors.Trace(err) - } - dbID, err := t.CreateMySQLDatabaseIfNotExists() - if err != nil { - return err - } - if err = createAndSplitTables(store, t, dbID, BackfillTables); err != nil { - return err - } - return t.SetBackfillTables() + return t.SetDDLTables(meta.MDLTableVersion) }) } @@ -3275,7 +3260,7 @@ func BootstrapSession(store kv.Storage) (*domain.Domain, error) { return nil, err } } - err := InitDDLJobTables(store) + err := InitDDLJobTables(store, meta.BaseDDLTableVersion) if err != nil { return nil, err } @@ -3283,7 +3268,7 @@ func BootstrapSession(store kv.Storage) (*domain.Domain, error) { if err != nil { return nil, err } - err = InitBackfillTable(store) + err = InitDDLJobTables(store, meta.BackfillTableVersion) if err != nil { return nil, err } From ca8f3b56048d4f6157b9821eea9a7a00e5b534d5 Mon Sep 17 00:00:00 2001 From: Jason Mo Date: Fri, 3 Feb 2023 10:42:06 +0800 Subject: [PATCH 4/4] fix lint --- meta/meta.go | 1 + 1 file changed, 1 insertion(+) diff --git a/meta/meta.go b/meta/meta.go index 0dec9dd4831eb..c189514fb503e 100644 --- a/meta/meta.go +++ b/meta/meta.go @@ -122,6 +122,7 @@ var ( ErrInvalidString = dbterror.ClassMeta.NewStd(errno.ErrInvalidCharacterString) ) +// DDLTableVersion is to display ddl related table versions type DDLTableVersion int const (