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 }