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  }