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

     1  // Copyright 2021 PingCAP, Inc. Licensed under Apache-2.0.
     2  
     3  package restore
     4  
     5  import (
     6  	"context"
     7  	"database/sql/driver"
     8  
     9  	"github.com/DATA-DOG/go-sqlmock"
    10  	. "github.com/pingcap/check"
    11  	"github.com/pingcap/parser"
    12  	"github.com/pingcap/parser/ast"
    13  	"github.com/pingcap/parser/model"
    14  	"github.com/pingcap/tidb/ddl"
    15  	tmock "github.com/pingcap/tidb/util/mock"
    16  	"go.uber.org/zap"
    17  
    18  	"github.com/pingcap/br/pkg/lightning/checkpoints"
    19  	"github.com/pingcap/br/pkg/lightning/common"
    20  	"github.com/pingcap/br/pkg/lightning/log"
    21  	"github.com/pingcap/br/pkg/lightning/verification"
    22  )
    23  
    24  var _ = Suite(&metaMgrSuite{})
    25  
    26  type metaMgrSuite struct {
    27  	mockDB      sqlmock.Sqlmock
    28  	tr          *TableRestore
    29  	mgr         *dbTableMetaMgr
    30  	checksumMgr *testChecksumMgr
    31  }
    32  
    33  func (s *metaMgrSuite) SetUpSuite(c *C) {
    34  	p := parser.New()
    35  	se := tmock.NewContext()
    36  
    37  	node, err := p.ParseOneStmt("CREATE TABLE `t1` (`c1` varchar(5) NOT NULL)", "utf8mb4", "utf8mb4_bin")
    38  	c.Assert(err, IsNil)
    39  	tableInfo, err := ddl.MockTableInfo(se, node.(*ast.CreateTableStmt), int64(1))
    40  	c.Assert(err, IsNil)
    41  	tableInfo.State = model.StatePublic
    42  
    43  	schema := "test"
    44  	tb := "t1"
    45  	ti := &checkpoints.TidbTableInfo{
    46  		ID:   tableInfo.ID,
    47  		DB:   schema,
    48  		Name: tb,
    49  		Core: tableInfo,
    50  	}
    51  
    52  	tableName := common.UniqueTable(schema, tb)
    53  	logger := log.With(zap.String("table", tableName))
    54  	s.tr = &TableRestore{
    55  		tableName: tableName,
    56  		tableInfo: ti,
    57  		logger:    logger,
    58  	}
    59  }
    60  
    61  func (s *metaMgrSuite) SetUpTest(c *C) {
    62  	db, m, err := sqlmock.New()
    63  	c.Assert(err, IsNil)
    64  
    65  	s.mgr = &dbTableMetaMgr{
    66  		session:      db,
    67  		taskID:       1,
    68  		tr:           s.tr,
    69  		tableName:    common.UniqueTable("test", tableMetaTableName),
    70  		needChecksum: true,
    71  	}
    72  	s.mockDB = m
    73  	s.checksumMgr = &testChecksumMgr{}
    74  }
    75  
    76  func (s *metaMgrSuite) TearDownTest(c *C) {
    77  	c.Assert(s.mockDB.ExpectationsWereMet(), IsNil)
    78  }
    79  
    80  func (s *metaMgrSuite) TestAllocTableRowIDsSingleTable(c *C) {
    81  	ctx := context.WithValue(context.Background(), &checksumManagerKey, s.checksumMgr)
    82  
    83  	rows := [][]driver.Value{
    84  		{int64(1), int64(0), int64(0), uint64(0), uint64(0), uint64(0), "initialized"},
    85  	}
    86  	nextID := int64(1)
    87  	updateArgs := []driver.Value{int64(0), int64(10), "restore", int64(1), int64(1)}
    88  	s.prepareMock(rows, &nextID, updateArgs, nil, nil)
    89  
    90  	ck, rowIDBase, err := s.mgr.AllocTableRowIDs(ctx, 10)
    91  	c.Assert(err, IsNil)
    92  	c.Assert(rowIDBase, Equals, int64(0))
    93  	c.Assert(ck, IsNil)
    94  	c.Assert(s.checksumMgr.callCnt, Equals, 0)
    95  }
    96  
    97  func (s *metaMgrSuite) TestAllocTableRowIDsSingleTableAutoIDNot0(c *C) {
    98  	ctx := context.WithValue(context.Background(), &checksumManagerKey, s.checksumMgr)
    99  
   100  	rows := [][]driver.Value{
   101  		{int64(1), int64(0), int64(0), uint64(0), uint64(0), uint64(0), "initialized"},
   102  	}
   103  	nextID := int64(999)
   104  	updateArgs := []driver.Value{int64(998), int64(1008), "allocated", int64(1), int64(1)}
   105  	newStatus := "restore"
   106  	s.prepareMock(rows, &nextID, updateArgs, nil, &newStatus)
   107  
   108  	ck, rowIDBase, err := s.mgr.AllocTableRowIDs(ctx, 10)
   109  	c.Assert(err, IsNil)
   110  	c.Assert(rowIDBase, Equals, int64(998))
   111  	c.Assert(ck, IsNil)
   112  	c.Assert(s.checksumMgr.callCnt, Equals, 1)
   113  }
   114  
   115  func (s *metaMgrSuite) TestAllocTableRowIDsSingleTableContainsData(c *C) {
   116  	ctx := context.WithValue(context.Background(), &checksumManagerKey, s.checksumMgr)
   117  
   118  	rows := [][]driver.Value{
   119  		{int64(1), int64(0), int64(0), uint64(0), uint64(0), uint64(0), "initialized"},
   120  	}
   121  	nextID := int64(999)
   122  	checksum := verification.MakeKVChecksum(1, 2, 3)
   123  	updateArgs := []driver.Value{int64(998), int64(1008), "allocated", int64(1), int64(1)}
   124  	s.prepareMock(rows, &nextID, updateArgs, &checksum, nil)
   125  
   126  	ck, rowIDBase, err := s.mgr.AllocTableRowIDs(ctx, 10)
   127  	c.Assert(err, IsNil)
   128  	c.Assert(rowIDBase, Equals, int64(998))
   129  	c.Assert(ck, DeepEquals, &checksum)
   130  	c.Assert(s.checksumMgr.callCnt, Equals, 1)
   131  }
   132  
   133  func (s *metaMgrSuite) TestAllocTableRowIDsSingleTableSkipChecksum(c *C) {
   134  	s.mgr.needChecksum = false
   135  	defer func() {
   136  		s.mgr.needChecksum = true
   137  	}()
   138  	ctx := context.WithValue(context.Background(), &checksumManagerKey, s.checksumMgr)
   139  
   140  	rows := [][]driver.Value{
   141  		{int64(1), int64(0), int64(0), uint64(0), uint64(0), uint64(0), "initialized"},
   142  	}
   143  	nextID := int64(999)
   144  	newStatus := "restore"
   145  	updateArgs := []driver.Value{int64(998), int64(1008), "allocated", int64(1), int64(1)}
   146  	s.prepareMock(rows, &nextID, updateArgs, nil, &newStatus)
   147  
   148  	ck, rowIDBase, err := s.mgr.AllocTableRowIDs(ctx, 10)
   149  	c.Assert(err, IsNil)
   150  	c.Assert(rowIDBase, Equals, int64(998))
   151  	c.Assert(ck, IsNil)
   152  	c.Assert(s.checksumMgr.callCnt, Equals, 0)
   153  }
   154  
   155  func (s *metaMgrSuite) TestAllocTableRowIDsAllocated(c *C) {
   156  	ctx := context.WithValue(context.Background(), &checksumManagerKey, s.checksumMgr)
   157  
   158  	rows := [][]driver.Value{
   159  		{int64(1), int64(998), int64(1008), uint64(0), uint64(0), uint64(0), metaStatusRowIDAllocated.String()},
   160  	}
   161  	checksum := verification.MakeKVChecksum(2, 1, 3)
   162  	s.prepareMock(rows, nil, nil, &checksum, nil)
   163  
   164  	ck, rowIDBase, err := s.mgr.AllocTableRowIDs(ctx, 10)
   165  	c.Assert(err, IsNil)
   166  	c.Assert(rowIDBase, Equals, int64(998))
   167  	c.Assert(ck, DeepEquals, &checksum)
   168  	c.Assert(s.checksumMgr.callCnt, Equals, 1)
   169  }
   170  
   171  func (s *metaMgrSuite) TestAllocTableRowIDsFinished(c *C) {
   172  	ctx := context.WithValue(context.Background(), &checksumManagerKey, s.checksumMgr)
   173  
   174  	rows := [][]driver.Value{
   175  		{int64(1), int64(998), int64(1008), uint64(1), uint64(2), uint64(3), metaStatusRestoreStarted.String()},
   176  	}
   177  	checksum := verification.MakeKVChecksum(2, 1, 3)
   178  	s.prepareMock(rows, nil, nil, nil, nil)
   179  
   180  	ck, rowIDBase, err := s.mgr.AllocTableRowIDs(ctx, 10)
   181  	c.Assert(err, IsNil)
   182  	c.Assert(rowIDBase, Equals, int64(998))
   183  	c.Assert(ck, DeepEquals, &checksum)
   184  	c.Assert(s.checksumMgr.callCnt, Equals, 0)
   185  }
   186  
   187  func (s *metaMgrSuite) TestAllocTableRowIDsMultiTasksInit(c *C) {
   188  	ctx := context.WithValue(context.Background(), &checksumManagerKey, s.checksumMgr)
   189  
   190  	rows := [][]driver.Value{
   191  		{int64(1), int64(0), int64(0), uint64(0), uint64(0), uint64(0), "initialized"},
   192  		{int64(2), int64(0), int64(0), uint64(0), uint64(0), uint64(0), "initialized"},
   193  	}
   194  	nextID := int64(1)
   195  	updateArgs := []driver.Value{int64(0), int64(10), "restore", int64(1), int64(1)}
   196  	s.prepareMock(rows, &nextID, updateArgs, nil, nil)
   197  
   198  	ck, rowIDBase, err := s.mgr.AllocTableRowIDs(ctx, 10)
   199  	c.Assert(err, IsNil)
   200  	c.Assert(rowIDBase, Equals, int64(0))
   201  	c.Assert(ck, IsNil)
   202  	c.Assert(s.checksumMgr.callCnt, Equals, 0)
   203  }
   204  
   205  func (s *metaMgrSuite) TestAllocTableRowIDsMultiTasksAllocated(c *C) {
   206  	ctx := context.WithValue(context.Background(), &checksumManagerKey, s.checksumMgr)
   207  
   208  	rows := [][]driver.Value{
   209  		{int64(1), int64(0), int64(0), uint64(0), uint64(0), uint64(0), metaStatusInitial.String()},
   210  		{int64(2), int64(0), int64(100), uint64(0), uint64(0), uint64(0), metaStatusRowIDAllocated.String()},
   211  	}
   212  	updateArgs := []driver.Value{int64(100), int64(110), "restore", int64(1), int64(1)}
   213  	s.prepareMock(rows, nil, updateArgs, nil, nil)
   214  
   215  	ck, rowIDBase, err := s.mgr.AllocTableRowIDs(ctx, 10)
   216  	c.Assert(err, IsNil)
   217  	c.Assert(rowIDBase, Equals, int64(100))
   218  	c.Assert(ck, IsNil)
   219  	c.Assert(s.checksumMgr.callCnt, Equals, 0)
   220  }
   221  
   222  func (s *metaMgrSuite) prepareMock(rowsVal [][]driver.Value, nextRowID *int64, updateArgs []driver.Value, checksum *verification.KVChecksum, updateStatus *string) {
   223  	s.mockDB.ExpectExec("SET SESSION tidb_txn_mode = 'pessimistic';").
   224  		WillReturnResult(sqlmock.NewResult(int64(0), int64(0)))
   225  
   226  	s.mockDB.ExpectBegin()
   227  
   228  	rows := sqlmock.NewRows([]string{"task_id", "row_id_base", "row_id_max", "total_kvs_base", "total_bytes_base", "checksum_base", "status"})
   229  	for _, r := range rowsVal {
   230  		rows = rows.AddRow(r...)
   231  	}
   232  	s.mockDB.ExpectQuery("\\QSELECT task_id, row_id_base, row_id_max, total_kvs_base, total_bytes_base, checksum_base, status from `test`.`table_meta` WHERE table_id = ? FOR UPDATE\\E").
   233  		WithArgs(int64(1)).
   234  		WillReturnRows(rows)
   235  	if nextRowID != nil {
   236  		s.mockDB.ExpectQuery("SHOW TABLE `test`.`t1` NEXT_ROW_ID").
   237  			WillReturnRows(sqlmock.NewRows([]string{"DB_NAME", "TABLE_NAME", "COLUMN_NAME", "NEXT_GLOBAL_ROW_ID", "ID_TYPE"}).
   238  				AddRow("test", "t1", "_tidb_rowid", *nextRowID, "AUTO_INCREMENT"))
   239  	}
   240  
   241  	if len(updateArgs) > 0 {
   242  		s.mockDB.ExpectExec("\\Qupdate `test`.`table_meta` set row_id_base = ?, row_id_max = ?, status = ? where table_id = ? and task_id = ?\\E").
   243  			WithArgs(updateArgs...).
   244  			WillReturnResult(sqlmock.NewResult(int64(0), int64(1)))
   245  	}
   246  
   247  	s.mockDB.ExpectCommit()
   248  
   249  	if checksum != nil {
   250  		s.mockDB.ExpectExec("\\Qupdate `test`.`table_meta` set total_kvs_base = ?, total_bytes_base = ?, checksum_base = ?, status = ? where table_id = ? and task_id = ?\\E").
   251  			WithArgs(checksum.SumKVS(), checksum.SumSize(), checksum.Sum(), metaStatusRestoreStarted.String(), int64(1), int64(1)).
   252  			WillReturnResult(sqlmock.NewResult(int64(0), int64(1)))
   253  		s.checksumMgr.checksum = RemoteChecksum{
   254  			TotalBytes: checksum.SumSize(),
   255  			TotalKVs:   checksum.SumKVS(),
   256  			Checksum:   checksum.Sum(),
   257  		}
   258  	}
   259  
   260  	if updateStatus != nil {
   261  		s.mockDB.ExpectExec("\\Qupdate `test`.`table_meta` set status = ? where table_id = ? and task_id = ?\\E").
   262  			WithArgs(*updateStatus, int64(1), int64(1)).
   263  			WillReturnResult(sqlmock.NewResult(int64(0), int64(1)))
   264  	}
   265  }