mirror of
https://github.com/minio/minio.git
synced 2025-01-12 07:23:23 -05:00
parent
434423de89
commit
751fa972f5
@ -58,7 +58,7 @@ func (fs fsObjects) CompleteMultipartUpload(bucket string, object string, upload
|
|||||||
return "", InvalidUploadID{UploadID: uploadID}
|
return "", InvalidUploadID{UploadID: uploadID}
|
||||||
}
|
}
|
||||||
|
|
||||||
tempObj := path.Join(tmpMetaPrefix, bucket, object, uploadID)
|
tempObj := path.Join(tmpMetaPrefix, bucket, object, uploadID, incompleteFile)
|
||||||
fileWriter, err := fs.storage.CreateFile(minioMetaBucket, tempObj)
|
fileWriter, err := fs.storage.CreateFile(minioMetaBucket, tempObj)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return "", toObjectErr(err, bucket, object)
|
return "", toObjectErr(err, bucket, object)
|
||||||
@ -67,8 +67,8 @@ func (fs fsObjects) CompleteMultipartUpload(bucket string, object string, upload
|
|||||||
var md5Sums []string
|
var md5Sums []string
|
||||||
for _, part := range parts {
|
for _, part := range parts {
|
||||||
// Construct part suffix.
|
// Construct part suffix.
|
||||||
partSuffix := fmt.Sprintf("%s.%.5d.%s", uploadID, part.PartNumber, part.ETag)
|
partSuffix := fmt.Sprintf("%.5d.%s", part.PartNumber, part.ETag)
|
||||||
multipartPartFile := path.Join(mpartMetaPrefix, bucket, object, partSuffix)
|
multipartPartFile := path.Join(mpartMetaPrefix, bucket, object, uploadID, partSuffix)
|
||||||
var fileReader io.ReadCloser
|
var fileReader io.ReadCloser
|
||||||
fileReader, err = fs.storage.ReadFile(minioMetaBucket, multipartPartFile, 0)
|
fileReader, err = fs.storage.ReadFile(minioMetaBucket, multipartPartFile, 0)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
|
@ -32,7 +32,6 @@ type fsObjects struct {
|
|||||||
listObjectMapMutex *sync.Mutex
|
listObjectMapMutex *sync.Mutex
|
||||||
}
|
}
|
||||||
|
|
||||||
// FIXME: constructor should return a pointer.
|
|
||||||
// newFSObjects - initialize new fs object layer.
|
// newFSObjects - initialize new fs object layer.
|
||||||
func newFSObjects(exportPath string) (ObjectLayer, error) {
|
func newFSObjects(exportPath string) (ObjectLayer, error) {
|
||||||
var storage StorageAPI
|
var storage StorageAPI
|
||||||
|
@ -31,6 +31,42 @@ import (
|
|||||||
"github.com/skyrings/skyring-common/tools/uuid"
|
"github.com/skyrings/skyring-common/tools/uuid"
|
||||||
)
|
)
|
||||||
|
|
||||||
|
const (
|
||||||
|
incompleteFile = "00000.incomplete"
|
||||||
|
uploadsJSONFile = "uploads.json"
|
||||||
|
)
|
||||||
|
|
||||||
|
// createUploadsJSON - create uploads.json placeholder file.
|
||||||
|
func createUploadsJSON(storage StorageAPI, bucket, object, uploadID string) error {
|
||||||
|
// Place holder uploads.json
|
||||||
|
uploadsPath := path.Join(mpartMetaPrefix, bucket, object, uploadsJSONFile)
|
||||||
|
tmpUploadsPath := path.Join(tmpMetaPrefix, bucket, object, uploadID, uploadsJSONFile)
|
||||||
|
w, err := storage.CreateFile(minioMetaBucket, uploadsPath)
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
if err = w.Close(); err != nil {
|
||||||
|
if clErr := safeCloseAndRemove(w); clErr != nil {
|
||||||
|
return clErr
|
||||||
|
}
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
_, err = storage.StatFile(minioMetaBucket, uploadsPath)
|
||||||
|
if err != nil {
|
||||||
|
if err == errFileNotFound {
|
||||||
|
err = storage.RenameFile(minioMetaBucket, tmpUploadsPath, minioMetaBucket, uploadsPath)
|
||||||
|
if err == nil {
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if derr := storage.DeleteFile(minioMetaBucket, tmpUploadsPath); derr != nil {
|
||||||
|
return derr
|
||||||
|
}
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
/// Common multipart object layer functions.
|
/// Common multipart object layer functions.
|
||||||
|
|
||||||
// newMultipartUploadCommon - initialize a new multipart, is a common
|
// newMultipartUploadCommon - initialize a new multipart, is a common
|
||||||
@ -59,8 +95,13 @@ func newMultipartUploadCommon(storage StorageAPI, bucket string, object string)
|
|||||||
return "", err
|
return "", err
|
||||||
}
|
}
|
||||||
uploadID := uuid.String()
|
uploadID := uuid.String()
|
||||||
uploadIDPath := path.Join(mpartMetaPrefix, bucket, object, uploadID)
|
// Create placeholder file 'uploads.json'
|
||||||
tempUploadIDPath := path.Join(tmpMetaPrefix, bucket, object, uploadID)
|
err = createUploadsJSON(storage, bucket, object, uploadID)
|
||||||
|
if err != nil {
|
||||||
|
return "", err
|
||||||
|
}
|
||||||
|
uploadIDPath := path.Join(mpartMetaPrefix, bucket, object, uploadID, incompleteFile)
|
||||||
|
tempUploadIDPath := path.Join(tmpMetaPrefix, bucket, object, uploadID, incompleteFile)
|
||||||
if _, err = storage.StatFile(minioMetaBucket, uploadIDPath); err != nil {
|
if _, err = storage.StatFile(minioMetaBucket, uploadIDPath); err != nil {
|
||||||
if err != errFileNotFound {
|
if err != errFileNotFound {
|
||||||
return "", toObjectErr(err, minioMetaBucket, uploadIDPath)
|
return "", toObjectErr(err, minioMetaBucket, uploadIDPath)
|
||||||
@ -114,7 +155,7 @@ func putObjectPartCommon(storage StorageAPI, bucket string, object string, uploa
|
|||||||
return "", InvalidUploadID{UploadID: uploadID}
|
return "", InvalidUploadID{UploadID: uploadID}
|
||||||
}
|
}
|
||||||
|
|
||||||
partSuffix := fmt.Sprintf("%s.%d", uploadID, partID)
|
partSuffix := fmt.Sprintf("%s.%.5d", uploadID, partID)
|
||||||
partSuffixPath := path.Join(tmpMetaPrefix, bucket, object, partSuffix)
|
partSuffixPath := path.Join(tmpMetaPrefix, bucket, object, partSuffix)
|
||||||
fileWriter, err := storage.CreateFile(minioMetaBucket, partSuffixPath)
|
fileWriter, err := storage.CreateFile(minioMetaBucket, partSuffixPath)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
@ -170,8 +211,8 @@ func putObjectPartCommon(storage StorageAPI, bucket string, object string, uploa
|
|||||||
return "", err
|
return "", err
|
||||||
}
|
}
|
||||||
|
|
||||||
partSuffixMD5 := fmt.Sprintf("%s.%.5d.%s", uploadID, partID, newMD5Hex)
|
partSuffixMD5 := fmt.Sprintf("%.5d.%s", partID, newMD5Hex)
|
||||||
partSuffixMD5Path := path.Join(mpartMetaPrefix, bucket, object, partSuffixMD5)
|
partSuffixMD5Path := path.Join(mpartMetaPrefix, bucket, object, uploadID, partSuffixMD5)
|
||||||
err = storage.RenameFile(minioMetaBucket, partSuffixPath, minioMetaBucket, partSuffixMD5Path)
|
err = storage.RenameFile(minioMetaBucket, partSuffixPath, minioMetaBucket, partSuffixMD5Path)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
if derr := storage.DeleteFile(minioMetaBucket, partSuffixPath); derr != nil {
|
if derr := storage.DeleteFile(minioMetaBucket, partSuffixPath); derr != nil {
|
||||||
@ -190,18 +231,16 @@ func cleanupAllTmpEntries(storage StorageAPI) error {
|
|||||||
// Wrapper to which removes all the uploaded parts after a successful
|
// Wrapper to which removes all the uploaded parts after a successful
|
||||||
// complete multipart upload.
|
// complete multipart upload.
|
||||||
func cleanupUploadedParts(storage StorageAPI, prefix, bucket, object, uploadID string) error {
|
func cleanupUploadedParts(storage StorageAPI, prefix, bucket, object, uploadID string) error {
|
||||||
multipartDir := path.Join(prefix, bucket, object)
|
multipartDir := path.Join(prefix, bucket, object, uploadID)
|
||||||
entries, err := storage.ListDir(minioMetaBucket, multipartDir)
|
entries, err := storage.ListDir(minioMetaBucket, multipartDir)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
for _, entry := range entries {
|
for _, entry := range entries {
|
||||||
if strings.HasPrefix(entry, uploadID) {
|
|
||||||
if err = storage.DeleteFile(minioMetaBucket, path.Join(multipartDir, entry)); err != nil {
|
if err = storage.DeleteFile(minioMetaBucket, path.Join(multipartDir, entry)); err != nil {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -223,20 +262,39 @@ func abortMultipartUploadCommon(storage StorageAPI, bucket, object, uploadID str
|
|||||||
return cleanupUploadedParts(storage, mpartMetaPrefix, bucket, object, uploadID)
|
return cleanupUploadedParts(storage, mpartMetaPrefix, bucket, object, uploadID)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// isIncompleteMultipart - is object incomplete multipart.
|
||||||
|
func isIncompleteMultipart(storage StorageAPI, objectPath string) (bool, error) {
|
||||||
|
_, err := storage.StatFile(minioMetaBucket, path.Join(objectPath, uploadsJSONFile))
|
||||||
|
if err != nil {
|
||||||
|
if err == errFileNotFound {
|
||||||
|
return false, nil
|
||||||
|
}
|
||||||
|
return false, err
|
||||||
|
}
|
||||||
|
return true, nil
|
||||||
|
}
|
||||||
|
|
||||||
// listLeafEntries - lists all entries if a given prefixPath is a leaf
|
// listLeafEntries - lists all entries if a given prefixPath is a leaf
|
||||||
// directory, returns error if any - returns empty list if prefixPath
|
// directory, returns error if any - returns empty list if prefixPath
|
||||||
// is not a leaf directory.
|
// is not a leaf directory.
|
||||||
func listLeafEntries(storage StorageAPI, prefixPath string) (entries []string, err error) {
|
func listLeafEntries(storage StorageAPI, prefixPath string) (entries []string, err error) {
|
||||||
|
var ok bool
|
||||||
|
if ok, err = isIncompleteMultipart(storage, prefixPath); err != nil {
|
||||||
|
return nil, err
|
||||||
|
} else if !ok {
|
||||||
|
return nil, nil
|
||||||
|
}
|
||||||
entries, err = storage.ListDir(minioMetaBucket, prefixPath)
|
entries, err = storage.ListDir(minioMetaBucket, prefixPath)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, err
|
return nil, err
|
||||||
}
|
}
|
||||||
|
var newEntries []string
|
||||||
for _, entry := range entries {
|
for _, entry := range entries {
|
||||||
if strings.HasSuffix(entry, slashSeparator) {
|
if strings.HasSuffix(entry, slashSeparator) {
|
||||||
return nil, nil
|
newEntries = append(newEntries, entry)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
return entries, nil
|
return newEntries, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
// listMetaBucketMultipartFiles - list all files at a given prefix inside minioMetaBucket.
|
// listMetaBucketMultipartFiles - list all files at a given prefix inside minioMetaBucket.
|
||||||
@ -299,51 +357,34 @@ func listMetaBucketMultipartFiles(layer ObjectLayer, prefixPath string, markerPa
|
|||||||
// We reach here for non-recursive case and a leaf entry.
|
// We reach here for non-recursive case and a leaf entry.
|
||||||
sort.Strings(entries)
|
sort.Strings(entries)
|
||||||
for _, entry := range entries {
|
for _, entry := range entries {
|
||||||
if strings.ContainsRune(entry, '.') {
|
|
||||||
continue
|
|
||||||
}
|
|
||||||
var fileInfo FileInfo
|
var fileInfo FileInfo
|
||||||
fileInfo, err = storage.StatFile(minioMetaBucket, path.Join(fi.Name, entry))
|
incompleteUploadFile := path.Join(fi.Name, entry, incompleteFile)
|
||||||
|
fileInfo, err = storage.StatFile(minioMetaBucket, incompleteUploadFile)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, false, err
|
return nil, false, err
|
||||||
}
|
}
|
||||||
|
fileInfo.Name = path.Join(fi.Name, entry)
|
||||||
fileInfos = append(fileInfos, fileInfo)
|
fileInfos = append(fileInfos, fileInfo)
|
||||||
newMaxKeys++
|
|
||||||
// If we have reached the maxKeys, it means we have listed
|
|
||||||
// everything that was requested. Return right here.
|
|
||||||
if newMaxKeys == maxKeys {
|
|
||||||
// Return values:
|
|
||||||
// allFileInfos : "maxKeys" number of entries.
|
|
||||||
// eof : eof returned by fs.storage.ListFiles()
|
|
||||||
// error : nil
|
|
||||||
return
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
// We reach here for a non-recursive case non-leaf entry
|
// We reach here for a non-recursive case non-leaf entry
|
||||||
// OR recursive case with fi.Name matching pattern bucket/object/uploadID[.partNum.md5sum]
|
// OR recursive case with fi.Name.
|
||||||
if !fi.Mode.IsDir() { // Do not skip non-recursive case directory entries.
|
if !fi.Mode.IsDir() { // Do not skip non-recursive case directory entries.
|
||||||
// Skip files matching pattern bucket/object/uploadID.partNum.md5sum
|
// Validate if 'fi.Name' is incomplete multipart.
|
||||||
// and retain files matching pattern bucket/object/uploadID
|
if !strings.HasSuffix(fi.Name, incompleteFile) {
|
||||||
specialFile := path.Base(fi.Name)
|
|
||||||
if strings.Contains(specialFile, ".") {
|
|
||||||
// Contains partnumber and md5sum info, skip this.
|
|
||||||
continue
|
continue
|
||||||
}
|
}
|
||||||
|
fi.Name = path.Dir(fi.Name)
|
||||||
}
|
}
|
||||||
fileInfos = append(fileInfos, fi)
|
fileInfos = append(fileInfos, fi)
|
||||||
|
}
|
||||||
newMaxKeys++
|
newMaxKeys++
|
||||||
// If we have reached the maxKeys, it means we have listed
|
// If we have reached the maxKeys, it means we have listed
|
||||||
// everything that was requested. Return right here.
|
// everything that was requested. Return right here.
|
||||||
if newMaxKeys == maxKeys {
|
if newMaxKeys == maxKeys {
|
||||||
// Return values:
|
|
||||||
// allFileInfos : "maxKeys" number of entries.
|
|
||||||
// eof : eof returned by fs.storage.ListFiles()
|
|
||||||
// error : nil
|
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
|
||||||
|
|
||||||
// Return entries here.
|
// Return entries here.
|
||||||
return fileInfos, eof, nil
|
return fileInfos, eof, nil
|
||||||
@ -465,35 +506,29 @@ func listObjectPartsCommon(storage StorageAPI, bucket, object, uploadID string,
|
|||||||
return ListPartsInfo{}, (InvalidUploadID{UploadID: uploadID})
|
return ListPartsInfo{}, (InvalidUploadID{UploadID: uploadID})
|
||||||
}
|
}
|
||||||
result := ListPartsInfo{}
|
result := ListPartsInfo{}
|
||||||
entries, err := storage.ListDir(minioMetaBucket, path.Join(mpartMetaPrefix, bucket, object))
|
entries, err := storage.ListDir(minioMetaBucket, path.Join(mpartMetaPrefix, bucket, object, uploadID))
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return result, err
|
return result, err
|
||||||
}
|
}
|
||||||
sort.Strings(entries)
|
sort.Strings(entries)
|
||||||
var newEntries []string
|
var newEntries []string
|
||||||
for _, entry := range entries {
|
for _, entry := range entries {
|
||||||
if !strings.Contains(entry, ".") {
|
newEntries = append(newEntries, path.Base(entry))
|
||||||
continue
|
|
||||||
}
|
}
|
||||||
if !strings.HasPrefix(entry, uploadID) {
|
idx := sort.SearchStrings(newEntries, fmt.Sprintf("%.5d.", partNumberMarker+1))
|
||||||
continue
|
|
||||||
}
|
|
||||||
newEntries = append(newEntries, entry)
|
|
||||||
}
|
|
||||||
idx := sort.SearchStrings(newEntries, fmt.Sprintf("%s.%.5d.", uploadID, partNumberMarker+1))
|
|
||||||
newEntries = newEntries[idx:]
|
newEntries = newEntries[idx:]
|
||||||
count := maxParts
|
count := maxParts
|
||||||
for _, entry := range newEntries {
|
for _, entry := range newEntries {
|
||||||
fi, err := storage.StatFile(minioMetaBucket, path.Join(mpartMetaPrefix, bucket, object, entry))
|
fi, err := storage.StatFile(minioMetaBucket, path.Join(mpartMetaPrefix, bucket, object, uploadID, entry))
|
||||||
splitEntry := strings.Split(entry, ".")
|
splitEntry := strings.Split(entry, ".")
|
||||||
partNum, err := strconv.Atoi(splitEntry[1])
|
partNum, err := strconv.Atoi(splitEntry[0])
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return ListPartsInfo{}, err
|
return ListPartsInfo{}, err
|
||||||
}
|
}
|
||||||
result.Parts = append(result.Parts, partInfo{
|
result.Parts = append(result.Parts, partInfo{
|
||||||
PartNumber: partNum,
|
PartNumber: partNum,
|
||||||
LastModified: fi.ModTime,
|
LastModified: fi.ModTime,
|
||||||
ETag: splitEntry[2],
|
ETag: splitEntry[1],
|
||||||
Size: fi.Size,
|
Size: fi.Size,
|
||||||
})
|
})
|
||||||
count--
|
count--
|
||||||
@ -513,7 +548,7 @@ func listObjectPartsCommon(storage StorageAPI, bucket, object, uploadID string,
|
|||||||
|
|
||||||
// isUploadIDExists - verify if a given uploadID exists and is valid.
|
// isUploadIDExists - verify if a given uploadID exists and is valid.
|
||||||
func isUploadIDExists(storage StorageAPI, bucket, object, uploadID string) (bool, error) {
|
func isUploadIDExists(storage StorageAPI, bucket, object, uploadID string) (bool, error) {
|
||||||
uploadIDPath := path.Join(mpartMetaPrefix, bucket, object, uploadID)
|
uploadIDPath := path.Join(mpartMetaPrefix, bucket, object, uploadID, incompleteFile)
|
||||||
st, err := storage.StatFile(minioMetaBucket, uploadIDPath)
|
st, err := storage.StatFile(minioMetaBucket, uploadIDPath)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
// Upload id does not exist.
|
// Upload id does not exist.
|
||||||
|
@ -758,7 +758,8 @@ func (api objectAPIHandlers) PutObjectPartHandler(w http.ResponseWriter, r *http
|
|||||||
// Close the writer.
|
// Close the writer.
|
||||||
writer.Close()
|
writer.Close()
|
||||||
}()
|
}()
|
||||||
partMD5, err = api.ObjectAPI.PutObjectPart(bucket, object, uploadID, partID, size, reader, hex.EncodeToString(md5Bytes))
|
md5SumHex := hex.EncodeToString(md5Bytes)
|
||||||
|
partMD5, err = api.ObjectAPI.PutObjectPart(bucket, object, uploadID, partID, size, reader, md5SumHex)
|
||||||
}
|
}
|
||||||
if err != nil {
|
if err != nil {
|
||||||
errorIf(err, "PutObjectPart failed.", nil)
|
errorIf(err, "PutObjectPart failed.", nil)
|
||||||
|
11
tree-walk.go
11
tree-walk.go
@ -131,10 +131,15 @@ func treeWalk(layer ObjectLayer, bucket, prefixDir, entryPrefixMatch, marker str
|
|||||||
// For XL multipart files strip the trailing "/" and append ".minio.multipart" to the entry so that
|
// For XL multipart files strip the trailing "/" and append ".minio.multipart" to the entry so that
|
||||||
// entryToFileInfo() can call StatFile for regular files or getMultipartObjectInfo() for multipart files.
|
// entryToFileInfo() can call StatFile for regular files or getMultipartObjectInfo() for multipart files.
|
||||||
for i, entry := range entries {
|
for i, entry := range entries {
|
||||||
if isXL && strings.HasSuffix(entry, slashSeparator) && isLeafDirectory(disk, bucket, path.Join(prefixDir, entry)) {
|
if isXL && strings.HasSuffix(entry, slashSeparator) {
|
||||||
|
if ok, err := isMultipartObject(disk, bucket, path.Join(prefixDir, entry)); err != nil {
|
||||||
|
send(treeWalkResult{err: err})
|
||||||
|
return false
|
||||||
|
} else if ok {
|
||||||
entries[i] = strings.TrimSuffix(entry, slashSeparator) + multipartSuffix
|
entries[i] = strings.TrimSuffix(entry, slashSeparator) + multipartSuffix
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
}
|
||||||
sort.Sort(byMultipartFiles(entries))
|
sort.Sort(byMultipartFiles(entries))
|
||||||
// Skip the empty strings
|
// Skip the empty strings
|
||||||
for len(entries) > 0 && entries[0] == "" {
|
for len(entries) > 0 && entries[0] == "" {
|
||||||
@ -146,7 +151,9 @@ func treeWalk(layer ObjectLayer, bucket, prefixDir, entryPrefixMatch, marker str
|
|||||||
// example:
|
// example:
|
||||||
// If markerDir="four/" Search() returns the index of "four/" in the sorted
|
// If markerDir="four/" Search() returns the index of "four/" in the sorted
|
||||||
// entries list so we skip all the entries till "four/"
|
// entries list so we skip all the entries till "four/"
|
||||||
idx := sort.Search(len(entries), func(i int) bool { return strings.TrimSuffix(entries[i], multipartSuffix) >= markerDir })
|
idx := sort.Search(len(entries), func(i int) bool {
|
||||||
|
return strings.TrimSuffix(entries[i], multipartSuffix) >= markerDir
|
||||||
|
})
|
||||||
entries = entries[idx:]
|
entries = entries[idx:]
|
||||||
*count += len(entries)
|
*count += len(entries)
|
||||||
for i, entry := range entries {
|
for i, entry := range entries {
|
||||||
|
@ -111,8 +111,8 @@ func (xl xlObjects) CompleteMultipartUpload(bucket string, object string, upload
|
|||||||
var md5Sums []string
|
var md5Sums []string
|
||||||
for _, part := range parts {
|
for _, part := range parts {
|
||||||
// Construct part suffix.
|
// Construct part suffix.
|
||||||
partSuffix := fmt.Sprintf("%s.%.5d.%s", uploadID, part.PartNumber, part.ETag)
|
partSuffix := fmt.Sprintf("%.5d.%s", part.PartNumber, part.ETag)
|
||||||
multipartPartFile := path.Join(mpartMetaPrefix, bucket, object, partSuffix)
|
multipartPartFile := path.Join(mpartMetaPrefix, bucket, object, uploadID, partSuffix)
|
||||||
fi, err := xl.storage.StatFile(minioMetaBucket, multipartPartFile)
|
fi, err := xl.storage.StatFile(minioMetaBucket, multipartPartFile)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
if err == errFileNotFound {
|
if err == errFileNotFound {
|
||||||
@ -179,8 +179,8 @@ func (xl xlObjects) CompleteMultipartUpload(bucket string, object string, upload
|
|||||||
|
|
||||||
// Attempt a rename of the upload id to temporary location, if
|
// Attempt a rename of the upload id to temporary location, if
|
||||||
// successful then delete it.
|
// successful then delete it.
|
||||||
uploadIDPath := path.Join(mpartMetaPrefix, bucket, object, uploadID)
|
uploadIDPath := path.Join(mpartMetaPrefix, bucket, object, uploadID, incompleteFile)
|
||||||
tempUploadIDPath := path.Join(tmpMetaPrefix, bucket, object, uploadID)
|
tempUploadIDPath := path.Join(tmpMetaPrefix, bucket, object, uploadID, incompleteFile)
|
||||||
if err = xl.storage.RenameFile(minioMetaBucket, uploadIDPath, minioMetaBucket, tempUploadIDPath); err == nil {
|
if err = xl.storage.RenameFile(minioMetaBucket, uploadIDPath, minioMetaBucket, tempUploadIDPath); err == nil {
|
||||||
if err = xl.storage.DeleteFile(minioMetaBucket, tempUploadIDPath); err != nil {
|
if err = xl.storage.DeleteFile(minioMetaBucket, tempUploadIDPath); err != nil {
|
||||||
return "", toObjectErr(err, minioMetaBucket, tempUploadIDPath)
|
return "", toObjectErr(err, minioMetaBucket, tempUploadIDPath)
|
||||||
@ -192,6 +192,13 @@ func (xl xlObjects) CompleteMultipartUpload(bucket string, object string, upload
|
|||||||
if err != nil {
|
if err != nil {
|
||||||
return "", toObjectErr(err, minioMetaBucket, uploadIDPath)
|
return "", toObjectErr(err, minioMetaBucket, uploadIDPath)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
uploadsJSONPath := path.Join(mpartMetaPrefix, bucket, object, uploadsJSONFile)
|
||||||
|
err = xl.storage.DeleteFile(minioMetaBucket, uploadsJSONPath)
|
||||||
|
if err != nil {
|
||||||
|
return "", toObjectErr(err, minioMetaBucket, uploadsJSONPath)
|
||||||
|
}
|
||||||
|
|
||||||
// Return md5sum.
|
// Return md5sum.
|
||||||
return s3MD5, nil
|
return s3MD5, nil
|
||||||
}
|
}
|
||||||
|
@ -40,11 +40,6 @@ type xlObjects struct {
|
|||||||
listObjectMapMutex *sync.Mutex
|
listObjectMapMutex *sync.Mutex
|
||||||
}
|
}
|
||||||
|
|
||||||
func isLeafDirectory(disk StorageAPI, volume, leafPath string) bool {
|
|
||||||
_, err := disk.StatFile(volume, pathJoin(leafPath, multipartMetaFile))
|
|
||||||
return err == nil
|
|
||||||
}
|
|
||||||
|
|
||||||
// isValidFormat - validates input arguments with backend 'format.json'
|
// isValidFormat - validates input arguments with backend 'format.json'
|
||||||
func isValidFormat(storage StorageAPI, exportPaths ...string) bool {
|
func isValidFormat(storage StorageAPI, exportPaths ...string) bool {
|
||||||
// Load saved XL format.json and validate.
|
// Load saved XL format.json and validate.
|
||||||
@ -70,7 +65,6 @@ func isValidFormat(storage StorageAPI, exportPaths ...string) bool {
|
|||||||
return true
|
return true
|
||||||
}
|
}
|
||||||
|
|
||||||
// FIXME: constructor should return a pointer.
|
|
||||||
// newXLObjects - initialize new xl object layer.
|
// newXLObjects - initialize new xl object layer.
|
||||||
func newXLObjects(exportPaths ...string) (ObjectLayer, error) {
|
func newXLObjects(exportPaths ...string) (ObjectLayer, error) {
|
||||||
storage, err := newXL(exportPaths...)
|
storage, err := newXL(exportPaths...)
|
||||||
@ -289,9 +283,19 @@ func (xl xlObjects) DeleteObject(bucket, object string) error {
|
|||||||
return toObjectErr(err, bucket, object)
|
return toObjectErr(err, bucket, object)
|
||||||
}
|
}
|
||||||
// Range through all files and delete it.
|
// Range through all files and delete it.
|
||||||
|
var wg = &sync.WaitGroup{}
|
||||||
|
var errChs = make([]chan error, len(info.Parts))
|
||||||
for _, part := range info.Parts {
|
for _, part := range info.Parts {
|
||||||
|
wg.Add(1)
|
||||||
|
go func(part MultipartPartInfo) {
|
||||||
|
defer wg.Done()
|
||||||
err = xl.storage.DeleteFile(bucket, pathJoin(object, partNumToPartFileName(part.PartNumber)))
|
err = xl.storage.DeleteFile(bucket, pathJoin(object, partNumToPartFileName(part.PartNumber)))
|
||||||
if err != nil {
|
errChs[part.PartNumber-1] <- err
|
||||||
|
}(part)
|
||||||
|
}
|
||||||
|
wg.Wait()
|
||||||
|
for _, errCh := range errChs {
|
||||||
|
if err = <-errCh; err != nil {
|
||||||
return toObjectErr(err, bucket, object)
|
return toObjectErr(err, bucket, object)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -302,6 +306,7 @@ func (xl xlObjects) DeleteObject(bucket, object string) error {
|
|||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// ListObjects - list all objects at prefix, delimited by '/'.
|
||||||
func (xl xlObjects) ListObjects(bucket, prefix, marker, delimiter string, maxKeys int) (ListObjectsInfo, error) {
|
func (xl xlObjects) ListObjects(bucket, prefix, marker, delimiter string, maxKeys int) (ListObjectsInfo, error) {
|
||||||
return listObjectsCommon(xl, bucket, prefix, marker, delimiter, maxKeys)
|
return listObjectsCommon(xl, bucket, prefix, marker, delimiter, maxKeys)
|
||||||
}
|
}
|
||||||
|
Loading…
Reference in New Issue
Block a user