Skip to content
This repository was archived by the owner on Aug 21, 2023. It is now read-only.

Commit 6f74c68

Browse files
authored
fix consistency bug (#128)
* fix consistency problem * add consistency integration test * address comment * address comments
1 parent 4c8f99c commit 6f74c68

File tree

8 files changed

+147
-59
lines changed

8 files changed

+147
-59
lines changed

Makefile

Lines changed: 20 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -4,6 +4,9 @@ LDFLAGS += -X "github.com/pingcap/dumpling/v4/cli.GitHash=$(shell git rev-parse
44
LDFLAGS += -X "github.com/pingcap/dumpling/v4/cli.GitBranch=$(shell git rev-parse --abbrev-ref HEAD)"
55
LDFLAGS += -X "github.com/pingcap/dumpling/v4/cli.GoVersion=$(shell go version)"
66

7+
FAILPOINT_ENABLE := $$(find $$PWD/ -type d | grep -vE "(\.git|tools)" | xargs bin/failpoint-ctl enable)
8+
FAILPOINT_DISABLE := $$(find $$PWD/ -type d | grep -vE "(\.git|tools)" | xargs bin/failpoint-ctl disable)
9+
710
GO = go
811
GOLDFLAGS = -ldflags '$(LDFLAGS)'
912
ifeq ("$(WITH_RACE)", "1")
@@ -17,8 +20,21 @@ build: bin/dumpling
1720
bin/%: cmd/%/main.go $(wildcard v4/**/*.go)
1821
$(GO) build $(GOLDFLAGS) -tags codes -o $@ $<
1922

20-
test:
21-
$(GO) list ./... | xargs $(GO) test $(GOLDFLAGS) -coverprofile=coverage.txt -covermode=atomic
23+
test: failpoint-enable
24+
$(GO) list ./... | xargs $(GO) test $(GOLDFLAGS) -coverprofile=coverage.txt -covermode=atomic ||{ $(FAILPOINT_DISABLE); exit 1; }
25+
@make failpoint-disable
26+
27+
integration_test: failpoint-enable bin/dumpling
28+
@make failpoint-disable
29+
./tests/run.sh ||{ $(FAILPOINT_DISABLE); exit 1; }
30+
31+
bin/failpoint-ctl: go.mod
32+
$(GO) build -o $@ github.com/pingcap/failpoint/failpoint-ctl
33+
34+
failpoint-enable: bin/failpoint-ctl
35+
# Converting gofail failpoints...
36+
@$(FAILPOINT_ENABLE)
2237

23-
integration_test: bin/dumpling
24-
./tests/run.sh
38+
failpoint-disable: bin/failpoint-ctl
39+
# Restoring gofail failpoints...
40+
@$(FAILPOINT_DISABLE)

go.mod

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -9,13 +9,13 @@ require (
99
github.com/go-sql-driver/mysql v1.5.0
1010
github.com/pingcap/check v0.0.0-20191216031241-8a5a85928f12
1111
github.com/pingcap/errors v0.11.5-0.20190809092503-95897b64e011
12+
github.com/pingcap/failpoint v0.0.0-20200702092429-9f69995143ce
1213
github.com/pingcap/log v0.0.0-20200511115504-543df19646ad
1314
github.com/pingcap/pd/v4 v4.0.0
1415
github.com/pingcap/tidb-tools v4.0.0-rc.2.0.20200521050818-6dd445d83fe0+incompatible
1516
github.com/pkg/errors v0.9.1
1617
github.com/soheilhy/cmux v0.1.4
1718
github.com/spf13/pflag v1.0.3
18-
github.com/stretchr/testify v1.5.1 // indirect
1919
go.etcd.io/etcd v0.5.0-alpha.5.0.20191023171146-3cf2f69b5738
2020
go.uber.org/zap v1.14.0
2121
golang.org/x/mod v0.3.0 // indirect

go.sum

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -228,9 +228,12 @@ github.com/pingcap/check v0.0.0-20191216031241-8a5a85928f12/go.mod h1:PYMCGwN0JH
228228
github.com/pingcap/errcode v0.0.0-20180921232412-a1a7271709d9 h1:KH4f4Si9XK6/IW50HtoaiLIFHGkapOM6w83za47UYik=
229229
github.com/pingcap/errcode v0.0.0-20180921232412-a1a7271709d9/go.mod h1:4b2X8xSqxIroj/IZ9MX/VGZhAwc11wB9wRIzHvz6SeM=
230230
github.com/pingcap/errors v0.11.0/go.mod h1:Oi8TUi2kEtXXLMJk9l1cGmz20kV3TaQ0usTwv5KuLY8=
231+
github.com/pingcap/errors v0.11.4/go.mod h1:Oi8TUi2kEtXXLMJk9l1cGmz20kV3TaQ0usTwv5KuLY8=
231232
github.com/pingcap/errors v0.11.5-0.20190809092503-95897b64e011 h1:58naV4XMEqm0hl9LcYo6cZoGBGiLtefMQMF/vo3XLgQ=
232233
github.com/pingcap/errors v0.11.5-0.20190809092503-95897b64e011/go.mod h1:Oi8TUi2kEtXXLMJk9l1cGmz20kV3TaQ0usTwv5KuLY8=
233234
github.com/pingcap/failpoint v0.0.0-20191029060244-12f4ac2fd11d/go.mod h1:DNS3Qg7bEDhU6EXNHF+XSv/PGznQaMJ5FWvctpm6pQI=
235+
github.com/pingcap/failpoint v0.0.0-20200702092429-9f69995143ce h1:Y1kCxlCtlPTMtVcOkjUcuQKh+YrluSo7+7YMCQSzy30=
236+
github.com/pingcap/failpoint v0.0.0-20200702092429-9f69995143ce/go.mod h1:w4PEZ5y16LeofeeGwdgZB4ddv9bLyDuIX+ljstgKZyk=
234237
github.com/pingcap/kvproto v0.0.0-20191211054548-3c6b38ea5107/go.mod h1:WWLmULLO7l8IOcQG+t+ItJ3fEcrL5FxF0Wu+HrMy26w=
235238
github.com/pingcap/kvproto v0.0.0-20200411081810-b85805c9476c/go.mod h1:IOdRDPLyda8GX2hE/jO7gqaCV/PNFh8BZQCQZXfIOqI=
236239
github.com/pingcap/kvproto v0.0.0-20200518112156-d4aeb467de29 h1:NpW1OuYrIl+IQrSsVbtyHpHpazmSCHy+ysrOixY0xY4=
@@ -270,6 +273,7 @@ github.com/rs/cors v1.7.0/go.mod h1:gFx+x8UowdsKA9AchylcLynDq+nNFfI8FkUZdN/jGCU=
270273
github.com/russross/blackfriday/v2 v2.0.1/go.mod h1:+Rmxgy9KzJVeS9/2gXHxylqXiyQDYRxCVz55jmeOWTM=
271274
github.com/sasha-s/go-deadlock v0.2.0/go.mod h1:StQn567HiB1fF2yJ44N9au7wOhrPS3iZqiDbRupzT10=
272275
github.com/satori/go.uuid v1.2.0/go.mod h1:dA0hQrYB0VpLJoorglMZABFdXlWrHn1NEOzdhQKdks0=
276+
github.com/sergi/go-diff v1.0.1-0.20180205163309-da645544ed44 h1:tB9NOR21++IjLyVx3/PCPhWMwqGNCMQEH96A6dMZ/gc=
273277
github.com/sergi/go-diff v1.0.1-0.20180205163309-da645544ed44/go.mod h1:0CfEIISq7TuYL3j771MWULgwwjU+GofnZX9QAmXWZgo=
274278
github.com/shirou/gopsutil v2.19.10+incompatible/go.mod h1:5b4v6he4MtMOwMlS0TUMTu2PcXUg8+E1lC7eC3UO/RA=
275279
github.com/shirou/w32 v0.0.0-20160930032740-bb4de0191aa4/go.mod h1:qsXQc7+bwAM3Q1u/4XEfrquwF8Lw7D7y5cD8CuHnfIc=

tests/consistency/run.sh

Lines changed: 60 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,60 @@
1+
#!/bin/sh
2+
3+
set -eu
4+
cur=$(cd `dirname $0`; pwd)
5+
6+
DB_NAME="mysql_consistency"
7+
TABLE_NAME="t"
8+
9+
# drop database on mysql
10+
run_sql "drop database if exists \`$DB_NAME\`;"
11+
12+
# build data on mysql
13+
run_sql "create database $DB_NAME;"
14+
run_sql "create table $DB_NAME.$TABLE_NAME (a int(255));"
15+
16+
# insert 100 records
17+
run_sql "insert into $DB_NAME.$TABLE_NAME values $(seq -s, 100 | sed 's/,*$//g' | sed "s/[0-9]*/('1')/g");"
18+
19+
# dumping with consistency flush
20+
export DUMPLING_TEST_DATABASE=$DB_NAME
21+
export GO_FAILPOINTS="github.com/pingcap/dumpling/v4/export/ConsistencyCheck=1*sleep(5000)"
22+
run_dumpling &
23+
# wait dumpling process to start to sleep
24+
sleep 2
25+
26+
# record metadata info
27+
metadata=`run_sql "show master status;"`
28+
metaLog=`echo $metadata | awk -F 'File:' '{print $2}' | awk '{print $1}'`
29+
metaPos=`echo $metadata | awk -F 'Position:' '{print $2}' | awk '{print $1}'`
30+
metaGTID=`echo $metadata | awk -F 'Executed_Gtid_Set:' '{print $2}' | awk '{print $1}'`
31+
# insert 100 more records, test whether dumpling will dump these data out
32+
run_sql "insert into $DB_NAME.$TABLE_NAME values $(seq -s, 100 | sed 's/,*$//g' | sed "s/[0-9]*/('1')/g");"
33+
34+
wait
35+
36+
# check data record count
37+
cnt=`grep -o "(1)" ${DUMPLING_OUTPUT_DIR}/${DB_NAME}.${TABLE_NAME}.0.sql|wc -l`
38+
echo "1st records count is ${cnt}"
39+
[ $cnt = 100 ]
40+
41+
# check metadata
42+
echo "metaLog: $metaLog"
43+
echo "metaPos: $metaPos"
44+
echo "metaGTID: $metaGTID"
45+
if [ $metaLog != "" ]; then
46+
[ `grep -o "Log: $metaLog" ${DUMPLING_OUTPUT_DIR}/metadata|wc -l` ]
47+
fi
48+
if [ $metaPos != "" ]; then
49+
[ `grep -o "Pos: $metaPos" ${DUMPLING_OUTPUT_DIR}/metadata|wc -l` ]
50+
fi
51+
if [ $metaGTID != "" ]; then
52+
[ `grep -o "GTID: $metaGTID" ${DUMPLING_OUTPUT_DIR}/metadata|wc -l` ]
53+
fi
54+
55+
# test dumpling normally
56+
export GO_FAILPOINTS=""
57+
run_dumpling
58+
cnt=`grep -o "(1)" ${DUMPLING_OUTPUT_DIR}/${DB_NAME}.${TABLE_NAME}.0.sql|wc -l`
59+
echo "2nd records count is ${cnt}"
60+
[ $cnt = 200 ]

v4/export/consistency.go

Lines changed: 24 additions & 25 deletions
Original file line numberDiff line numberDiff line change
@@ -1,22 +1,27 @@
11
package export
22

33
import (
4+
"context"
45
"database/sql"
56
"errors"
67
"fmt"
78
)
89

9-
func NewConsistencyController(conf *Config, session *sql.DB) (ConsistencyController, error) {
10+
func NewConsistencyController(ctx context.Context, conf *Config, session *sql.DB) (ConsistencyController, error) {
1011
resolveAutoConsistency(conf)
12+
conn, err := session.Conn(ctx)
13+
if err != nil {
14+
return nil, err
15+
}
1116
switch conf.Consistency {
1217
case "flush":
1318
return &ConsistencyFlushTableWithReadLock{
1419
serverType: conf.ServerInfo.ServerType,
15-
db: session,
20+
conn: conn,
1621
}, nil
1722
case "lock":
1823
return &ConsistencyLockDumpingTables{
19-
db: session,
24+
conn: conn,
2025
allTables: conf.Tables,
2126
}, nil
2227
case "snapshot":
@@ -32,49 +37,46 @@ func NewConsistencyController(conf *Config, session *sql.DB) (ConsistencyControl
3237
}
3338

3439
type ConsistencyController interface {
35-
Setup() error
36-
TearDown() error
40+
Setup(context.Context) error
41+
TearDown(context.Context) error
3742
}
3843

3944
type ConsistencyNone struct{}
4045

41-
func (c *ConsistencyNone) Setup() error {
46+
func (c *ConsistencyNone) Setup(_ context.Context) error {
4247
return nil
4348
}
4449

45-
func (c *ConsistencyNone) TearDown() error {
50+
func (c *ConsistencyNone) TearDown(_ context.Context) error {
4651
return nil
4752
}
4853

4954
type ConsistencyFlushTableWithReadLock struct {
5055
serverType ServerType
51-
db *sql.DB
56+
conn *sql.Conn
5257
}
5358

54-
func (c *ConsistencyFlushTableWithReadLock) Setup() error {
59+
func (c *ConsistencyFlushTableWithReadLock) Setup(ctx context.Context) error {
5560
if c.serverType == ServerTypeTiDB {
5661
return withStack(errors.New("'flush table with read lock' cannot be used to ensure the consistency in TiDB"))
5762
}
58-
return FlushTableWithReadLock(c.db)
63+
return FlushTableWithReadLock(ctx, c.conn)
5964
}
6065

61-
func (c *ConsistencyFlushTableWithReadLock) TearDown() error {
62-
err := c.db.Ping()
63-
if err != nil {
64-
return withStack(errors.New("ConsistencyFlushTableWithReadLock lost database connection"))
65-
}
66-
return UnlockTables(c.db)
66+
func (c *ConsistencyFlushTableWithReadLock) TearDown(ctx context.Context) error {
67+
defer c.conn.Close()
68+
return UnlockTables(ctx, c.conn)
6769
}
6870

6971
type ConsistencyLockDumpingTables struct {
70-
db *sql.DB
72+
conn *sql.Conn
7173
allTables DatabaseTables
7274
}
7375

74-
func (c *ConsistencyLockDumpingTables) Setup() error {
76+
func (c *ConsistencyLockDumpingTables) Setup(ctx context.Context) error {
7577
for dbName, tables := range c.allTables {
7678
for _, table := range tables {
77-
err := LockTables(c.db, dbName, table.Name)
79+
err := LockTables(ctx, c.conn, dbName, table.Name)
7880
if err != nil {
7981
return err
8082
}
@@ -83,12 +85,9 @@ func (c *ConsistencyLockDumpingTables) Setup() error {
8385
return nil
8486
}
8587

86-
func (c *ConsistencyLockDumpingTables) TearDown() error {
87-
err := c.db.Ping()
88-
if err != nil {
89-
return withStack(errors.New("ConsistencyLockDumpingTables lost database connection"))
90-
}
91-
return UnlockTables(c.db)
88+
func (c *ConsistencyLockDumpingTables) TearDown(ctx context.Context) error {
89+
defer c.conn.Close()
90+
return UnlockTables(ctx, c.conn)
9291
}
9392

9493
const showMasterStatusFieldNum = 5

v4/export/consistency_test.go

Lines changed: 22 additions & 17 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,7 @@
11
package export
22

33
import (
4+
"context"
45
"errors"
56
"strings"
67

@@ -18,41 +19,43 @@ func (s *testConsistencySuite) assertNil(err error, c *C) {
1819
}
1920
}
2021

21-
func (s *testConsistencySuite) assertLifetimeErrNil(ctrl ConsistencyController, c *C) {
22-
s.assertNil(ctrl.Setup(), c)
23-
s.assertNil(ctrl.TearDown(), c)
22+
func (s *testConsistencySuite) assertLifetimeErrNil(ctx context.Context, ctrl ConsistencyController, c *C) {
23+
s.assertNil(ctrl.Setup(ctx), c)
24+
s.assertNil(ctrl.TearDown(ctx), c)
2425
}
2526

2627
func (s *testConsistencySuite) TestConsistencyController(c *C) {
2728
db, mock, err := sqlmock.New()
2829
c.Assert(err, IsNil)
2930
defer db.Close()
31+
ctx, cancel := context.WithCancel(context.Background())
32+
defer cancel()
3033
conf := DefaultConfig()
3134
resultOk := sqlmock.NewResult(0, 1)
3235

3336
conf.Consistency = "none"
34-
ctrl, _ := NewConsistencyController(conf, db)
37+
ctrl, _ := NewConsistencyController(ctx, conf, db)
3538
_, ok := ctrl.(*ConsistencyNone)
3639
c.Assert(ok, IsTrue)
37-
s.assertLifetimeErrNil(ctrl, c)
40+
s.assertLifetimeErrNil(ctx, ctrl, c)
3841

3942
conf.Consistency = "flush"
4043
mock.ExpectExec("FLUSH TABLES WITH READ LOCK").WillReturnResult(resultOk)
4144
mock.ExpectExec("UNLOCK TABLES").WillReturnResult(resultOk)
42-
ctrl, _ = NewConsistencyController(conf, db)
45+
ctrl, _ = NewConsistencyController(ctx, conf, db)
4346
_, ok = ctrl.(*ConsistencyFlushTableWithReadLock)
4447
c.Assert(ok, IsTrue)
45-
s.assertLifetimeErrNil(ctrl, c)
48+
s.assertLifetimeErrNil(ctx, ctrl, c)
4649
if err = mock.ExpectationsWereMet(); err != nil {
4750
c.Fatalf(err.Error())
4851
}
4952

5053
conf.Consistency = "snapshot"
5154
conf.ServerInfo.ServerType = ServerTypeTiDB
52-
ctrl, _ = NewConsistencyController(conf, db)
55+
ctrl, _ = NewConsistencyController(ctx, conf, db)
5356
_, ok = ctrl.(*ConsistencyNone)
5457
c.Assert(ok, IsTrue)
55-
s.assertLifetimeErrNil(ctrl, c)
58+
s.assertLifetimeErrNil(ctx, ctrl, c)
5659

5760
conf.Consistency = "lock"
5861
conf.Tables = NewDatabaseTables().
@@ -62,10 +65,10 @@ func (s *testConsistencySuite) TestConsistencyController(c *C) {
6265
mock.ExpectExec("LOCK TABLES").WillReturnResult(resultOk)
6366
}
6467
mock.ExpectExec("UNLOCK TABLES").WillReturnResult(resultOk)
65-
ctrl, _ = NewConsistencyController(conf, db)
68+
ctrl, _ = NewConsistencyController(ctx, conf, db)
6669
_, ok = ctrl.(*ConsistencyLockDumpingTables)
6770
c.Assert(ok, IsTrue)
68-
s.assertLifetimeErrNil(ctrl, c)
71+
s.assertLifetimeErrNil(ctx, ctrl, c)
6972
if err = mock.ExpectationsWereMet(); err != nil {
7073
c.Fatalf(err.Error())
7174
}
@@ -96,31 +99,33 @@ func (s *testConsistencySuite) TestConsistencyControllerError(c *C) {
9699
db, mock, err := sqlmock.New()
97100
c.Assert(err, IsNil)
98101
defer db.Close()
102+
ctx, cancel := context.WithCancel(context.Background())
103+
defer cancel()
99104
conf := DefaultConfig()
100105

101106
conf.Consistency = "invalid_str"
102-
_, err = NewConsistencyController(conf, db)
107+
_, err = NewConsistencyController(ctx, conf, db)
103108
c.Assert(err, NotNil)
104109
c.Assert(strings.Contains(err.Error(), "invalid consistency option"), IsTrue)
105110

106111
// snapshot consistency is only available in TiDB
107112
conf.Consistency = "snapshot"
108113
conf.ServerInfo.ServerType = ServerTypeUnknown
109-
_, err = NewConsistencyController(conf, db)
114+
_, err = NewConsistencyController(ctx, conf, db)
110115
c.Assert(err, NotNil)
111116

112117
// flush consistency is unavailable in TiDB
113118
conf.Consistency = "flush"
114119
conf.ServerInfo.ServerType = ServerTypeTiDB
115-
ctrl, _ := NewConsistencyController(conf, db)
116-
err = ctrl.Setup()
120+
ctrl, _ := NewConsistencyController(ctx, conf, db)
121+
err = ctrl.Setup(ctx)
117122
c.Assert(err, NotNil)
118123

119124
// lock table fail
120125
conf.Consistency = "lock"
121126
conf.Tables = NewDatabaseTables().AppendTables("db", "t")
122127
mock.ExpectExec("LOCK TABLE").WillReturnError(errors.New(""))
123-
ctrl, _ = NewConsistencyController(conf, db)
124-
err = ctrl.Setup()
128+
ctrl, _ = NewConsistencyController(ctx, conf, db)
129+
err = ctrl.Setup(ctx)
125130
c.Assert(err, NotNil)
126131
}

0 commit comments

Comments
 (0)