github.com/pingcap/tiflow@v0.0.0-20240520035814-5bf52d54e205/dm/chaos/cases/diff.go (about) 1 // Copyright 2020 PingCAP, Inc. 2 // 3 // Licensed under the Apache License, Version 2.0 (the "License"); 4 // you may not use this file except in compliance with the License. 5 // You may obtain a copy of the License at 6 // 7 // http://www.apache.org/licenses/LICENSE-2.0 8 // 9 // Unless required by applicable law or agreed to in writing, software 10 // distributed under the License is distributed on an "AS IS" BASIS, 11 // See the License for the specific language governing permissions and 12 // limitations under the License. 13 14 package main 15 16 import ( 17 "context" 18 "database/sql" 19 "fmt" 20 "time" 21 22 "github.com/pingcap/errors" 23 "github.com/pingcap/tidb-tools/pkg/diff" 24 "github.com/pingcap/tidb/pkg/util/dbutil" 25 "github.com/pingcap/tiflow/dm/pkg/log" 26 "go.uber.org/zap" 27 ) 28 29 // diffDataLoop checks whether target has the same data with source via `sync-diff-inspector` multiple times. 30 func diffDataLoop(ctx context.Context, count int, interval time.Duration, schema string, tables []string, targetDB *sql.DB, sourceDBs ...*sql.DB) (err error) { 31 for i := 0; i < count; i++ { 32 select { 33 case <-ctx.Done(): 34 return nil 35 case <-time.After(interval): 36 err = diffData(ctx, schema, tables, targetDB, sourceDBs...) 37 if err == nil { 38 return nil 39 } 40 log.L().Warn("diff data error", zap.Int("count", i+1), log.ShortError(err)) 41 } 42 } 43 return err 44 } 45 46 // diffData checks whether target has the same data with source via `sync-diff-inspector`. 47 func diffData(ctx context.Context, schema string, tables []string, targetDB *sql.DB, sourceDBs ...*sql.DB) error { 48 for _, table := range tables { 49 sourceTables := make([]*diff.TableInstance, 0, len(sourceDBs)) 50 for i, sourceDB := range sourceDBs { 51 sourceTables = append(sourceTables, &diff.TableInstance{ 52 Conn: sourceDB, 53 Schema: schema, 54 Table: table, 55 InstanceID: fmt.Sprintf("source-%d", i), 56 }) 57 } 58 59 targetTable := &diff.TableInstance{ 60 Conn: targetDB, 61 Schema: schema, 62 Table: table, 63 InstanceID: "target", 64 } 65 66 td := &diff.TableDiff{ 67 SourceTables: sourceTables, 68 TargetTable: targetTable, 69 ChunkSize: 1000, 70 Sample: 100, 71 CheckThreadCount: 1, 72 UseChecksum: true, 73 TiDBStatsSource: targetTable, 74 CpDB: targetDB, 75 } 76 77 structEqual, dataEqual, err := td.Equal(ctx, func(dml string) error { 78 return nil 79 }) 80 81 if errors.Cause(err) == context.Canceled || errors.Cause(err) == context.DeadlineExceeded { 82 return nil 83 } 84 if !structEqual { 85 return fmt.Errorf("different struct for table %s", dbutil.TableName(schema, table)) 86 } else if !dataEqual { 87 return fmt.Errorf("different data for table %s", dbutil.TableName(schema, table)) 88 } 89 log.L().Info("data equal for table", zap.String("schema", schema), zap.String("table", table)) 90 } 91 92 return nil 93 }