diff --git a/cmd/cp-main.go b/cmd/cp-main.go index 9ec393ef6d..33e795bfa8 100644 --- a/cmd/cp-main.go +++ b/cmd/cp-main.go @@ -24,6 +24,7 @@ import ( "io" "path/filepath" "strings" + "time" "github.com/fatih/color" "github.com/minio/cli" @@ -101,6 +102,10 @@ var ( Name: "max-workers", Usage: "maximum number of concurrent copies (default: autodetect)", }, + cli.BoolFlag{ + Name: "retry", + Usage: "if specified, will enable retrying on a per object basis if errors occur", + }, checksumFlag, } ) @@ -261,21 +266,49 @@ func doCopy(ctx context.Context, copyOpts doCopyOpts) URLs { TotalSize: copyOpts.cpURLs.TotalSize, }) } - - urls := uploadSourceToTargetURL(ctx, uploadSourceToTargetURLOpts{ - urls: copyOpts.cpURLs, - progress: copyOpts.pg, - encKeyDB: copyOpts.encryptionKeys, - preserve: copyOpts.preserve, - isZip: copyOpts.isZip, - multipartSize: copyOpts.multipartSize, - multipartThreads: copyOpts.multipartThreads, - updateProgressTotal: copyOpts.updateProgressTotal, - ifNotExists: copyOpts.ifNotExists, - }) - if copyOpts.isMvCmd && urls.Error == nil { - rmManager.add(ctx, sourceAlias, sourceURL.String()) + var urls URLs + if !copyOpts.isRetriable { + urls = uploadSourceToTargetURL(ctx, uploadSourceToTargetURLOpts{ + urls: copyOpts.cpURLs, + progress: copyOpts.pg, + encKeyDB: copyOpts.encryptionKeys, + preserve: copyOpts.preserve, + isZip: copyOpts.isZip, + multipartSize: copyOpts.multipartSize, + multipartThreads: copyOpts.multipartThreads, + updateProgressTotal: copyOpts.updateProgressTotal, + ifNotExists: copyOpts.ifNotExists, + }) + if copyOpts.isMvCmd && urls.Error == nil { + rmManager.add(ctx, sourceAlias, sourceURL.String()) + } + return urls } + newRetryManager(ctx, time.Second, 3).retry(func(rm *retryManager) *probe.Error { + if rm.retries > 0 { + printMsg(retryMessage{ + SourceURL: copyOpts.cpURLs.SourceContent.URL.String(), + TargetURL: copyOpts.cpURLs.TargetContent.URL.String(), + Retries: rm.retries, + }) + } + urls = uploadSourceToTargetURL(ctx, uploadSourceToTargetURLOpts{ + urls: copyOpts.cpURLs, + progress: copyOpts.pg, + encKeyDB: copyOpts.encryptionKeys, + preserve: copyOpts.preserve, + isZip: copyOpts.isZip, + multipartSize: copyOpts.multipartSize, + multipartThreads: copyOpts.multipartThreads, + updateProgressTotal: copyOpts.updateProgressTotal, + ifNotExists: copyOpts.ifNotExists, + }) + if copyOpts.isMvCmd && urls.Error == nil { + rmManager.add(ctx, sourceAlias, sourceURL.String()) + return nil + } + return urls.Error + }) return urls } @@ -450,6 +483,7 @@ func doCopySession(ctx context.Context, cancelCopy context.CancelFunc, cli *cli. isMvCmd: isMvCmd, preserve: preserve, isZip: isZip, + isRetriable: cli.Bool("retry"), }) }, cpURLs.SourceContent.Size) } @@ -563,12 +597,12 @@ func mainCopy(cliCtx *cli.Context) error { } type doCopyOpts struct { - cpURLs URLs - pg ProgressReader - encryptionKeys map[string][]prefixSSEPair - isMvCmd, preserve, isZip bool - updateProgressTotal bool - multipartSize string - multipartThreads string - ifNotExists bool + cpURLs URLs + pg ProgressReader + encryptionKeys map[string][]prefixSSEPair + isMvCmd, preserve, isZip, isRetriable bool + updateProgressTotal bool + multipartSize string + multipartThreads string + ifNotExists bool } diff --git a/cmd/get-main.go b/cmd/get-main.go index 43060a1e16..2e16d8e9ff 100644 --- a/cmd/get-main.go +++ b/cmd/get-main.go @@ -32,6 +32,10 @@ var ( Name: "version-id, vid", Usage: "get a specific version of an object", }, + cli.BoolFlag{ + Name: "retry", + Usage: "if specified, will enable retrying on a per object basis if errors occur", + }, } ) @@ -132,6 +136,7 @@ func mainGet(cliCtx *cli.Context) (e error) { pg: pg, encryptionKeys: encryptionKeys, updateProgressTotal: true, + isRetriable: cliCtx.Bool("retry"), }) if urls.Error != nil { e = urls.Error.ToGoError() diff --git a/cmd/mv-main.go b/cmd/mv-main.go index a490b6571c..7884c20b6a 100644 --- a/cmd/mv-main.go +++ b/cmd/mv-main.go @@ -63,6 +63,10 @@ var ( Name: "tags", Usage: "apply one or more tags to the uploaded objects", }, + cli.BoolFlag{ + Name: "retry", + Usage: "if specified, will enable retrying on a per object basis if errors occur", + }, checksumFlag, } ) diff --git a/cmd/put-main.go b/cmd/put-main.go index 14c4c3e94e..7c898b86dd 100644 --- a/cmd/put-main.go +++ b/cmd/put-main.go @@ -55,6 +55,10 @@ var ( Name: "storage-class, sc", Usage: "set storage class for new object on target", }, + cli.BoolFlag{ + Name: "retry", + Usage: "if specified, will enable retrying on a per object basis if errors occur", + }, } ) @@ -208,6 +212,7 @@ func mainPut(cliCtx *cli.Context) (e error) { multipartSize: size, multipartThreads: strconv.Itoa(threads), ifNotExists: cliCtx.Bool("if-not-exists"), + isRetriable: cliCtx.Bool("retry"), }) if urls.Error != nil { showLastProgressBar(pg, urls.Error.ToGoError())