@@ -512,7 +512,19 @@ func (s *S3Backend) getRequestId(r *request.Request) string {
512512 r .HTTPResponse .Header .Get ("x-amz-id-2" )
513513}
514514
515- func (s * S3Backend ) HeadBlob (param * HeadBlobInput ) (* HeadBlobOutput , error ) {
515+ // FIXME: Move retries to common code from S3
516+ func (s * S3Backend ) HeadBlob (req * HeadBlobInput ) (resp * HeadBlobOutput , err error ) {
517+ s .readBackoff (func (attempt int ) error {
518+ resp , err = s .tryHeadBlob (req )
519+ if err != nil && shouldRetry (err ) {
520+ s3Log .Errorf ("Error getting metadata of %v (attempt %v): %v\n " , req .Key , attempt , err )
521+ }
522+ return err
523+ })
524+ return
525+ }
526+
527+ func (s * S3Backend ) tryHeadBlob (param * HeadBlobInput ) (* HeadBlobOutput , error ) {
516528 head := s3.HeadObjectInput {Bucket : & s .bucket ,
517529 Key : & param .Key ,
518530 }
@@ -542,7 +554,20 @@ func (s *S3Backend) HeadBlob(param *HeadBlobInput) (*HeadBlobOutput, error) {
542554 }, nil
543555}
544556
545- func (s * S3Backend ) ListBlobs (param * ListBlobsInput ) (* ListBlobsOutput , error ) {
557+ // FIXME: Move retries to common code from S3
558+ func (s * S3Backend ) ListBlobs (req * ListBlobsInput ) (resp * ListBlobsOutput , err error ) {
559+ s .readBackoff (func (attempt int ) error {
560+ resp , err = s .tryListBlobs (req )
561+ if err != nil && shouldRetry (err ) {
562+ s3Log .Errorf ("Error listing objects with prefix=%v delimiter=%v start-after=%v max-keys=%v (attempt %v): %v\n " ,
563+ NilStr (req .Prefix ), NilStr (req .Delimiter ), NilStr (req .StartAfter ), NilUInt32 (req .MaxKeys ), attempt , err )
564+ }
565+ return err
566+ })
567+ return
568+ }
569+
570+ func (s * S3Backend ) tryListBlobs (param * ListBlobsInput ) (* ListBlobsOutput , error ) {
546571 var maxKeys * int64
547572
548573 if param .MaxKeys != nil {
@@ -868,7 +893,49 @@ func (s *S3Backend) CopyBlob(param *CopyBlobInput) (*CopyBlobOutput, error) {
868893 return & CopyBlobOutput {s .getRequestId (req )}, nil
869894}
870895
871- func (s * S3Backend ) GetBlob (param * GetBlobInput ) (* GetBlobOutput , error ) {
896+ func shouldRetry (err error ) bool {
897+ err = mapAwsError (err )
898+ return err != syscall .ENOENT && err != syscall .EINVAL &&
899+ err != syscall .EACCES && err != syscall .ENOTSUP && err != syscall .ERANGE
900+ }
901+
902+ // FIXME: Add similar write backoff (now it's handled by file/dir code)
903+ func (s * S3Backend ) readBackoff (try func (attempt int ) error ) (err error ) {
904+ interval := s .flags .ReadRetryInterval
905+ attempt := 1
906+ for {
907+ err = try (attempt )
908+ if err != nil {
909+ if shouldRetry (err ) && (s .flags .ReadRetryAttempts < 1 || attempt < s .flags .ReadRetryAttempts ) {
910+ attempt ++
911+ time .Sleep (interval )
912+ interval = time .Duration (s .flags .ReadRetryMultiplier * float64 (interval ))
913+ if interval > s .flags .ReadRetryMax {
914+ interval = s .flags .ReadRetryMax
915+ }
916+ } else {
917+ break
918+ }
919+ } else {
920+ break
921+ }
922+ }
923+ return
924+ }
925+
926+ // FIXME: Move retries to common code from S3
927+ func (s * S3Backend ) GetBlob (req * GetBlobInput ) (resp * GetBlobOutput , err error ) {
928+ s .readBackoff (func (attempt int ) error {
929+ resp , err = s .tryGetBlob (req )
930+ if err != nil && shouldRetry (err ) {
931+ log .Errorf ("Error reading %v +%v of %v (attempt %v): %v" , req .Start , req .Count , req .Key , attempt , err )
932+ }
933+ return err
934+ })
935+ return
936+ }
937+
938+ func (s * S3Backend ) tryGetBlob (param * GetBlobInput ) (* GetBlobOutput , error ) {
872939 get := s3.GetObjectInput {
873940 Bucket : & s .bucket ,
874941 Key : & param .Key ,
0 commit comments