Skip to content

Commit 3f84697

Browse files
authored
dumpling: fix cannot dump data bug when dumpling fails to check has tikv (#40977) (#41252)
close #40932
1 parent 3ab3be0 commit 3f84697

File tree

4 files changed

+72
-2
lines changed

4 files changed

+72
-2
lines changed

dumpling/export/BUILD.bazel

+1
Original file line numberDiff line numberDiff line change
@@ -106,6 +106,7 @@ go_test(
106106
"@com_github_data_dog_go_sqlmock//:go-sqlmock",
107107
"@com_github_go_sql_driver_mysql//:mysql",
108108
"@com_github_pingcap_errors//:errors",
109+
"@com_github_pingcap_failpoint//:failpoint",
109110
"@com_github_prometheus_client_golang//prometheus/collectors",
110111
"@com_github_stretchr_testify//require",
111112
"@org_golang_x_sync//errgroup",

dumpling/export/dump.go

+1-1
Original file line numberDiff line numberDiff line change
@@ -1531,7 +1531,7 @@ func setSessionParam(d *Dumper) error {
15311531
d.L().Info("cannot check whether TiDB has TiKV, will apply tidb_snapshot by default. This won't affect dump process", log.ShortError(err))
15321532
}
15331533
if conf.ServerInfo.HasTiKV {
1534-
sessionParam["tidb_snapshot"] = snapshot
1534+
sessionParam[snapshotVar] = snapshot
15351535
}
15361536
}
15371537
}

dumpling/export/dump_test.go

+63
Original file line numberDiff line numberDiff line change
@@ -9,7 +9,9 @@ import (
99
"time"
1010

1111
"github.com/DATA-DOG/go-sqlmock"
12+
"github.com/go-sql-driver/mysql"
1213
"github.com/pingcap/errors"
14+
"github.com/pingcap/failpoint"
1315
"github.com/pingcap/tidb/br/pkg/version"
1416
tcontext "github.com/pingcap/tidb/dumpling/context"
1517
"github.com/pingcap/tidb/parser"
@@ -224,3 +226,64 @@ func TestUnregisterMetrics(t *testing.T) {
224226
// should not panic
225227
require.Error(t, err)
226228
}
229+
230+
func TestSetSessionParams(t *testing.T) {
231+
// case 1: fail to set tidb_snapshot, should return error with hint
232+
db, mock, err := sqlmock.New()
233+
require.NoError(t, err)
234+
defer func() {
235+
require.NoError(t, db.Close())
236+
}()
237+
238+
mock.ExpectQuery("SELECT @@tidb_config").
239+
WillReturnError(errors.New("mock error"))
240+
mock.ExpectQuery("SELECT COUNT\\(1\\) as c FROM MYSQL.TiDB WHERE VARIABLE_NAME='tikv_gc_safe_point'").
241+
WillReturnError(errors.New("mock error"))
242+
tikvErr := &mysql.MySQLError{
243+
Number: 1105,
244+
Message: "can not get 'tikv_gc_safe_point'",
245+
}
246+
mock.ExpectExec("SET SESSION tidb_snapshot").
247+
WillReturnError(tikvErr)
248+
249+
require.NoError(t, failpoint.Enable("github.com/pingcap/tidb/dumpling/export/SkipResetDB", "return(true)"))
250+
defer failpoint.Disable("github.com/pingcap/tidb/dumpling/export/SkipResetDB=return(true)")
251+
252+
tctx, cancel := tcontext.Background().WithLogger(appLogger).WithCancel()
253+
defer cancel()
254+
255+
conf := DefaultConfig()
256+
conf.ServerInfo = version.ServerInfo{
257+
ServerType: version.ServerTypeTiDB,
258+
HasTiKV: false,
259+
}
260+
conf.Snapshot = "439153276059648000"
261+
conf.Consistency = ConsistencyTypeSnapshot
262+
d := &Dumper{
263+
tctx: tctx,
264+
conf: conf,
265+
cancelCtx: cancel,
266+
dbHandle: db,
267+
}
268+
err = setSessionParam(d)
269+
require.ErrorContains(t, err, "consistency=none")
270+
271+
// case 2: fail to set other
272+
conf.ServerInfo = version.ServerInfo{
273+
ServerType: version.ServerTypeMySQL,
274+
HasTiKV: false,
275+
}
276+
conf.Snapshot = ""
277+
conf.Consistency = ConsistencyTypeFlush
278+
conf.SessionParams = map[string]interface{}{
279+
"mock": "UTC",
280+
}
281+
d.dbHandle = db
282+
mock.ExpectExec("SET SESSION mock").
283+
WillReturnError(errors.New("Unknown system variable mock"))
284+
mock.ExpectClose()
285+
mock.ExpectClose()
286+
287+
err = setSessionParam(d)
288+
require.NoError(t, err)
289+
}

dumpling/export/sql.go

+7-1
Original file line numberDiff line numberDiff line change
@@ -29,6 +29,7 @@ import (
2929

3030
const (
3131
orderByTiDBRowID = "ORDER BY `_tidb_rowid`"
32+
snapshotVar = "tidb_snapshot"
3233
)
3334

3435
type listTableType int
@@ -851,7 +852,9 @@ func resetDBWithSessionParams(tctx *tcontext.Context, db *sql.DB, cfg *mysql.Con
851852
s := fmt.Sprintf("SET SESSION %s = ?", k)
852853
_, err := db.ExecContext(tctx, s, pv)
853854
if err != nil {
854-
if isUnknownSystemVariableErr(err) {
855+
if k == snapshotVar {
856+
err = errors.Annotate(err, "fail to set snapshot for tidb, please set --consistency=none/--consistency=lock or fix snapshot problem")
857+
} else if isUnknownSystemVariableErr(err) {
855858
tctx.L().Info("session variable is not supported by db", zap.String("variable", k), zap.Reflect("value", v))
856859
continue
857860
}
@@ -876,6 +879,9 @@ func resetDBWithSessionParams(tctx *tcontext.Context, db *sql.DB, cfg *mysql.Con
876879
}
877880
cfg.Params[k] = s
878881
}
882+
failpoint.Inject("SkipResetDB", func(_ failpoint.Value) {
883+
failpoint.Return(db, nil)
884+
})
879885

880886
db.Close()
881887
c, err := mysql.NewConnector(cfg)

0 commit comments

Comments
 (0)