Skip to content

Commit

Permalink
Merge branch 'master' into multi_key_pk_ttl
Browse files Browse the repository at this point in the history
  • Loading branch information
lcwangchao authored Dec 14, 2022
2 parents 6034d8d + d2eca72 commit 12c81a6
Show file tree
Hide file tree
Showing 18 changed files with 261 additions and 73 deletions.
2 changes: 1 addition & 1 deletion br/COMPATIBILITY_TEST.md
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,7 @@
## Background

We had some incompatibility issues in the past, which made BR cannot restore backed up data in some situations.
So we need a test workflow to check the compatiblity.
So we need a test workflow to check the compatibility.

## Goal

Expand Down
2 changes: 1 addition & 1 deletion docs/design/2019-11-05-index-advisor.md
Original file line number Diff line number Diff line change
Expand Up @@ -57,7 +57,7 @@ for {
Note that executing `Swap and Re-evaluate` algorithm is necessary as the `reduced_cost` sometimes is a joint effect of several indexes and it's hard to tell each index's independent contribution to the final `reduced_cost`. For example, assume there is an extremely slow query in input workload and the desired indexes for this query is `a` and `b`. However, the number of allowed recommended indexes for the whole workload is limited and for some reason, `a` ranks top `n` in the final score list while `b` is not. But there are chances that without `b`, `a` can no more optimize that extremely slow query.

----------------------------------------------
### A quick exmaple for single-column index recommendation
### A quick example for single-column index recommendation

**Workload**:

Expand Down
2 changes: 1 addition & 1 deletion docs/design/2020-01-24-collations.md
Original file line number Diff line number Diff line change
Expand Up @@ -233,7 +233,7 @@ The following features of the general collation algorithm will be supported:
* Tertiary Weight i.e. case
* PAD / NOPAD

All of them are supported by `text/collate` package of Go, so it is possible to map Go collations to some of UCA-based collations in MySQL like `utf8mb4_unicode_ci`/`utf8mb4_0900_ai_ci`, if we ignore the differences between UCA versions: current `text/collate` uses UCA version `6.2.0` and it is not changable. However, the collations in MySQL are with different UCA versions marked in the names, for example, `utf8mb4_0900_ai_ci` uses version `9.0`.
All of them are supported by `text/collate` package of Go, so it is possible to map Go collations to some of UCA-based collations in MySQL like `utf8mb4_unicode_ci`/`utf8mb4_0900_ai_ci`, if we ignore the differences between UCA versions: current `text/collate` uses UCA version `6.2.0` and it is not changeable. However, the collations in MySQL are with different UCA versions marked in the names, for example, `utf8mb4_0900_ai_ci` uses version `9.0`.

For non-standard UCA implementations in MySQL, i.e. the `utf8mb4_general_ci`. The implementation depends on our choice to the [Compatibility with MySQL](#compatibility-with-mysql) chapter, if a 100% compatibility of `utf8mb4_general_ci` is chosen, we need to implement it by our hands.

Expand Down
1 change: 1 addition & 0 deletions domain/plan_replayer.go
Original file line number Diff line number Diff line change
Expand Up @@ -527,6 +527,7 @@ type PlanReplayerDumpTask struct {
TblStats map[int64]interface{}

// variables used to dump the plan
StartTS uint64
SessionBindings []*bindinfo.BindRecord
EncodedPlan string
SessionVars *variable.SessionVars
Expand Down
42 changes: 37 additions & 5 deletions domain/plan_replayer_dump.go
Original file line number Diff line number Diff line change
Expand Up @@ -41,6 +41,8 @@ import (
)

const (
// planReplayerSQLMeta indicates sql meta path for plan replayer
planReplayerSQLMeta = "sql_meta.toml"
// PlanReplayerConfigFile indicates config file path for plan replayer
PlanReplayerConfigFile = "config.toml"
// PlanReplayerMetaFile meta file path for plan replayer
Expand All @@ -55,6 +57,11 @@ const (
PlanReplayerGlobalBindingFile = "global_bindings.sql"
)

const (
// PlanReplayerSQLMetaStartTS indicates the startTS in plan replayer sql meta
PlanReplayerSQLMetaStartTS = "startTS"
)

type tableNamePair struct {
DBName string
TableName string
Expand Down Expand Up @@ -131,6 +138,7 @@ func (tne *tableNameExtractor) handleIsView(t *ast.TableName) (bool, error) {
// DumpPlanReplayerInfo will dump the information about sqls.
// The files will be organized into the following format:
/*
|-sql_meta.toml
|-meta.txt
|-schema
| |-db1.table1.schema.txt
Expand Down Expand Up @@ -164,7 +172,7 @@ func DumpPlanReplayerInfo(ctx context.Context, sctx sessionctx.Context,
sessionVars := task.SessionVars
execStmts := task.ExecStmts
zw := zip.NewWriter(zf)
records := generateRecords(task)
var records []PlanReplayerStatusRecord
defer func() {
if err != nil {
logutil.BgLogger().Error("dump plan replayer failed", zap.Error(err))
Expand All @@ -183,6 +191,12 @@ func DumpPlanReplayerInfo(ctx context.Context, sctx sessionctx.Context,
}
insertPlanReplayerStatus(ctx, sctx, records)
}()

// Dump SQLMeta
if err = dumpSQLMeta(zw, task); err != nil {
return err
}

// Dump config
if err = dumpConfig(zw); err != nil {
return err
Expand Down Expand Up @@ -244,10 +258,11 @@ func DumpPlanReplayerInfo(ctx context.Context, sctx sessionctx.Context,
}

if len(task.EncodedPlan) > 0 {
records = generateRecords(task)
return dumpEncodedPlan(sctx, zw, task.EncodedPlan)
}
// Dump explain
return dumpExplain(sctx, zw, execStmts, task.Analyze)
return dumpExplain(sctx, zw, task, &records)
}

func generateRecords(task *PlanReplayerDumpTask) []PlanReplayerStatusRecord {
Expand All @@ -265,6 +280,19 @@ func generateRecords(task *PlanReplayerDumpTask) []PlanReplayerStatusRecord {
return records
}

func dumpSQLMeta(zw *zip.Writer, task *PlanReplayerDumpTask) error {
cf, err := zw.Create(planReplayerSQLMeta)
if err != nil {
return errors.AddStack(err)
}
varMap := make(map[string]string)
varMap[PlanReplayerSQLMetaStartTS] = strconv.FormatUint(task.StartTS, 10)
if err := toml.NewEncoder(cf).Encode(varMap); err != nil {
return errors.AddStack(err)
}
return nil
}

func dumpConfig(zw *zip.Writer) error {
cf, err := zw.Create(PlanReplayerConfigFile)
if err != nil {
Expand Down Expand Up @@ -488,12 +516,12 @@ func dumpEncodedPlan(ctx sessionctx.Context, zw *zip.Writer, encodedPlan string)
return nil
}

func dumpExplain(ctx sessionctx.Context, zw *zip.Writer, execStmts []ast.StmtNode, isAnalyze bool) error {
for i, stmtExec := range execStmts {
func dumpExplain(ctx sessionctx.Context, zw *zip.Writer, task *PlanReplayerDumpTask, records *[]PlanReplayerStatusRecord) error {
for i, stmtExec := range task.ExecStmts {
sql := stmtExec.Text()
var recordSets []sqlexec.RecordSet
var err error
if isAnalyze {
if task.Analyze {
// Explain analyze
recordSets, err = ctx.(sqlexec.SQLExecutor).Execute(context.Background(), fmt.Sprintf("explain analyze %s", sql))
if err != nil {
Expand Down Expand Up @@ -522,6 +550,10 @@ func dumpExplain(ctx sessionctx.Context, zw *zip.Writer, execStmts []ast.StmtNod
return err
}
}
*records = append(*records, PlanReplayerStatusRecord{
OriginSQL: sql,
Token: task.FileName,
})
}
return nil
}
Expand Down
13 changes: 9 additions & 4 deletions executor/compiler.go
Original file line number Diff line number Diff line change
Expand Up @@ -157,13 +157,17 @@ func (c *Compiler) Compile(ctx context.Context, stmtNode ast.StmtNode) (_ *ExecS
}
}
if c.Ctx.GetSessionVars().EnablePlanReplayerCapture && !c.Ctx.GetSessionVars().InRestrictedSQL {
checkPlanReplayerCaptureTask(c.Ctx, stmtNode)
startTS, err := sessiontxn.GetTxnManager(c.Ctx).GetStmtReadTS()
if err != nil {
return nil, err
}
checkPlanReplayerCaptureTask(c.Ctx, stmtNode, startTS)
}

return stmt, nil
}

func checkPlanReplayerCaptureTask(sctx sessionctx.Context, stmtNode ast.StmtNode) {
func checkPlanReplayerCaptureTask(sctx sessionctx.Context, stmtNode ast.StmtNode, startTS uint64) {
dom := domain.GetDomain(sctx)
if dom == nil {
return
Expand All @@ -178,21 +182,22 @@ func checkPlanReplayerCaptureTask(sctx sessionctx.Context, stmtNode ast.StmtNode
for _, task := range tasks {
if task.SQLDigest == sqlDigest.String() {
if task.PlanDigest == "*" || task.PlanDigest == planDigest.String() {
sendPlanReplayerDumpTask(sqlDigest.String(), planDigest.String(), sctx, stmtNode)
sendPlanReplayerDumpTask(sqlDigest.String(), planDigest.String(), sctx, stmtNode, startTS)
return
}
}
}
}

func sendPlanReplayerDumpTask(sqlDigest, planDigest string, sctx sessionctx.Context, stmtNode ast.StmtNode) {
func sendPlanReplayerDumpTask(sqlDigest, planDigest string, sctx sessionctx.Context, stmtNode ast.StmtNode, startTS uint64) {
stmtCtx := sctx.GetSessionVars().StmtCtx
handle := sctx.Value(bindinfo.SessionBindInfoKeyType).(*bindinfo.SessionHandle)
dumpTask := &domain.PlanReplayerDumpTask{
PlanReplayerTaskKey: domain.PlanReplayerTaskKey{
SQLDigest: sqlDigest,
PlanDigest: planDigest,
},
StartTS: startTS,
EncodePlan: GetEncodedPlan,
TblStats: stmtCtx.TableStats,
SessionBindings: handle.GetAllBindRecord(),
Expand Down
1 change: 1 addition & 0 deletions executor/executor.go
Original file line number Diff line number Diff line change
Expand Up @@ -2167,6 +2167,7 @@ func ResetContextOfStmt(ctx sessionctx.Context, s ast.StmtNode) (err error) {
vars.ClearStmtVars()
vars.PrevFoundInBinding = vars.FoundInBinding
vars.FoundInBinding = false
vars.DurationWaitTS = 0
return
}

Expand Down
1 change: 1 addition & 0 deletions executor/executor_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -87,6 +87,7 @@ func checkFileName(s string) bool {
"global_bindings.sql",
"sql/sql0.sql",
"explain/sql0.txt",
"sql_meta.toml",
}
for _, f := range files {
if strings.Compare(f, s) == 0 {
Expand Down
22 changes: 15 additions & 7 deletions executor/plan_replayer.go
Original file line number Diff line number Diff line change
Expand Up @@ -31,6 +31,7 @@ import (
"github.com/pingcap/tidb/parser/ast"
"github.com/pingcap/tidb/sessionctx"
"github.com/pingcap/tidb/sessionctx/variable"
"github.com/pingcap/tidb/sessiontxn"
"github.com/pingcap/tidb/statistics/handle"
"github.com/pingcap/tidb/util/chunk"
"github.com/pingcap/tidb/util/logutil"
Expand Down Expand Up @@ -133,7 +134,12 @@ func (e *PlanReplayerExec) createFile() error {
func (e *PlanReplayerDumpInfo) dump(ctx context.Context) (err error) {
fileName := e.FileName
zf := e.File
startTS, err := sessiontxn.GetTxnManager(e.ctx).GetStmtReadTS()
if err != nil {
return err
}
task := &domain.PlanReplayerDumpTask{
StartTS: startTS,
FileName: fileName,
Zf: zf,
SessionVars: e.ctx.GetSessionVars(),
Expand Down Expand Up @@ -375,21 +381,23 @@ func createSchemaAndItems(ctx sessionctx.Context, f *zip.File) error {
if err != nil {
return errors.AddStack(err)
}
sqls := strings.Split(buf.String(), ";")
if len(sqls) != 3 {
return errors.New("plan replayer: create schema and tables failed")
}
originText := buf.String()
index1 := strings.Index(originText, ";")
createDatabaseSQL := originText[:index1+1]
index2 := strings.Index(originText[index1+1:], ";")
useDatabaseSQL := originText[index1+1:][:index2+1]
createTableSQL := originText[index1+1:][index2+1:]
c := context.Background()
// create database if not exists
_, err = ctx.(sqlexec.SQLExecutor).Execute(c, sqls[0])
_, err = ctx.(sqlexec.SQLExecutor).Execute(c, createDatabaseSQL)
logutil.BgLogger().Debug("plan replayer: skip error", zap.Error(err))
// use database
_, err = ctx.(sqlexec.SQLExecutor).Execute(c, sqls[1])
_, err = ctx.(sqlexec.SQLExecutor).Execute(c, useDatabaseSQL)
if err != nil {
return err
}
// create table or view
_, err = ctx.(sqlexec.SQLExecutor).Execute(c, sqls[2])
_, err = ctx.(sqlexec.SQLExecutor).Execute(c, createTableSQL)
if err != nil {
return err
}
Expand Down
86 changes: 50 additions & 36 deletions session/session.go
Original file line number Diff line number Diff line change
Expand Up @@ -3055,22 +3055,21 @@ func loadCollationParameter(ctx context.Context, se *session) (bool, error) {
return false, nil
}

type tableBasicInfo struct {
SQL string
id int64
}

var (
errResultIsEmpty = dbterror.ClassExecutor.NewStd(errno.ErrResultIsEmpty)
// DDLJobTables is a list of tables definitions used in concurrent DDL.
DDLJobTables = []struct {
SQL string
id int64
}{
DDLJobTables = []tableBasicInfo{
{ddl.JobTableSQL, ddl.JobTableID},
{ddl.ReorgTableSQL, ddl.ReorgTableID},
{ddl.HistoryTableSQL, ddl.HistoryTableID},
}
// BackfillTables is a list of tables definitions used in dist reorg DDL.
BackfillTables = []struct {
SQL string
id int64
}{
BackfillTables = []tableBasicInfo{
{ddl.BackfillTableSQL, ddl.BackfillTableID},
{ddl.BackfillHistoryTableSQL, ddl.BackfillHistoryTableID},
}
Expand All @@ -3091,7 +3090,7 @@ func splitAndScatterTable(store kv.Storage, tableIDs []int64) {
}
}

// InitDDLJobTables is to create tidb_ddl_job, tidb_ddl_reorg and tidb_ddl_history, or tidb_ddl_backfill and tidb_ddl_backfill_history.
// 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 {
return kv.RunInNewTxn(kv.WithInternalSourceType(context.Background(), kv.InternalTxnDDL), store, true, func(ctx context.Context, txn kv.Transaction) error {
t := meta.NewMeta(txn)
Expand All @@ -3103,41 +3102,56 @@ func InitDDLJobTables(store kv.Storage) error {
if err != nil {
return err
}
tables := append(DDLJobTables, BackfillTables...)
if exists {
tblExist, err := t.CheckTableExists(dbID, BackfillTables[0].id)
if err != nil || tblExist {
return errors.Trace(err)
}
tables = BackfillTables
return initBackfillJobTables(store, t, dbID)
}
tableIDs := make([]int64, 0, len(tables))
for _, tbl := range tables {
tableIDs = append(tableIDs, tbl.id)

if err = createAndSplitTables(store, t, dbID, DDLJobTables); err != nil {
return err
}
splitAndScatterTable(store, tableIDs)
p := parser.New()
for _, tbl := range tables {
stmt, err := p.ParseOneStmt(tbl.SQL, "", "")
if err != nil {
return errors.Trace(err)
}
tblInfo, err := ddl.BuildTableInfoFromAST(stmt.(*ast.CreateTableStmt))
if err != nil {
return errors.Trace(err)
}
tblInfo.State = model.StatePublic
tblInfo.ID = tbl.id
tblInfo.UpdateTS = t.StartTS
err = t.CreateTableOrView(dbID, tblInfo)
if err != nil {
return errors.Trace(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 {
tableIDs = append(tableIDs, tbl.id)
}
splitAndScatterTable(store, tableIDs)
p := parser.New()
for _, tbl := range tables {
stmt, err := p.ParseOneStmt(tbl.SQL, "", "")
if err != nil {
return errors.Trace(err)
}
tblInfo, err := ddl.BuildTableInfoFromAST(stmt.(*ast.CreateTableStmt))
if err != nil {
return errors.Trace(err)
}
tblInfo.State = model.StatePublic
tblInfo.ID = tbl.id
tblInfo.UpdateTS = t.StartTS
err = t.CreateTableOrView(dbID, tblInfo)
if err != nil {
return errors.Trace(err)
}
}
return nil
}

// InitMDLTable is to create tidb_mdl_info, which is used for metadata lock.
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 {
Expand Down
Loading

0 comments on commit 12c81a6

Please sign in to comment.