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

     1  // Copyright 2020 PingCAP, Inc. Licensed under Apache-2.0.
     2  
     3  package restore_test
     4  
     5  import (
     6  	"bytes"
     7  	"context"
     8  	"sync"
     9  	"time"
    10  
    11  	"github.com/pingcap/br/pkg/metautil"
    12  
    13  	"github.com/pingcap/kvproto/pkg/import_sstpb"
    14  	"github.com/pingcap/log"
    15  	"go.uber.org/zap"
    16  
    17  	"github.com/pingcap/br/pkg/restore"
    18  
    19  	. "github.com/pingcap/check"
    20  	"github.com/pingcap/errors"
    21  	"github.com/pingcap/parser/model"
    22  
    23  	"github.com/pingcap/br/pkg/rtree"
    24  )
    25  
    26  type testBatcherSuite struct{}
    27  
    28  type drySender struct {
    29  	mu *sync.Mutex
    30  
    31  	rewriteRules *restore.RewriteRules
    32  	ranges       []rtree.Range
    33  	nBatch       int
    34  
    35  	sink restore.TableSink
    36  }
    37  
    38  func (sender *drySender) PutSink(sink restore.TableSink) {
    39  	sender.sink = sink
    40  }
    41  
    42  func (sender *drySender) RestoreBatch(ranges restore.DrainResult) {
    43  	sender.mu.Lock()
    44  	defer sender.mu.Unlock()
    45  	log.Info("fake restore range", rtree.ZapRanges(ranges.Ranges))
    46  	sender.nBatch++
    47  	sender.rewriteRules.Append(*ranges.RewriteRules)
    48  	sender.ranges = append(sender.ranges, ranges.Ranges...)
    49  	sender.sink.EmitTables(ranges.BlankTablesAfterSend...)
    50  }
    51  
    52  func (sender *drySender) Close() {
    53  	sender.sink.Close()
    54  }
    55  
    56  func waitForSend() {
    57  	time.Sleep(10 * time.Millisecond)
    58  }
    59  
    60  func (sender *drySender) Ranges() []rtree.Range {
    61  	return sender.ranges
    62  }
    63  
    64  func newDrySender() *drySender {
    65  	return &drySender{
    66  		rewriteRules: restore.EmptyRewriteRule(),
    67  		ranges:       []rtree.Range{},
    68  		mu:           new(sync.Mutex),
    69  	}
    70  }
    71  
    72  type recordCurrentTableManager struct {
    73  	lock sync.Mutex
    74  	m    map[int64]bool
    75  }
    76  
    77  func (manager *recordCurrentTableManager) Close(ctx context.Context) {
    78  	manager.lock.Lock()
    79  	defer manager.lock.Unlock()
    80  	if len(manager.m) > 0 {
    81  		log.Panic("When closing, there are still some tables doesn't be sent",
    82  			zap.Any("tables", manager.m))
    83  	}
    84  }
    85  
    86  func newMockManager() *recordCurrentTableManager {
    87  	return &recordCurrentTableManager{
    88  		m: make(map[int64]bool),
    89  	}
    90  }
    91  
    92  func (manager *recordCurrentTableManager) Enter(_ context.Context, tables []restore.CreatedTable) error {
    93  	manager.lock.Lock()
    94  	defer manager.lock.Unlock()
    95  	for _, t := range tables {
    96  		log.Info("entering", zap.Int64("table ID", t.Table.ID))
    97  		manager.m[t.Table.ID] = true
    98  	}
    99  	return nil
   100  }
   101  
   102  func (manager *recordCurrentTableManager) Leave(_ context.Context, tables []restore.CreatedTable) error {
   103  	manager.lock.Lock()
   104  	defer manager.lock.Unlock()
   105  	for _, t := range tables {
   106  		if !manager.m[t.Table.ID] {
   107  			return errors.Errorf("Table %d is removed before added", t.Table.ID)
   108  		}
   109  		log.Info("leaving", zap.Int64("table ID", t.Table.ID))
   110  		delete(manager.m, t.Table.ID)
   111  	}
   112  	return nil
   113  }
   114  
   115  func (manager *recordCurrentTableManager) Has(tables ...restore.TableWithRange) bool {
   116  	manager.lock.Lock()
   117  	defer manager.lock.Unlock()
   118  	ids := make([]int64, 0, len(tables))
   119  	currentIDs := make([]int64, 0, len(manager.m))
   120  	for _, t := range tables {
   121  		ids = append(ids, t.Table.ID)
   122  	}
   123  	for id, contains := range manager.m {
   124  		if contains {
   125  			currentIDs = append(currentIDs, id)
   126  		}
   127  	}
   128  	log.Info("testing", zap.Int64s("should has ID", ids), zap.Int64s("has ID", currentIDs))
   129  	for _, i := range ids {
   130  		if !manager.m[i] {
   131  			return false
   132  		}
   133  	}
   134  	return true
   135  }
   136  
   137  func (sender *drySender) HasRewriteRuleOfKey(prefix string) bool {
   138  	sender.mu.Lock()
   139  	defer sender.mu.Unlock()
   140  	for _, rule := range sender.rewriteRules.Data {
   141  		if bytes.Equal([]byte(prefix), rule.OldKeyPrefix) {
   142  			return true
   143  		}
   144  	}
   145  	return false
   146  }
   147  
   148  func (sender *drySender) RangeLen() int {
   149  	sender.mu.Lock()
   150  	defer sender.mu.Unlock()
   151  	return len(sender.ranges)
   152  }
   153  
   154  func (sender *drySender) BatchCount() int {
   155  	return sender.nBatch
   156  }
   157  
   158  var _ = Suite(&testBatcherSuite{})
   159  
   160  func fakeTableWithRange(id int64, rngs []rtree.Range) restore.TableWithRange {
   161  	tbl := &metautil.Table{
   162  		DB: &model.DBInfo{},
   163  		Info: &model.TableInfo{
   164  			ID: id,
   165  		},
   166  	}
   167  	tblWithRng := restore.TableWithRange{
   168  		CreatedTable: restore.CreatedTable{
   169  			RewriteRule: restore.EmptyRewriteRule(),
   170  			Table:       tbl.Info,
   171  			OldTable:    tbl,
   172  		},
   173  		Range: rngs,
   174  	}
   175  	return tblWithRng
   176  }
   177  
   178  func fakeRewriteRules(oldPrefix string, newPrefix string) *restore.RewriteRules {
   179  	return &restore.RewriteRules{
   180  		Data: []*import_sstpb.RewriteRule{
   181  			{
   182  				OldKeyPrefix: []byte(oldPrefix),
   183  				NewKeyPrefix: []byte(newPrefix),
   184  			},
   185  		},
   186  	}
   187  }
   188  
   189  func fakeRange(startKey, endKey string) rtree.Range {
   190  	return rtree.Range{
   191  		StartKey: []byte(startKey),
   192  		EndKey:   []byte(endKey),
   193  	}
   194  }
   195  
   196  func join(nested [][]rtree.Range) (plain []rtree.Range) {
   197  	for _, ranges := range nested {
   198  		plain = append(plain, ranges...)
   199  	}
   200  	return plain
   201  }
   202  
   203  // TestBasic tests basic workflow of batcher.
   204  func (*testBatcherSuite) TestBasic(c *C) {
   205  	ctx := context.Background()
   206  	errCh := make(chan error, 8)
   207  	sender := newDrySender()
   208  	manager := newMockManager()
   209  	batcher, _ := restore.NewBatcher(ctx, sender, manager, errCh)
   210  	batcher.SetThreshold(2)
   211  
   212  	tableRanges := [][]rtree.Range{
   213  		{fakeRange("aaa", "aab")},
   214  		{fakeRange("baa", "bab"), fakeRange("bac", "bad")},
   215  		{fakeRange("caa", "cab"), fakeRange("cac", "cad")},
   216  	}
   217  
   218  	simpleTables := []restore.TableWithRange{}
   219  	for i, ranges := range tableRanges {
   220  		simpleTables = append(simpleTables, fakeTableWithRange(int64(i), ranges))
   221  	}
   222  	for _, tbl := range simpleTables {
   223  		batcher.Add(tbl)
   224  	}
   225  
   226  	batcher.Close()
   227  	rngs := sender.Ranges()
   228  
   229  	c.Assert(join(tableRanges), DeepEquals, rngs)
   230  	select {
   231  	case err := <-errCh:
   232  		c.Fatal(errors.Trace(err))
   233  	default:
   234  	}
   235  }
   236  
   237  func (*testBatcherSuite) TestAutoSend(c *C) {
   238  	ctx := context.Background()
   239  	errCh := make(chan error, 8)
   240  	sender := newDrySender()
   241  	manager := newMockManager()
   242  	batcher, _ := restore.NewBatcher(ctx, sender, manager, errCh)
   243  	batcher.SetThreshold(1024)
   244  
   245  	simpleTable := fakeTableWithRange(1, []rtree.Range{fakeRange("caa", "cab"), fakeRange("cac", "cad")})
   246  
   247  	batcher.Add(simpleTable)
   248  	c.Assert(batcher.Len(), Greater, 0)
   249  
   250  	// enable auto commit.
   251  	batcher.EnableAutoCommit(ctx, 100*time.Millisecond)
   252  	time.Sleep(200 * time.Millisecond)
   253  
   254  	c.Assert(sender.RangeLen(), Greater, 0)
   255  	c.Assert(batcher.Len(), Equals, 0)
   256  
   257  	batcher.Close()
   258  
   259  	rngs := sender.Ranges()
   260  	c.Assert(rngs, DeepEquals, simpleTable.Range)
   261  	select {
   262  	case err := <-errCh:
   263  		c.Fatal(errors.Trace(err))
   264  	default:
   265  	}
   266  }
   267  
   268  func (*testBatcherSuite) TestSplitRangeOnSameTable(c *C) {
   269  	ctx := context.Background()
   270  	errCh := make(chan error, 8)
   271  	sender := newDrySender()
   272  	manager := newMockManager()
   273  	batcher, _ := restore.NewBatcher(ctx, sender, manager, errCh)
   274  	batcher.SetThreshold(2)
   275  
   276  	simpleTable := fakeTableWithRange(1, []rtree.Range{
   277  		fakeRange("caa", "cab"), fakeRange("cac", "cad"),
   278  		fakeRange("cae", "caf"), fakeRange("cag", "cai"),
   279  		fakeRange("caj", "cak"), fakeRange("cal", "cam"),
   280  		fakeRange("can", "cao"), fakeRange("cap", "caq"),
   281  	})
   282  
   283  	batcher.Add(simpleTable)
   284  	batcher.Close()
   285  	c.Assert(sender.BatchCount(), Equals, 4)
   286  
   287  	rngs := sender.Ranges()
   288  	c.Assert(rngs, DeepEquals, simpleTable.Range)
   289  	select {
   290  	case err := <-errCh:
   291  		c.Fatal(errors.Trace(err))
   292  	default:
   293  	}
   294  }
   295  
   296  func (*testBatcherSuite) TestRewriteRules(c *C) {
   297  	tableRanges := [][]rtree.Range{
   298  		{fakeRange("aaa", "aab")},
   299  		{fakeRange("baa", "bab"), fakeRange("bac", "bad")},
   300  		{
   301  			fakeRange("caa", "cab"), fakeRange("cac", "cad"),
   302  			fakeRange("cae", "caf"), fakeRange("cag", "cai"),
   303  			fakeRange("caj", "cak"), fakeRange("cal", "cam"),
   304  			fakeRange("can", "cao"), fakeRange("cap", "caq"),
   305  		},
   306  	}
   307  	rewriteRules := []*restore.RewriteRules{
   308  		fakeRewriteRules("a", "ada"),
   309  		fakeRewriteRules("b", "bob"),
   310  		fakeRewriteRules("c", "cpp"),
   311  	}
   312  
   313  	tables := make([]restore.TableWithRange, 0, len(tableRanges))
   314  	for i, ranges := range tableRanges {
   315  		table := fakeTableWithRange(int64(i), ranges)
   316  		table.RewriteRule = rewriteRules[i]
   317  		tables = append(tables, table)
   318  	}
   319  
   320  	ctx := context.Background()
   321  	errCh := make(chan error, 8)
   322  	sender := newDrySender()
   323  	manager := newMockManager()
   324  	batcher, _ := restore.NewBatcher(ctx, sender, manager, errCh)
   325  	batcher.SetThreshold(2)
   326  
   327  	batcher.Add(tables[0])
   328  	waitForSend()
   329  	c.Assert(sender.RangeLen(), Equals, 0)
   330  
   331  	batcher.Add(tables[1])
   332  	waitForSend()
   333  	c.Assert(sender.HasRewriteRuleOfKey("a"), IsTrue)
   334  	c.Assert(sender.HasRewriteRuleOfKey("b"), IsTrue)
   335  	c.Assert(manager.Has(tables[1]), IsTrue)
   336  	c.Assert(sender.RangeLen(), Equals, 2)
   337  
   338  	batcher.Add(tables[2])
   339  	batcher.Close()
   340  	c.Assert(sender.HasRewriteRuleOfKey("c"), IsTrue)
   341  	c.Assert(sender.Ranges(), DeepEquals, join(tableRanges))
   342  
   343  	select {
   344  	case err := <-errCh:
   345  		c.Fatal(errors.Trace(err))
   346  	default:
   347  	}
   348  }
   349  
   350  func (*testBatcherSuite) TestBatcherLen(c *C) {
   351  	ctx := context.Background()
   352  	errCh := make(chan error, 8)
   353  	sender := newDrySender()
   354  	manager := newMockManager()
   355  	batcher, _ := restore.NewBatcher(ctx, sender, manager, errCh)
   356  	batcher.SetThreshold(15)
   357  
   358  	simpleTable := fakeTableWithRange(1, []rtree.Range{
   359  		fakeRange("caa", "cab"), fakeRange("cac", "cad"),
   360  		fakeRange("cae", "caf"), fakeRange("cag", "cai"),
   361  		fakeRange("caj", "cak"), fakeRange("cal", "cam"),
   362  		fakeRange("can", "cao"), fakeRange("cap", "caq"),
   363  	})
   364  
   365  	simpleTable2 := fakeTableWithRange(2, []rtree.Range{
   366  		fakeRange("caa", "cab"), fakeRange("cac", "cad"),
   367  		fakeRange("cae", "caf"), fakeRange("cag", "cai"),
   368  		fakeRange("caj", "cak"), fakeRange("cal", "cam"),
   369  		fakeRange("can", "cao"), fakeRange("cap", "caq"),
   370  	})
   371  
   372  	batcher.Add(simpleTable)
   373  	waitForSend()
   374  	c.Assert(batcher.Len(), Equals, 8)
   375  	c.Assert(manager.Has(simpleTable), IsFalse)
   376  	c.Assert(manager.Has(simpleTable2), IsFalse)
   377  
   378  	batcher.Add(simpleTable2)
   379  	waitForSend()
   380  	c.Assert(batcher.Len(), Equals, 1)
   381  	c.Assert(manager.Has(simpleTable2), IsTrue)
   382  	c.Assert(manager.Has(simpleTable), IsFalse)
   383  	batcher.Close()
   384  	c.Assert(batcher.Len(), Equals, 0)
   385  
   386  	select {
   387  	case err := <-errCh:
   388  		c.Fatal(errors.Trace(err))
   389  	default:
   390  	}
   391  }