fs: All parts except the last part should be of the same size (#5045)

fixes #4881
master
Krishna Srinivas 7 years ago committed by Dee Koder
parent 3d2d63f71e
commit 75865efb0e
  1. 8
      cmd/api-errors.go
  2. 15
      cmd/fs-v1-multipart.go
  3. 7
      cmd/object-api-errors.go

@ -146,6 +146,7 @@ const (
ErrInvalidResourceName ErrInvalidResourceName
ErrServerNotInitialized ErrServerNotInitialized
ErrOperationTimedOut ErrOperationTimedOut
ErrPartsSizeUnequal
// Add new extended error codes here. // Add new extended error codes here.
// Please open a https://github.com/minio/minio/issues before adding // Please open a https://github.com/minio/minio/issues before adding
// new error codes here. // new error codes here.
@ -659,6 +660,11 @@ var errorCodeResponse = map[APIErrorCode]APIError{
Description: "Your metadata headers are not supported.", Description: "Your metadata headers are not supported.",
HTTPStatusCode: http.StatusBadRequest, HTTPStatusCode: http.StatusBadRequest,
}, },
ErrPartsSizeUnequal: {
Code: "XMinioPartsSizeUnequal",
Description: "All parts except the last part should be of the same size.",
HTTPStatusCode: http.StatusBadRequest,
},
// Add your error structure here. // Add your error structure here.
} }
@ -755,6 +761,8 @@ func toAPIErrorCode(err error) (apiErr APIErrorCode) {
apiErr = ErrEntityTooLarge apiErr = ErrEntityTooLarge
case UnsupportedMetadata: case UnsupportedMetadata:
apiErr = ErrUnsupportedMetadata apiErr = ErrUnsupportedMetadata
case PartsSizeUnequal:
apiErr = ErrPartsSizeUnequal
default: default:
apiErr = ErrInternalError apiErr = ErrInternalError
} }

@ -777,6 +777,7 @@ func (fs fsObjects) CompleteMultipartUpload(bucket string, object string, upload
return oi, toObjectErr(err, minioMetaMultipartBucket, fsMetaPathMultipart) return oi, toObjectErr(err, minioMetaMultipartBucket, fsMetaPathMultipart)
} }
partSize := int64(-1) // Used later to ensure that all parts sizes are same.
// Validate all parts and then commit to disk. // Validate all parts and then commit to disk.
for i, part := range parts { for i, part := range parts {
partIdx := fsMeta.ObjectPartIndex(part.PartNumber) partIdx := fsMeta.ObjectPartIndex(part.PartNumber)
@ -799,6 +800,20 @@ func (fs fsObjects) CompleteMultipartUpload(bucket string, object string, upload
PartETag: part.ETag, PartETag: part.ETag,
}) })
} }
if partSize == -1 {
partSize = fsMeta.Parts[partIdx].Size
}
// TODO: Make necessary changes in future as explained in the below comment.
// All parts except the last part has to be of same size. We are introducing this
// check to see if any clients break. If clients do not break then we can optimize
// multipart PutObjectPart by writing the part at the right offset using pwrite()
// so that we don't need to do background append at all. i.e by the time we get
// CompleteMultipartUpload we already have the full file available which can be
// renamed to the main name-space.
if (i < len(parts)-1) && partSize != fsMeta.Parts[partIdx].Size {
fs.rwPool.Close(fsMetaPathMultipart)
return oi, traceError(PartsSizeUnequal{})
}
} }
// Wait for any competing PutObject() operation on bucket/object, since same namespace // Wait for any competing PutObject() operation on bucket/object, since same namespace

@ -341,6 +341,13 @@ func (e InvalidPart) Error() string {
return "One or more of the specified parts could not be found. The part may not have been uploaded, or the specified entity tag may not match the part's entity tag." return "One or more of the specified parts could not be found. The part may not have been uploaded, or the specified entity tag may not match the part's entity tag."
} }
// PartsSizeUnequal - All parts except the last part should be of the same size
type PartsSizeUnequal struct{}
func (e PartsSizeUnequal) Error() string {
return "All parts except the last part should be of the same size"
}
// PartTooSmall - error if part size is less than 5MB. // PartTooSmall - error if part size is less than 5MB.
type PartTooSmall struct { type PartTooSmall struct {
PartSize int64 PartSize int64

Loading…
Cancel
Save