diff --git a/api-put-object-common.go b/api-put-object-common.go index cf18cd8df..886b5b569 100644 --- a/api-put-object-common.go +++ b/api-put-object-common.go @@ -166,13 +166,13 @@ func hashCopyN(hashAlgorithms map[string]hash.Hash, hashSums map[string][]byte, // getUploadID - fetch upload id if already present for an object name // or initiate a new request to fetch a new upload id. -func (c Client) getUploadID(bucketName, objectName, contentType string) (uploadID string, isNew bool, err error) { +func (c Client) newUploadID(bucketName, objectName, contentType string) (uploadID string, err error) { // Input validation. if err := isValidBucketName(bucketName); err != nil { - return "", false, err + return "", err } if err := isValidObjectName(objectName); err != nil { - return "", false, err + return "", err } // Set content Type to default if empty string. @@ -180,23 +180,55 @@ func (c Client) getUploadID(bucketName, objectName, contentType string) (uploadI contentType = "application/octet-stream" } - // Find upload id for previous upload for an object. - uploadID, err = c.findUploadID(bucketName, objectName) + // Initiate multipart upload for an object. + initMultipartUploadResult, err := c.initiateMultipartUpload(bucketName, objectName, contentType) if err != nil { - return "", false, err + return "", err } + return initMultipartUploadResult.UploadID, nil +} + +// getMpartUploadSession returns the upload id and the uploaded parts to continue a previous upload session +// or initiate a new multipart session if no current one found +func (c Client) getMpartUploadSession(bucketName, objectName, contentType string) (string, map[int]objectPart, error) { + // A map of all uploaded parts. + var partsInfo map[int]objectPart + var err error + + uploadID, err := c.findUploadID(bucketName, objectName) + if err != nil { + return "", nil, err + } + if uploadID == "" { - // Initiate multipart upload for an object. - initMultipartUploadResult, err := c.initiateMultipartUpload(bucketName, objectName, contentType) + // Initiates a new multipart request + uploadID, err = c.newUploadID(bucketName, objectName, contentType) if err != nil { - return "", false, err + return "", nil, err + } + } else { + // Fetch previously upload parts and maximum part size. + partsInfo, err = c.listObjectParts(bucketName, objectName, uploadID) + if err != nil { + // When the server returns NoSuchUpload even if its previouls acknowleged the existance of the upload id, + // initiate a new multipart upload + if respErr, ok := err.(ErrorResponse); ok && respErr.Code == "NoSuchUpload" { + uploadID, err = c.newUploadID(bucketName, objectName, contentType) + if err != nil { + return "", nil, err + } + } else { + return "", nil, err + } } - // Save the new upload id. - uploadID = initMultipartUploadResult.UploadID - // Indicate that this is a new upload id. - isNew = true } - return uploadID, isNew, nil + + // Allocate partsInfo if not done yet + if partsInfo == nil { + partsInfo = make(map[int]objectPart) + } + + return uploadID, partsInfo, nil } // computeHash - Calculates hashes for an input read Seeker. diff --git a/api-put-object-file.go b/api-put-object-file.go index 6b2436b5b..b2d0994e4 100644 --- a/api-put-object-file.go +++ b/api-put-object-file.go @@ -140,9 +140,8 @@ func (c Client) putObjectMultipartFromFile(bucketName, objectName string, fileRe return 0, err } - // Get upload id for an object, initiates a new multipart request - // if it cannot find any previously partially uploaded object. - uploadID, isNew, err := c.getUploadID(bucketName, objectName, contentType) + // Get the upload id of a previously partially uploaded object or initiate a new multipart upload + uploadID, partsInfo, err := c.getMpartUploadSession(bucketName, objectName, contentType) if err != nil { return 0, err } @@ -153,19 +152,6 @@ func (c Client) putObjectMultipartFromFile(bucketName, objectName string, fileRe // Complete multipart upload. var complMultipartUpload completeMultipartUpload - // A map of all uploaded parts. - var partsInfo = make(map[int]objectPart) - - // If this session is a continuation of a previous session fetch all - // previously uploaded parts info. - if !isNew { - // Fetch previously upload parts and maximum part size. - partsInfo, err = c.listObjectParts(bucketName, objectName, uploadID) - if err != nil { - return 0, err - } - } - // Calculate the optimal parts info for a given size. totalPartsCount, partSize, lastPartSize, err := optimalPartInfo(fileSize) if err != nil { diff --git a/api-put-object-multipart.go b/api-put-object-multipart.go index b0a004900..f20ef6129 100644 --- a/api-put-object-multipart.go +++ b/api-put-object-multipart.go @@ -83,27 +83,12 @@ func (c Client) putObjectMultipartStream(bucketName, objectName string, reader i // Complete multipart upload. var complMultipartUpload completeMultipartUpload - // A map of all previously uploaded parts. - var partsInfo = make(map[int]objectPart) - - // getUploadID for an object, initiates a new multipart request - // if it cannot find any previously partially uploaded object. - uploadID, isNew, err := c.getUploadID(bucketName, objectName, contentType) + // Get the upload id of a previously partially uploaded object or initiate a new multipart upload + uploadID, partsInfo, err := c.getMpartUploadSession(bucketName, objectName, contentType) if err != nil { return 0, err } - // If This session is a continuation of a previous session fetch all - // previously uploaded parts info and as a special case only fetch partsInfo - // for only known upload size. - if !isNew { - // Fetch previously uploaded parts and maximum part size. - partsInfo, err = c.listObjectParts(bucketName, objectName, uploadID) - if err != nil { - return 0, err - } - } - // Calculate the optimal parts info for a given size. totalPartsCount, partSize, _, err := optimalPartInfo(size) if err != nil { diff --git a/api-put-object-readat.go b/api-put-object-readat.go index 8ed87609b..798688d70 100644 --- a/api-put-object-readat.go +++ b/api-put-object-readat.go @@ -72,9 +72,8 @@ func (c Client) putObjectMultipartFromReadAt(bucketName, objectName string, read return 0, err } - // Get upload id for an object, initiates a new multipart request - // if it cannot find any previously partially uploaded object. - uploadID, isNew, err := c.getUploadID(bucketName, objectName, contentType) + // Get the upload id of a previously partially uploaded object or initiate a new multipart upload + uploadID, partsInfo, err := c.getMpartUploadSession(bucketName, objectName, contentType) if err != nil { return 0, err } @@ -85,17 +84,6 @@ func (c Client) putObjectMultipartFromReadAt(bucketName, objectName string, read // Complete multipart upload. var complMultipartUpload completeMultipartUpload - // A map of all uploaded parts. - var partsInfo = make(map[int]objectPart) - - // Fetch all parts info previously uploaded. - if !isNew { - partsInfo, err = c.listObjectParts(bucketName, objectName, uploadID) - if err != nil { - return 0, err - } - } - // Calculate the optimal parts info for a given size. totalPartsCount, partSize, lastPartSize, err := optimalPartInfo(size) if err != nil {