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

bootstrap: use BatchCreateTableWithInfo to speed up #42432

Closed
wants to merge 11 commits into from
9 changes: 9 additions & 0 deletions ddl/ddl.go
Original file line number Diff line number Diff line change
Expand Up @@ -112,6 +112,7 @@ type AllocTableIDIf func(*model.TableInfo) bool
type CreateTableWithInfoConfig struct {
OnExist OnExist
ShouldAllocTableID AllocTableIDIf
SkipTableID int
}

// CreateTableWithInfoConfigurier is the "diff" which can be applied to the
Expand Down Expand Up @@ -144,6 +145,14 @@ func (a AllocTableIDIf) Apply(c *CreateTableWithInfoConfig) {
c.ShouldAllocTableID = a
}

// SkipTableID is used to let BatchCreateTableWithInfo mimic the behaviour of CreateTable.
type SkipTableID int

// Apply implements Configurier.
func (a SkipTableID) Apply(c *CreateTableWithInfoConfig) {
c.SkipTableID = int(a)
}

const (
// OnExistError throws an error on name collision.
OnExistError OnExist = iota
Expand Down
7 changes: 7 additions & 0 deletions ddl/ddl_api.go
Original file line number Diff line number Diff line change
Expand Up @@ -2221,6 +2221,11 @@ func BuildTableInfoFromAST(s *ast.CreateTableStmt) (*model.TableInfo, error) {
return buildTableInfoWithCheck(mock.NewContext(), s, mysql.DefaultCharset, "", nil)
}

// BuildTableInfoWithContext builds model.TableInfo from a SQL statement using given context.
func BuildTableInfoWithContext(ctx sessionctx.Context, s *ast.CreateTableStmt) (*model.TableInfo, error) {
return buildTableInfoWithCheck(ctx, s, mysql.DefaultCharset, "", nil)
}

// buildTableInfoWithCheck builds model.TableInfo from a SQL statement.
// Note: TableID and PartitionIDs are left as uninitialized value.
func buildTableInfoWithCheck(ctx sessionctx.Context, s *ast.CreateTableStmt, dbCharset, dbCollate string, placementPolicyRef *model.PolicyRefInfo) (*model.TableInfo, error) {
Expand Down Expand Up @@ -2598,6 +2603,7 @@ func (d *ddl) BatchCreateTableWithInfo(ctx sessionctx.Context,
}
}

totalID *= 1 + c.SkipTableID
genIDs, err := d.genGlobalIDs(totalID)
if err != nil {
return errors.Trace(err)
Expand All @@ -2612,6 +2618,7 @@ func (d *ddl) BatchCreateTableWithInfo(ctx sessionctx.Context,
parts.Definitions[i].ID, genIDs = genIDs[0], genIDs[1:]
}
}
genIDs = genIDs[c.SkipTableID:]
}

job, err := d.createTableWithInfoJob(ctx, dbName, info, c.OnExist, true)
Expand Down
4 changes: 2 additions & 2 deletions ddl/schematracker/checker.go
Original file line number Diff line number Diff line change
Expand Up @@ -472,8 +472,8 @@ func (d Checker) CreateTableWithInfo(ctx sessionctx.Context, schema model.CIStr,

// BatchCreateTableWithInfo implements the DDL interface.
func (d Checker) BatchCreateTableWithInfo(ctx sessionctx.Context, schema model.CIStr, info []*model.TableInfo, cs ...ddl.CreateTableWithInfoConfigurier) error {
//TODO implement me
panic("implement me")
// currently this is only used in bootstrap, we don't need to check it.
return d.realDDL.BatchCreateTableWithInfo(ctx, schema, info, cs...)
}

// CreatePlacementPolicyWithInfo implements the DDL interface.
Expand Down
3 changes: 2 additions & 1 deletion executor/executor_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -5663,9 +5663,10 @@ func TestAdmin(t *testing.T) {
tk.MustExec("use test")
tk.MustExec("drop table if exists admin_test2")
tk.MustExec("create table admin_test2 (c1 int, c2 int, c3 int default 1, index (c1))")
// we cn only see last 10 queries
Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Suggested change
// we cn only see last 10 queries
// we can only see last 10 queries

Due to BatchCreateTableWithInfo, we have less history DDL jobs

result := tk.MustQuery(`admin show ddl job queries 1, 1, 1`)
result.Check(testkit.Rows())
result = tk.MustQuery(`admin show ddl job queries 1, 2, 3, 4`)
result = tk.MustQuery(`admin show ddl job queries 1, 2`)
result.Check(testkit.Rows())
historyJobs, err = ddl.GetLastNHistoryDDLJobs(meta.NewMeta(txn), ddl.DefNumHistoryJobs)
result = tk.MustQuery(fmt.Sprintf("admin show ddl job queries %d", historyJobs[0].ID))
Expand Down
176 changes: 89 additions & 87 deletions session/bootstrap.go
Original file line number Diff line number Diff line change
Expand Up @@ -40,11 +40,13 @@ import (
"github.com/pingcap/tidb/meta"
"github.com/pingcap/tidb/owner"
"github.com/pingcap/tidb/parser"
"github.com/pingcap/tidb/parser/ast"
"github.com/pingcap/tidb/parser/auth"
"github.com/pingcap/tidb/parser/model"
"github.com/pingcap/tidb/parser/mysql"
"github.com/pingcap/tidb/parser/terror"
"github.com/pingcap/tidb/planner/core"
"github.com/pingcap/tidb/sessionctx"
"github.com/pingcap/tidb/sessionctx/variable"
"github.com/pingcap/tidb/table/tables"
"github.com/pingcap/tidb/types"
Expand Down Expand Up @@ -586,6 +588,31 @@ const (
PRIMARY KEY (job_id),
KEY (create_time),
KEY (create_user));`
// please make sure newly added CREATE TABLE consts are also added to below
// allCreateTablesPart2
)

var (
allCreateTablesPart1 = []string{
CreateUserTable, CreatePasswordHistory, CreateGlobalPrivTable,
CreateDBPrivTable, CreateTablePrivTable, CreateColumnPrivTable,
CreateGlobalVariablesTable, CreateTiDBTable, CreateHelpTopic,
CreateStatsMetaTable, CreateStatsColsTable, CreateStatsBucketsTable,
CreateGCDeleteRangeTable, CreateGCDeleteRangeDoneTable, CreateStatsFeedbackTable,
CreateRoleEdgesTable, CreateDefaultRolesTable, CreateBindInfoTable,
CreateStatsTopNTable, CreateExprPushdownBlacklist, CreateOptRuleBlacklist,
CreateStatsExtended, CreateSchemaIndexUsageTable, CreateStatsFMSketchTable,
CreateGlobalGrantsTable, CreateCapturePlanBaselinesBlacklist,
CreateColumnStatsUsageTable, CreateTableCacheMetaTable, CreateAnalyzeOptionsTable,
CreateStatsHistory, CreateStatsMetaHistory, CreateAnalyzeJobs,
CreateAdvisoryLocks,
}
// we should create MDL view between allCreateTablesPart1 and allCreateTablesPart2
allCreateTablesPart2 = []string{
CreatePlanReplayerStatusTable, CreatePlanReplayerTaskTable,
CreateStatsTableLocked, CreateTTLTableStatus, CreateTTLTask,
CreateTTLJobHistory, CreateGlobalTask, CreateLoadDataJobs,
}
)

// bootstrap initiates system DB for a store.
Expand Down Expand Up @@ -613,7 +640,7 @@ func bootstrap(s Session) {
// To reduce conflict when multiple TiDB-server start at the same time.
// Actually only one server need to do the bootstrap. So we chose DDL owner to do this.
if dom.DDL().OwnerManager().IsOwner() {
doDDLWorks(s)
doDDLWorks(s, dom)
doDMLWorks(s)
runBootstrapSQLFile = true
logutil.BgLogger().Info("bootstrap successful",
Expand Down Expand Up @@ -1747,11 +1774,6 @@ func upgradeToVer57(s Session, ver int64) {
insertBuiltinBindInfoRow(s)
}

func initBindInfoTable(s Session) {
mustExecute(s, CreateBindInfoTable)
insertBuiltinBindInfoRow(s)
}

func insertBuiltinBindInfoRow(s Session) {
mustExecute(s, `INSERT HIGH_PRIORITY INTO mysql.bind_info(original_sql, bind_sql, default_db, status, create_time, update_time, charset, collation, source)
VALUES (%?, %?, "mysql", %?, "0000-00-00 00:00:00", "0000-00-00 00:00:00", "", "", %?)`,
Expand Down Expand Up @@ -2460,94 +2482,74 @@ func getBootstrapVersion(s Session) (int64, error) {
}

// doDDLWorks executes DDL statements in bootstrap stage.
func doDDLWorks(s Session) {
func doDDLWorks(s Session, dom *domain.Domain) {
// Create a test database.
mustExecute(s, "CREATE DATABASE IF NOT EXISTS test")
// Create system db.
mustExecute(s, "CREATE DATABASE IF NOT EXISTS %n", mysql.SystemDB)
// Create user table.
mustExecute(s, CreateUserTable)
// Create password history.
mustExecute(s, CreatePasswordHistory)
// Create privilege tables.
mustExecute(s, CreateGlobalPrivTable)
mustExecute(s, CreateDBPrivTable)
mustExecute(s, CreateTablePrivTable)
mustExecute(s, CreateColumnPrivTable)
// Create global system variable table.
mustExecute(s, CreateGlobalVariablesTable)
// Create TiDB table.
mustExecute(s, CreateTiDBTable)
// Create help table.
mustExecute(s, CreateHelpTopic)
// Create stats_meta table.
mustExecute(s, CreateStatsMetaTable)
// Create stats_columns table.
mustExecute(s, CreateStatsColsTable)
// Create stats_buckets table.
mustExecute(s, CreateStatsBucketsTable)
// Create gc_delete_range table.
mustExecute(s, CreateGCDeleteRangeTable)
// Create gc_delete_range_done table.
mustExecute(s, CreateGCDeleteRangeDoneTable)
// Create stats_feedback table.
mustExecute(s, CreateStatsFeedbackTable)
// Create role_edges table.
mustExecute(s, CreateRoleEdgesTable)
// Create default_roles table.
mustExecute(s, CreateDefaultRolesTable)
// Create bind_info table.
initBindInfoTable(s)
// Create stats_topn_store table.
mustExecute(s, CreateStatsTopNTable)
// Create expr_pushdown_blacklist table.
mustExecute(s, CreateExprPushdownBlacklist)
// Create opt_rule_blacklist table.
mustExecute(s, CreateOptRuleBlacklist)
// Create stats_extended table.
mustExecute(s, CreateStatsExtended)
// Create schema_index_usage.
mustExecute(s, CreateSchemaIndexUsageTable)
// Create stats_fm_sketch table.
mustExecute(s, CreateStatsFMSketchTable)
// Create global_grants
mustExecute(s, CreateGlobalGrantsTable)
// Create capture_plan_baselines_blacklist
mustExecute(s, CreateCapturePlanBaselinesBlacklist)
// Create column_stats_usage table
mustExecute(s, CreateColumnStatsUsageTable)
// Create table_cache_meta table.
mustExecute(s, CreateTableCacheMetaTable)
// Create analyze_options table.
mustExecute(s, CreateAnalyzeOptionsTable)
// Create stats_history table.
mustExecute(s, CreateStatsHistory)
// Create stats_meta_history table.
mustExecute(s, CreateStatsMetaHistory)
// Create analyze_jobs table.
mustExecute(s, CreateAnalyzeJobs)
// Create advisory_locks table.
mustExecute(s, CreateAdvisoryLocks)
// Create mdl view.
p := parser.New()
tableInfosPart1 := make([]*model.TableInfo, 0, len(allCreateTablesPart1))
for _, createTable := range allCreateTablesPart1 {
stmt, err := p.ParseOneStmt(createTable, "", "")
if err != nil {
logutil.BgLogger().Fatal("ParseOneStmt error", zap.Error(err), zap.Stack("stack"))
}
tblInfo, err := ddl.BuildTableInfoWithContext(s, stmt.(*ast.CreateTableStmt))
if err != nil {
logutil.BgLogger().Fatal("BuildTableInfoFromAST error", zap.Error(err), zap.Stack("stack"))
}
tableInfosPart1 = append(tableInfosPart1, tblInfo)
}
batchCreateTable(s, dom.DDL(), tableInfosPart1)
mustExecute(s, CreateMDLView)
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

So why CreateMDLView is skipped?

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

98b8e9e

add comment

// Create plan_replayer_status table
mustExecute(s, CreatePlanReplayerStatusTable)
// Create plan_replayer_task table
mustExecute(s, CreatePlanReplayerTaskTable)
// Create stats_meta_table_locked table
mustExecute(s, CreateStatsTableLocked)
// Create tidb_ttl_table_status table
mustExecute(s, CreateTTLTableStatus)
// Create tidb_ttl_task table
mustExecute(s, CreateTTLTask)
// Create tidb_ttl_job_history table
mustExecute(s, CreateTTLJobHistory)
// Create tidb_global_task table
mustExecute(s, CreateGlobalTask)
tableInfosPart2 := make([]*model.TableInfo, 0, len(allCreateTablesPart2))
for _, createTable := range allCreateTablesPart2 {
stmt, err := p.ParseOneStmt(createTable, "", "")
if err != nil {
logutil.BgLogger().Fatal("ParseOneStmt error", zap.Error(err), zap.Stack("stack"))
}
tblInfo, err := ddl.BuildTableInfoWithContext(s, stmt.(*ast.CreateTableStmt))
if err != nil {
logutil.BgLogger().Fatal("BuildTableInfoFromAST error", zap.Error(err), zap.Stack("stack"))
}
tableInfosPart2 = append(tableInfosPart2, tblInfo)
}
batchCreateTable(s, dom.DDL(), tableInfosPart2)

err := dom.Reload()
if err != nil {
logutil.BgLogger().Fatal("Reload error", zap.Error(err), zap.Stack("stack"))
}

// init bind_info table.
insertBuiltinBindInfoRow(s)
// Create default resource group
mustExecute(s, CreateDefaultResourceGroup)
// Create load_data_jobs
mustExecute(s, CreateLoadDataJobs)
}

func batchCreateTable(s Session, d ddl.DDL, tableInfos []*model.TableInfo) {
s.SetValue(sessionctx.QueryString, "skip")

err := d.BatchCreateTableWithInfo(
s,
model.NewCIStr(mysql.SystemDB),
tableInfos,
ddl.OnExistIgnore,
ddl.SkipTableID(1),
)
if err == nil {
return
}
if kv.ErrEntryTooLarge.Equal(err) {
if len(tableInfos) == 1 {
logutil.BgLogger().Fatal("too large TableInfo", zap.Any("tableInfo", tableInfos[0]), zap.Stack("stack"))
}
mid := len(tableInfos) / 2
batchCreateTable(s, d, tableInfos[:mid])
batchCreateTable(s, d, tableInfos[mid:])
} else {
logutil.BgLogger().Fatal("batchCreateTable meet error", zap.Error(err), zap.Stack("stack"))
}
}

// doBootstrapSQLFile executes SQL commands in a file as the last stage of bootstrap.
Expand Down
2 changes: 1 addition & 1 deletion session/bootstrap_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -164,7 +164,7 @@ func TestBootstrapWithError(t *testing.T) {
b, err := checkBootstrapped(se)
require.False(t, b)
require.NoError(t, err)
doDDLWorks(se)
doDDLWorks(se, dom)
}

dom, err := domap.Get(store)
Expand Down