mirror of
https://github.com/seaweedfs/seaweedfs.git
synced 2025-09-20 02:38:04 +08:00
[s3] add s3 pass test_multipart_upload_size_too_small (#5475)
* add s3 pass test_multipart_upload_size_too_small * refactor metric names * return ErrNoSuchUpload if empty parts * fix test
This commit is contained in:

committed by
GitHub

parent
35cba720a5
commit
3e25ed1b11
2
.github/workflows/s3tests.yml
vendored
2
.github/workflows/s3tests.yml
vendored
@@ -169,6 +169,7 @@ jobs:
|
|||||||
s3tests_boto3/functional/test_s3.py::test_multipart_upload \
|
s3tests_boto3/functional/test_s3.py::test_multipart_upload \
|
||||||
s3tests_boto3/functional/test_s3.py::test_multipart_upload_contents \
|
s3tests_boto3/functional/test_s3.py::test_multipart_upload_contents \
|
||||||
s3tests_boto3/functional/test_s3.py::test_multipart_upload_overwrite_existing_object \
|
s3tests_boto3/functional/test_s3.py::test_multipart_upload_overwrite_existing_object \
|
||||||
|
s3tests_boto3/functional/test_s3.py::test_multipart_upload_size_too_small \
|
||||||
s3tests_boto3/functional/test_s3.py::test_abort_multipart_upload \
|
s3tests_boto3/functional/test_s3.py::test_abort_multipart_upload \
|
||||||
s3tests_boto3/functional/test_s3.py::test_list_multipart_upload \
|
s3tests_boto3/functional/test_s3.py::test_list_multipart_upload \
|
||||||
s3tests_boto3/functional/test_s3.py::test_atomic_read_1mb \
|
s3tests_boto3/functional/test_s3.py::test_atomic_read_1mb \
|
||||||
@@ -181,7 +182,6 @@ jobs:
|
|||||||
s3tests_boto3/functional/test_s3.py::test_atomic_dual_write_4mb \
|
s3tests_boto3/functional/test_s3.py::test_atomic_dual_write_4mb \
|
||||||
s3tests_boto3/functional/test_s3.py::test_atomic_dual_write_8mb \
|
s3tests_boto3/functional/test_s3.py::test_atomic_dual_write_8mb \
|
||||||
s3tests_boto3/functional/test_s3.py::test_atomic_multipart_upload_write \
|
s3tests_boto3/functional/test_s3.py::test_atomic_multipart_upload_write \
|
||||||
s3tests_boto3/functional/test_s3.py::test_multipart_resend_first_finishes_last \
|
|
||||||
s3tests_boto3/functional/test_s3.py::test_ranged_request_response_code \
|
s3tests_boto3/functional/test_s3.py::test_ranged_request_response_code \
|
||||||
s3tests_boto3/functional/test_s3.py::test_ranged_big_request_response_code \
|
s3tests_boto3/functional/test_s3.py::test_ranged_big_request_response_code \
|
||||||
s3tests_boto3/functional/test_s3.py::test_ranged_request_skip_leading_bytes_response_code \
|
s3tests_boto3/functional/test_s3.py::test_ranged_request_skip_leading_bytes_response_code \
|
||||||
|
@@ -25,7 +25,10 @@ import (
|
|||||||
"github.com/seaweedfs/seaweedfs/weed/pb/filer_pb"
|
"github.com/seaweedfs/seaweedfs/weed/pb/filer_pb"
|
||||||
)
|
)
|
||||||
|
|
||||||
const multipartExt = ".part"
|
const (
|
||||||
|
multipartExt = ".part"
|
||||||
|
multiPartMinSize = 5 * 1024 * 1024
|
||||||
|
)
|
||||||
|
|
||||||
type InitiateMultipartUploadResult struct {
|
type InitiateMultipartUploadResult struct {
|
||||||
XMLName xml.Name `xml:"http://s3.amazonaws.com/doc/2006-03-01/ InitiateMultipartUploadResult"`
|
XMLName xml.Name `xml:"http://s3.amazonaws.com/doc/2006-03-01/ InitiateMultipartUploadResult"`
|
||||||
@@ -75,6 +78,10 @@ type CompleteMultipartUploadResult struct {
|
|||||||
func (s3a *S3ApiServer) completeMultipartUpload(input *s3.CompleteMultipartUploadInput, parts *CompleteMultipartUpload) (output *CompleteMultipartUploadResult, code s3err.ErrorCode) {
|
func (s3a *S3ApiServer) completeMultipartUpload(input *s3.CompleteMultipartUploadInput, parts *CompleteMultipartUpload) (output *CompleteMultipartUploadResult, code s3err.ErrorCode) {
|
||||||
|
|
||||||
glog.V(2).Infof("completeMultipartUpload input %v", input)
|
glog.V(2).Infof("completeMultipartUpload input %v", input)
|
||||||
|
if len(parts.Parts) == 0 {
|
||||||
|
stats.S3HandlerCounter.WithLabelValues(stats.ErrorCompletedNoSuchUpload).Inc()
|
||||||
|
return nil, s3err.ErrNoSuchUpload
|
||||||
|
}
|
||||||
completedPartNumbers := []int{}
|
completedPartNumbers := []int{}
|
||||||
completedPartMap := make(map[int][]string)
|
completedPartMap := make(map[int][]string)
|
||||||
for _, part := range parts.Parts {
|
for _, part := range parts.Parts {
|
||||||
@@ -83,8 +90,9 @@ func (s3a *S3ApiServer) completeMultipartUpload(input *s3.CompleteMultipartUploa
|
|||||||
}
|
}
|
||||||
completedPartMap[part.PartNumber] = append(completedPartMap[part.PartNumber], part.ETag)
|
completedPartMap[part.PartNumber] = append(completedPartMap[part.PartNumber], part.ETag)
|
||||||
}
|
}
|
||||||
uploadDirectory := s3a.genUploadsFolder(*input.Bucket) + "/" + *input.UploadId
|
sort.Ints(completedPartNumbers)
|
||||||
|
|
||||||
|
uploadDirectory := s3a.genUploadsFolder(*input.Bucket) + "/" + *input.UploadId
|
||||||
entries, _, err := s3a.list(uploadDirectory, "", "", false, maxPartsList)
|
entries, _, err := s3a.list(uploadDirectory, "", "", false, maxPartsList)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
glog.Errorf("completeMultipartUpload %s %s error: %v, entries:%d", *input.Bucket, *input.UploadId, err, len(entries))
|
glog.Errorf("completeMultipartUpload %s %s error: %v, entries:%d", *input.Bucket, *input.UploadId, err, len(entries))
|
||||||
@@ -118,6 +126,7 @@ func (s3a *S3ApiServer) completeMultipartUpload(input *s3.CompleteMultipartUploa
|
|||||||
}
|
}
|
||||||
deleteEntries := []*filer_pb.Entry{}
|
deleteEntries := []*filer_pb.Entry{}
|
||||||
partEntries := make(map[int][]*filer_pb.Entry, len(entries))
|
partEntries := make(map[int][]*filer_pb.Entry, len(entries))
|
||||||
|
entityTooSmall := false
|
||||||
for _, entry := range entries {
|
for _, entry := range entries {
|
||||||
foundEntry := false
|
foundEntry := false
|
||||||
glog.V(4).Infof("completeMultipartUpload part entries %s", entry.Name)
|
glog.V(4).Infof("completeMultipartUpload part entries %s", entry.Name)
|
||||||
@@ -156,16 +165,23 @@ func (s3a *S3ApiServer) completeMultipartUpload(input *s3.CompleteMultipartUploa
|
|||||||
partEntries[partNumber] = append(partEntries[partNumber], entry)
|
partEntries[partNumber] = append(partEntries[partNumber], entry)
|
||||||
foundEntry = true
|
foundEntry = true
|
||||||
}
|
}
|
||||||
if !foundEntry {
|
if foundEntry {
|
||||||
|
if len(completedPartNumbers) > 1 && partNumber != completedPartNumbers[len(completedPartNumbers)-1] &&
|
||||||
|
entry.Attributes.FileSize < multiPartMinSize {
|
||||||
|
glog.Warningf("completeMultipartUpload %s part file size less 5mb", entry.Name)
|
||||||
|
entityTooSmall = true
|
||||||
|
}
|
||||||
|
} else {
|
||||||
deleteEntries = append(deleteEntries, entry)
|
deleteEntries = append(deleteEntries, entry)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
if entityTooSmall {
|
||||||
|
stats.S3HandlerCounter.WithLabelValues(stats.ErrorCompleteEntityTooSmall).Inc()
|
||||||
|
return nil, s3err.ErrEntityTooSmall
|
||||||
|
}
|
||||||
mime := pentry.Attributes.Mime
|
mime := pentry.Attributes.Mime
|
||||||
|
|
||||||
var finalParts []*filer_pb.FileChunk
|
var finalParts []*filer_pb.FileChunk
|
||||||
var offset int64
|
var offset int64
|
||||||
sort.Ints(completedPartNumbers)
|
|
||||||
for _, partNumber := range completedPartNumbers {
|
for _, partNumber := range completedPartNumbers {
|
||||||
partEntriesByNumber, ok := partEntries[partNumber]
|
partEntriesByNumber, ok := partEntries[partNumber]
|
||||||
if !ok {
|
if !ok {
|
||||||
|
@@ -46,8 +46,9 @@ const (
|
|||||||
|
|
||||||
// s3 handler
|
// s3 handler
|
||||||
ErrorCompletedNoSuchUpload = "errorCompletedNoSuchUpload"
|
ErrorCompletedNoSuchUpload = "errorCompletedNoSuchUpload"
|
||||||
ErrorCompletedPartEmpty = "ErrorCompletedPartEmpty"
|
ErrorCompleteEntityTooSmall = "errorCompleteEntityTooSmall"
|
||||||
ErrorCompletedPartNumber = "ErrorCompletedPartNumber"
|
ErrorCompletedPartEmpty = "errorCompletedPartEmpty"
|
||||||
|
ErrorCompletedPartNumber = "errorCompletedPartNumber"
|
||||||
ErrorCompletedPartNotFound = "errorCompletedPartNotFound"
|
ErrorCompletedPartNotFound = "errorCompletedPartNotFound"
|
||||||
ErrorCompletedEtagInvalid = "errorCompletedEtagInvalid"
|
ErrorCompletedEtagInvalid = "errorCompletedEtagInvalid"
|
||||||
ErrorCompletedEtagMismatch = "errorCompletedEtagMismatch"
|
ErrorCompletedEtagMismatch = "errorCompletedEtagMismatch"
|
||||||
|
Reference in New Issue
Block a user