github.com/pingcap/br@v5.3.0-alpha.0.20220125034240-ec59c7b6ce30+incompatible/pkg/restore/db_test.go (about)

     1  // Copyright 2020 PingCAP, Inc. Licensed under Apache-2.0.
     2  
     3  package restore_test
     4  
     5  import (
     6  	"context"
     7  	"encoding/json"
     8  	"math"
     9  	"strconv"
    10  	"testing"
    11  
    12  	"github.com/golang/protobuf/proto"
    13  	backuppb "github.com/pingcap/kvproto/pkg/backup"
    14  
    15  	"github.com/pingcap/br/pkg/metautil"
    16  	"github.com/pingcap/br/pkg/storage"
    17  
    18  	. "github.com/pingcap/check"
    19  	"github.com/pingcap/parser/model"
    20  	"github.com/pingcap/tidb/meta/autoid"
    21  	"github.com/pingcap/tidb/util/testkit"
    22  	"github.com/pingcap/tidb/util/testleak"
    23  	"github.com/tikv/client-go/v2/oracle"
    24  
    25  	"github.com/pingcap/br/pkg/backup"
    26  	"github.com/pingcap/br/pkg/gluetidb"
    27  	"github.com/pingcap/br/pkg/mock"
    28  	"github.com/pingcap/br/pkg/restore"
    29  )
    30  
    31  func TestT(t *testing.T) {
    32  	TestingT(t)
    33  }
    34  
    35  var _ = Suite(&testRestoreSchemaSuite{})
    36  
    37  type testRestoreSchemaSuite struct {
    38  	mock    *mock.Cluster
    39  	storage storage.ExternalStorage
    40  }
    41  
    42  func (s *testRestoreSchemaSuite) SetUpSuite(c *C) {
    43  	var err error
    44  	s.mock, err = mock.NewCluster()
    45  	c.Assert(err, IsNil)
    46  	base := c.MkDir()
    47  	s.storage, err = storage.NewLocalStorage(base)
    48  	c.Assert(err, IsNil)
    49  	c.Assert(s.mock.Start(), IsNil)
    50  }
    51  
    52  func (s *testRestoreSchemaSuite) TearDownSuite(c *C) {
    53  	s.mock.Stop()
    54  	testleak.AfterTest(c)()
    55  }
    56  
    57  func (s *testRestoreSchemaSuite) TestRestoreAutoIncID(c *C) {
    58  	tk := testkit.NewTestKit(c, s.mock.Storage)
    59  	tk.MustExec("use test")
    60  	tk.MustExec("set @@sql_mode=''")
    61  	tk.MustExec("drop table if exists `\"t\"`;")
    62  	// Test SQL Mode
    63  	tk.MustExec("create table `\"t\"` (" +
    64  		"a int not null," +
    65  		"time timestamp not null default '0000-00-00 00:00:00');",
    66  	)
    67  	tk.MustExec("insert into `\"t\"` values (10, '0000-00-00 00:00:00');")
    68  	// Query the current AutoIncID
    69  	autoIncID, err := strconv.ParseUint(tk.MustQuery("admin show `\"t\"` next_row_id").Rows()[0][3].(string), 10, 64)
    70  	c.Assert(err, IsNil, Commentf("Error query auto inc id: %s", err))
    71  	// Get schemas of db and table
    72  	info, err := s.mock.Domain.GetSnapshotInfoSchema(math.MaxUint64)
    73  	c.Assert(err, IsNil, Commentf("Error get snapshot info schema: %s", err))
    74  	dbInfo, exists := info.SchemaByName(model.NewCIStr("test"))
    75  	c.Assert(exists, IsTrue, Commentf("Error get db info"))
    76  	tableInfo, err := info.TableByName(model.NewCIStr("test"), model.NewCIStr("\"t\""))
    77  	c.Assert(err, IsNil, Commentf("Error get table info: %s", err))
    78  	table := metautil.Table{
    79  		Info: tableInfo.Meta(),
    80  		DB:   dbInfo,
    81  	}
    82  	// Get the next AutoIncID
    83  	idAlloc := autoid.NewAllocator(s.mock.Storage, dbInfo.ID, false, autoid.RowIDAllocType)
    84  	globalAutoID, err := idAlloc.NextGlobalAutoID(table.Info.ID)
    85  	c.Assert(err, IsNil, Commentf("Error allocate next auto id"))
    86  	c.Assert(autoIncID, Equals, uint64(globalAutoID))
    87  	// Alter AutoIncID to the next AutoIncID + 100
    88  	table.Info.AutoIncID = globalAutoID + 100
    89  	db, err := restore.NewDB(gluetidb.New(), s.mock.Storage)
    90  	c.Assert(err, IsNil, Commentf("Error create DB"))
    91  	tk.MustExec("drop database if exists test;")
    92  	// Test empty collate value
    93  	table.DB.Charset = "utf8mb4"
    94  	table.DB.Collate = ""
    95  	err = db.CreateDatabase(context.Background(), table.DB)
    96  	c.Assert(err, IsNil, Commentf("Error create empty collate db: %s %s", err, s.mock.DSN))
    97  	tk.MustExec("drop database if exists test;")
    98  	// Test empty charset value
    99  	table.DB.Charset = ""
   100  	table.DB.Collate = "utf8mb4_bin"
   101  	err = db.CreateDatabase(context.Background(), table.DB)
   102  	c.Assert(err, IsNil, Commentf("Error create empty charset db: %s %s", err, s.mock.DSN))
   103  	err = db.CreateTable(context.Background(), &table)
   104  	c.Assert(err, IsNil, Commentf("Error create table: %s %s", err, s.mock.DSN))
   105  	tk.MustExec("use test")
   106  	// Check if AutoIncID is altered successfully
   107  	autoIncID, err = strconv.ParseUint(tk.MustQuery("admin show `\"t\"` next_row_id").Rows()[0][3].(string), 10, 64)
   108  	c.Assert(err, IsNil, Commentf("Error query auto inc id: %s", err))
   109  	c.Assert(autoIncID, Equals, uint64(globalAutoID+100))
   110  }
   111  
   112  func (s *testRestoreSchemaSuite) TestFilterDDLJobs(c *C) {
   113  	tk := testkit.NewTestKit(c, s.mock.Storage)
   114  	tk.MustExec("CREATE DATABASE IF NOT EXISTS test_db;")
   115  	tk.MustExec("CREATE TABLE IF NOT EXISTS test_db.test_table (c1 INT);")
   116  	lastTS, err := s.mock.GetOracle().GetTimestamp(context.Background(), &oracle.Option{TxnScope: oracle.GlobalTxnScope})
   117  	c.Assert(err, IsNil, Commentf("Error get last ts: %s", err))
   118  	tk.MustExec("RENAME TABLE test_db.test_table to test_db.test_table1;")
   119  	tk.MustExec("DROP TABLE test_db.test_table1;")
   120  	tk.MustExec("DROP DATABASE test_db;")
   121  	tk.MustExec("CREATE DATABASE test_db;")
   122  	tk.MustExec("USE test_db;")
   123  	tk.MustExec("CREATE TABLE test_table1 (c2 CHAR(255));")
   124  	tk.MustExec("RENAME TABLE test_table1 to test_table;")
   125  	tk.MustExec("TRUNCATE TABLE test_table;")
   126  
   127  	ts, err := s.mock.GetOracle().GetTimestamp(context.Background(), &oracle.Option{TxnScope: oracle.GlobalTxnScope})
   128  	c.Assert(err, IsNil, Commentf("Error get ts: %s", err))
   129  
   130  	metaWriter := metautil.NewMetaWriter(s.storage, metautil.MetaFileSize, false)
   131  	ctx := context.Background()
   132  	metaWriter.StartWriteMetasAsync(ctx, metautil.AppendDDL)
   133  	err = backup.WriteBackupDDLJobs(metaWriter, s.mock.Storage, lastTS, ts)
   134  	c.Assert(err, IsNil, Commentf("Error get ddl jobs: %s", err))
   135  	err = metaWriter.FinishWriteMetas(ctx, metautil.AppendDDL)
   136  	c.Assert(err, IsNil, Commentf("Flush failed", err))
   137  	infoSchema, err := s.mock.Domain.GetSnapshotInfoSchema(ts)
   138  	c.Assert(err, IsNil, Commentf("Error get snapshot info schema: %s", err))
   139  	dbInfo, ok := infoSchema.SchemaByName(model.NewCIStr("test_db"))
   140  	c.Assert(ok, IsTrue, Commentf("DB info not exist"))
   141  	tableInfo, err := infoSchema.TableByName(model.NewCIStr("test_db"), model.NewCIStr("test_table"))
   142  	c.Assert(err, IsNil, Commentf("Error get table info: %s", err))
   143  	tables := []*metautil.Table{{
   144  		DB:   dbInfo,
   145  		Info: tableInfo.Meta(),
   146  	}}
   147  	metaBytes, err := s.storage.ReadFile(ctx, metautil.MetaFile)
   148  	c.Assert(err, IsNil)
   149  	mockMeta := &backuppb.BackupMeta{}
   150  	err = proto.Unmarshal(metaBytes, mockMeta)
   151  	c.Assert(err, IsNil)
   152  	// check the schema version
   153  	c.Assert(mockMeta.Version, Equals, int32(metautil.MetaV1))
   154  	metaReader := metautil.NewMetaReader(mockMeta, s.storage)
   155  	allDDLJobsBytes, err := metaReader.ReadDDLs(ctx)
   156  	c.Assert(err, IsNil)
   157  	var allDDLJobs []*model.Job
   158  	err = json.Unmarshal(allDDLJobsBytes, &allDDLJobs)
   159  	c.Assert(err, IsNil)
   160  
   161  	ddlJobs := restore.FilterDDLJobs(allDDLJobs, tables)
   162  	for _, job := range ddlJobs {
   163  		c.Logf("get ddl job: %s", job.Query)
   164  	}
   165  	c.Assert(len(ddlJobs), Equals, 7)
   166  }
   167  
   168  func (s *testRestoreSchemaSuite) TestFilterDDLJobsV2(c *C) {
   169  	tk := testkit.NewTestKit(c, s.mock.Storage)
   170  	tk.MustExec("CREATE DATABASE IF NOT EXISTS test_db;")
   171  	tk.MustExec("CREATE TABLE IF NOT EXISTS test_db.test_table (c1 INT);")
   172  	lastTS, err := s.mock.GetOracle().GetTimestamp(context.Background(), &oracle.Option{TxnScope: oracle.GlobalTxnScope})
   173  	c.Assert(err, IsNil, Commentf("Error get last ts: %s", err))
   174  	tk.MustExec("RENAME TABLE test_db.test_table to test_db.test_table1;")
   175  	tk.MustExec("DROP TABLE test_db.test_table1;")
   176  	tk.MustExec("DROP DATABASE test_db;")
   177  	tk.MustExec("CREATE DATABASE test_db;")
   178  	tk.MustExec("USE test_db;")
   179  	tk.MustExec("CREATE TABLE test_table1 (c2 CHAR(255));")
   180  	tk.MustExec("RENAME TABLE test_table1 to test_table;")
   181  	tk.MustExec("TRUNCATE TABLE test_table;")
   182  
   183  	ts, err := s.mock.GetOracle().GetTimestamp(context.Background(), &oracle.Option{TxnScope: oracle.GlobalTxnScope})
   184  	c.Assert(err, IsNil, Commentf("Error get ts: %s", err))
   185  
   186  	metaWriter := metautil.NewMetaWriter(s.storage, metautil.MetaFileSize, true)
   187  	ctx := context.Background()
   188  	metaWriter.StartWriteMetasAsync(ctx, metautil.AppendDDL)
   189  	err = backup.WriteBackupDDLJobs(metaWriter, s.mock.Storage, lastTS, ts)
   190  	c.Assert(err, IsNil, Commentf("Error get ddl jobs: %s", err))
   191  	err = metaWriter.FinishWriteMetas(ctx, metautil.AppendDDL)
   192  	c.Assert(err, IsNil, Commentf("Flush failed", err))
   193  	infoSchema, err := s.mock.Domain.GetSnapshotInfoSchema(ts)
   194  	c.Assert(err, IsNil, Commentf("Error get snapshot info schema: %s", err))
   195  	dbInfo, ok := infoSchema.SchemaByName(model.NewCIStr("test_db"))
   196  	c.Assert(ok, IsTrue, Commentf("DB info not exist"))
   197  	tableInfo, err := infoSchema.TableByName(model.NewCIStr("test_db"), model.NewCIStr("test_table"))
   198  	c.Assert(err, IsNil, Commentf("Error get table info: %s", err))
   199  	tables := []*metautil.Table{{
   200  		DB:   dbInfo,
   201  		Info: tableInfo.Meta(),
   202  	}}
   203  	metaBytes, err := s.storage.ReadFile(ctx, metautil.MetaFile)
   204  	c.Assert(err, IsNil)
   205  	mockMeta := &backuppb.BackupMeta{}
   206  	err = proto.Unmarshal(metaBytes, mockMeta)
   207  	c.Assert(err, IsNil)
   208  	// check the schema version
   209  	c.Assert(mockMeta.Version, Equals, int32(metautil.MetaV2))
   210  	metaReader := metautil.NewMetaReader(mockMeta, s.storage)
   211  	allDDLJobsBytes, err := metaReader.ReadDDLs(ctx)
   212  	c.Assert(err, IsNil)
   213  	var allDDLJobs []*model.Job
   214  	err = json.Unmarshal(allDDLJobsBytes, &allDDLJobs)
   215  	c.Assert(err, IsNil)
   216  
   217  	ddlJobs := restore.FilterDDLJobs(allDDLJobs, tables)
   218  	for _, job := range ddlJobs {
   219  		c.Logf("get ddl job: %s", job.Query)
   220  	}
   221  	c.Assert(len(ddlJobs), Equals, 7)
   222  }