github.com/pingcap/br@v5.3.0-alpha.0.20220125034240-ec59c7b6ce30+incompatible/pkg/gluetidb/glue.go (about) 1 // Copyright 2020 PingCAP, Inc. Licensed under Apache-2.0. 2 3 package gluetidb 4 5 import ( 6 "bytes" 7 "context" 8 9 "github.com/pingcap/errors" 10 "github.com/pingcap/log" 11 "github.com/pingcap/parser/model" 12 "github.com/pingcap/parser/mysql" 13 "github.com/pingcap/tidb/config" 14 "github.com/pingcap/tidb/ddl" 15 "github.com/pingcap/tidb/domain" 16 "github.com/pingcap/tidb/executor" 17 "github.com/pingcap/tidb/kv" 18 "github.com/pingcap/tidb/meta/autoid" 19 "github.com/pingcap/tidb/session" 20 "github.com/pingcap/tidb/sessionctx" 21 pd "github.com/tikv/pd/client" 22 23 "github.com/pingcap/br/pkg/glue" 24 "github.com/pingcap/br/pkg/gluetikv" 25 ) 26 27 const ( 28 defaultCapOfCreateTable = 512 29 defaultCapOfCreateDatabase = 64 30 brComment = `/*from(br)*/` 31 ) 32 33 // New makes a new tidb glue. 34 func New() Glue { 35 log.Debug("enabling no register config") 36 config.UpdateGlobal(func(conf *config.Config) { 37 conf.SkipRegisterToDashboard = true 38 }) 39 return Glue{} 40 } 41 42 // Glue is an implementation of glue.Glue using a new TiDB session. 43 type Glue struct { 44 tikvGlue gluetikv.Glue 45 } 46 47 type tidbSession struct { 48 se session.Session 49 } 50 51 // GetDomain implements glue.Glue. 52 func (Glue) GetDomain(store kv.Storage) (*domain.Domain, error) { 53 se, err := session.CreateSession(store) 54 if err != nil { 55 return nil, errors.Trace(err) 56 } 57 dom, err := session.GetDomain(store) 58 if err != nil { 59 return nil, errors.Trace(err) 60 } 61 // create stats handler for backup and restore. 62 err = dom.UpdateTableStatsLoop(se) 63 if err != nil { 64 return nil, errors.Trace(err) 65 } 66 return dom, nil 67 } 68 69 // CreateSession implements glue.Glue. 70 func (Glue) CreateSession(store kv.Storage) (glue.Session, error) { 71 se, err := session.CreateSession(store) 72 if err != nil { 73 return nil, errors.Trace(err) 74 } 75 tiSession := &tidbSession{ 76 se: se, 77 } 78 return tiSession, nil 79 } 80 81 // Open implements glue.Glue. 82 func (g Glue) Open(path string, option pd.SecurityOption) (kv.Storage, error) { 83 return g.tikvGlue.Open(path, option) 84 } 85 86 // OwnsStorage implements glue.Glue. 87 func (Glue) OwnsStorage() bool { 88 return true 89 } 90 91 // StartProgress implements glue.Glue. 92 func (g Glue) StartProgress(ctx context.Context, cmdName string, total int64, redirectLog bool) glue.Progress { 93 return g.tikvGlue.StartProgress(ctx, cmdName, total, redirectLog) 94 } 95 96 // Record implements glue.Glue. 97 func (g Glue) Record(name string, value uint64) { 98 g.tikvGlue.Record(name, value) 99 } 100 101 // GetVersion implements glue.Glue. 102 func (g Glue) GetVersion() string { 103 return g.tikvGlue.GetVersion() 104 } 105 106 // Execute implements glue.Session. 107 func (gs *tidbSession) Execute(ctx context.Context, sql string) error { 108 _, err := gs.se.ExecuteInternal(ctx, sql) 109 return errors.Trace(err) 110 } 111 112 // CreateDatabase implements glue.Session. 113 func (gs *tidbSession) CreateDatabase(ctx context.Context, schema *model.DBInfo) error { 114 d := domain.GetDomain(gs.se).DDL() 115 query, err := gs.showCreateDatabase(schema) 116 if err != nil { 117 return errors.Trace(err) 118 } 119 gs.se.SetValue(sessionctx.QueryString, query) 120 schema = schema.Clone() 121 if len(schema.Charset) == 0 { 122 schema.Charset = mysql.DefaultCharset 123 } 124 return d.CreateSchemaWithInfo(gs.se, schema, ddl.OnExistIgnore, true) 125 } 126 127 // CreateTable implements glue.Session. 128 func (gs *tidbSession) CreateTable(ctx context.Context, dbName model.CIStr, table *model.TableInfo) error { 129 d := domain.GetDomain(gs.se).DDL() 130 query, err := gs.showCreateTable(table) 131 if err != nil { 132 return errors.Trace(err) 133 } 134 gs.se.SetValue(sessionctx.QueryString, query) 135 // Clone() does not clone partitions yet :( 136 table = table.Clone() 137 if table.Partition != nil { 138 newPartition := *table.Partition 139 newPartition.Definitions = append([]model.PartitionDefinition{}, table.Partition.Definitions...) 140 table.Partition = &newPartition 141 } 142 return d.CreateTableWithInfo(gs.se, dbName, table, ddl.OnExistIgnore, true) 143 } 144 145 // Close implements glue.Session. 146 func (gs *tidbSession) Close() { 147 gs.se.Close() 148 } 149 150 // showCreateTable shows the result of SHOW CREATE TABLE from a TableInfo. 151 func (gs *tidbSession) showCreateTable(tbl *model.TableInfo) (string, error) { 152 table := tbl.Clone() 153 table.AutoIncID = 0 154 result := bytes.NewBuffer(make([]byte, 0, defaultCapOfCreateTable)) 155 // this can never fail. 156 _, _ = result.WriteString(brComment) 157 if err := executor.ConstructResultOfShowCreateTable(gs.se, tbl, autoid.Allocators{}, result); err != nil { 158 return "", errors.Trace(err) 159 } 160 return result.String(), nil 161 } 162 163 // showCreateDatabase shows the result of SHOW CREATE DATABASE from a dbInfo. 164 func (gs *tidbSession) showCreateDatabase(db *model.DBInfo) (string, error) { 165 result := bytes.NewBuffer(make([]byte, 0, defaultCapOfCreateDatabase)) 166 // this can never fail. 167 _, _ = result.WriteString(brComment) 168 if err := executor.ConstructResultOfShowCreateDatabase(gs.se, db, true, result); err != nil { 169 return "", errors.Trace(err) 170 } 171 return result.String(), nil 172 }