diff --git a/br/pkg/restore/import_retry_test.go b/br/pkg/restore/import_retry_test.go index 8a8cff0da303b..edb077e144628 100644 --- a/br/pkg/restore/import_retry_test.go +++ b/br/pkg/restore/import_retry_test.go @@ -597,3 +597,25 @@ func TestFilterFilesByRegion(t *testing.T) { require.Equal(t, subfile, c.subfiles) } } + +func TestRetryRecognizeErrCode(t *testing.T) { + waitTime := 1 * time.Millisecond + maxWaitTime := 16 * time.Millisecond + ctx := context.Background() + inner := 0 + outer := 0 + utils.WithRetry(ctx, func() error { + e := utils.WithRetry(ctx, func() error { + inner++ + e := status.Error(codes.Unavailable, "the connection to TiKV has been cut by a neko, meow :3") + if e != nil { + return errors.Trace(e) + } + return nil + }, utils.NewBackoffer(10, waitTime, maxWaitTime, utils.NewErrorContext("download sst", 3))) + outer++ + return errors.Trace(e) + }, utils.NewBackoffer(10, waitTime, maxWaitTime, utils.NewErrorContext("import sst", 3))) + require.Equal(t, 10, outer) + require.Equal(t, 100, inner) +} diff --git a/br/pkg/restore/log_client/BUILD.bazel b/br/pkg/restore/log_client/BUILD.bazel new file mode 100644 index 0000000000000..e69de29bb2d1d diff --git a/br/pkg/utils/backoff.go b/br/pkg/utils/backoff.go index f0a81283d68de..cfb71e4395e1a 100644 --- a/br/pkg/utils/backoff.go +++ b/br/pkg/utils/backoff.go @@ -13,6 +13,7 @@ import ( "github.com/pingcap/failpoint" "github.com/pingcap/log" berrors "github.com/pingcap/tidb/br/pkg/errors" + "go.uber.org/multierr" "go.uber.org/zap" "google.golang.org/grpc/codes" "google.golang.org/grpc/status" @@ -169,12 +170,14 @@ func NewBackupSSTBackoffer() Backoffer { func (bo *importerBackoffer) NextBackoff(err error) time.Duration { // we don't care storeID here. - res := bo.errContext.HandleErrorMsg(err.Error(), 0) + errs := multierr.Errors(err) + lastErr := errs[len(errs)-1] + res := bo.errContext.HandleErrorMsg(lastErr.Error(), 0) if res.Strategy == RetryStrategy { bo.delayTime = 2 * bo.delayTime bo.attempt-- } else { - e := errors.Cause(err) + e := errors.Cause(lastErr) switch e { // nolint:errorlint case berrors.ErrKVEpochNotMatch, berrors.ErrKVDownloadFailed, berrors.ErrKVIngestFailed, berrors.ErrPDLeaderNotFound: bo.delayTime = 2 * bo.delayTime @@ -189,7 +192,7 @@ func (bo *importerBackoffer) NextBackoff(err error) time.Duration { bo.delayTime = 2 * bo.delayTime bo.attempt-- case codes.Canceled: - if isGRPCCancel(err) { + if isGRPCCancel(lastErr) { bo.delayTime = 2 * bo.delayTime bo.attempt-- } else {