diff --git a/cmd/fs-v1-multipart-common.go b/cmd/fs-v1-multipart-common.go index d994d8d7f..eb471c333 100644 --- a/cmd/fs-v1-multipart-common.go +++ b/cmd/fs-v1-multipart-common.go @@ -16,7 +16,10 @@ package cmd -import "path" +import ( + "path" + "time" +) // Returns if the prefix is a multipart upload. func (fs fsObjects) isMultipartUpload(bucket, prefix string) bool { @@ -52,11 +55,10 @@ func (fs fsObjects) isUploadIDExists(bucket, object, uploadID string) bool { return true } -// writeUploadJSON - create `uploads.json` or update it with new uploadID. -func (fs fsObjects) updateUploadJSON(bucket, object string, uCh uploadIDChange) error { +// updateUploadJSON - add or remove upload ID info in all `uploads.json`. +func (fs fsObjects) updateUploadJSON(bucket, object, uploadID string, initiated time.Time, isRemove bool) error { uploadsPath := path.Join(bucket, object, uploadsJSONFile) - uniqueID := getUUID() - tmpUploadsPath := uniqueID + tmpUploadsPath := getUUID() uploadsJSON, err := readUploadsJSON(bucket, object, fs.storage) if errorCause(err) == errFileNotFound { @@ -69,12 +71,12 @@ func (fs fsObjects) updateUploadJSON(bucket, object string, uCh uploadIDChange) } // update the uploadsJSON struct - if !uCh.isRemove { + if !isRemove { // Add the uploadID - uploadsJSON.AddUploadID(uCh.uploadID, uCh.initiated) + uploadsJSON.AddUploadID(uploadID, initiated) } else { // Remove the upload ID - uploadsJSON.RemoveUploadID(uCh.uploadID) + uploadsJSON.RemoveUploadID(uploadID) } // update the file or delete it? @@ -88,3 +90,13 @@ func (fs fsObjects) updateUploadJSON(bucket, object string, uCh uploadIDChange) } return err } + +// addUploadID - add upload ID and its initiated time to 'uploads.json'. +func (fs fsObjects) addUploadID(bucket, object string, uploadID string, initiated time.Time) error { + return fs.updateUploadJSON(bucket, object, uploadID, initiated, false) +} + +// removeUploadID - remove upload ID in 'uploads.json'. +func (fs fsObjects) removeUploadID(bucket, object string, uploadID string) error { + return fs.updateUploadJSON(bucket, object, uploadID, time.Time{}, true) +} diff --git a/cmd/fs-v1-multipart-common_test.go b/cmd/fs-v1-multipart-common_test.go index 53392ea6b..2d356cd4e 100644 --- a/cmd/fs-v1-multipart-common_test.go +++ b/cmd/fs-v1-multipart-common_test.go @@ -122,7 +122,7 @@ func TestFSWriteUploadJSON(t *testing.T) { t.Fatal("Unexpected err: ", err) } - if err := fs.updateUploadJSON(bucketName, objectName, uploadIDChange{uploadID, time.Now().UTC(), false}); err != nil { + if err := fs.addUploadID(bucketName, objectName, uploadID, time.Now().UTC()); err != nil { t.Fatal("Unexpected err: ", err) } @@ -131,8 +131,7 @@ func TestFSWriteUploadJSON(t *testing.T) { for i := 1; i <= 3; i++ { naughty := newNaughtyDisk(fsStorage, map[int]error{i: errFaultyDisk}, nil) fs.storage = naughty - if err := fs.updateUploadJSON(bucketName, objectName, - uploadIDChange{uploadID, time.Now().UTC(), false}); errorCause(err) != errFaultyDisk { + if err := fs.addUploadID(bucketName, objectName, uploadID, time.Now().UTC()); errorCause(err) != errFaultyDisk { t.Fatal("Unexpected err: ", err) } } diff --git a/cmd/fs-v1-multipart.go b/cmd/fs-v1-multipart.go index 0fafa7a5b..738e81715 100644 --- a/cmd/fs-v1-multipart.go +++ b/cmd/fs-v1-multipart.go @@ -238,8 +238,8 @@ func (fs fsObjects) newMultipartUpload(bucket string, object string, meta map[st uploadID = getUUID() initiated := time.Now().UTC() - // Create 'uploads.json' - if err = fs.updateUploadJSON(bucket, object, uploadIDChange{uploadID, initiated, false}); err != nil { + // Add upload ID to uploads.json + if err = fs.addUploadID(bucket, object, uploadID, initiated); err != nil { return "", err } uploadIDPath := path.Join(bucket, object, uploadID) @@ -685,7 +685,7 @@ func (fs fsObjects) CompleteMultipartUpload(bucket string, object string, upload defer objectMPartPathLock.Unlock() // remove entry from uploads.json - if err = fs.updateUploadJSON(bucket, object, uploadIDChange{uploadID: uploadID, isRemove: true}); err != nil { + if err := fs.removeUploadID(bucket, object, uploadID); err != nil { return "", toObjectErr(err, minioMetaMultipartBucket, path.Join(bucket, object)) } @@ -703,8 +703,9 @@ func (fs fsObjects) abortMultipartUpload(bucket, object, uploadID string) error return err } fs.bgAppend.remove(uploadID) - // remove entry from uploads.json with quorum - if err := fs.updateUploadJSON(bucket, object, uploadIDChange{uploadID: uploadID, isRemove: true}); err != nil { + + // remove upload ID in uploads.json + if err := fs.removeUploadID(bucket, object, uploadID); err != nil { return toObjectErr(err, bucket, object) } diff --git a/cmd/object-multipart-common.go b/cmd/object-multipart-common.go index c91c39404..2744a9f09 100644 --- a/cmd/object-multipart-common.go +++ b/cmd/object-multipart-common.go @@ -93,17 +93,6 @@ func newUploadsV1(format string) uploadsV1 { return uploadIDs } -// uploadIDChange - represents a change to uploads.json - either add -// or remove an upload id. -type uploadIDChange struct { - // the id being added or removed. - uploadID string - // time of upload start. only used in uploadid add operations. - initiated time.Time - // if true, removes uploadID and ignores initiated time. - isRemove bool -} - func writeUploadJSON(u *uploadsV1, uploadsPath, tmpPath string, disk StorageAPI) error { // Serialize to prepare to write to disk. uplBytes, wErr := json.Marshal(&u) diff --git a/cmd/xl-v1-multipart-common.go b/cmd/xl-v1-multipart-common.go index 40df49972..2ad17cea6 100644 --- a/cmd/xl-v1-multipart-common.go +++ b/cmd/xl-v1-multipart-common.go @@ -19,14 +19,13 @@ package cmd import ( "path" "sync" + "time" ) -// writeUploadJSON - create `uploads.json` or update it with change -// described in uCh. -func (xl xlObjects) updateUploadJSON(bucket, object string, uCh uploadIDChange) error { +// updateUploadJSON - add or remove upload ID info in all `uploads.json`. +func (xl xlObjects) updateUploadJSON(bucket, object, uploadID string, initiated time.Time, isRemove bool) error { uploadsPath := path.Join(bucket, object, uploadsJSONFile) - uniqueID := getUUID() - tmpUploadsPath := uniqueID + tmpUploadsPath := getUUID() // slice to store errors from disks errs := make([]error, len(xl.storageDisks)) @@ -58,12 +57,12 @@ func (xl xlObjects) updateUploadJSON(bucket, object string, uCh uploadIDChange) return } - if !uCh.isRemove { + if !isRemove { // Add the uploadID - uploadsJSON.AddUploadID(uCh.uploadID, uCh.initiated) + uploadsJSON.AddUploadID(uploadID, initiated) } else { // Remove the upload ID - uploadsJSON.RemoveUploadID(uCh.uploadID) + uploadsJSON.RemoveUploadID(uploadID) if len(uploadsJSON.Uploads) == 0 { isDelete[index] = true } @@ -146,6 +145,16 @@ func (xl xlObjects) updateUploadJSON(bucket, object string, uCh uploadIDChange) return nil } +// addUploadID - add upload ID and its initiated time to 'uploads.json'. +func (xl xlObjects) addUploadID(bucket, object string, uploadID string, initiated time.Time) error { + return xl.updateUploadJSON(bucket, object, uploadID, initiated, false) +} + +// removeUploadID - remove upload ID in 'uploads.json'. +func (xl xlObjects) removeUploadID(bucket, object string, uploadID string) error { + return xl.updateUploadJSON(bucket, object, uploadID, time.Time{}, true) +} + // Returns if the prefix is a multipart upload. func (xl xlObjects) isMultipartUpload(bucket, prefix string) bool { for _, disk := range xl.getLoadBalancedDisks() { diff --git a/cmd/xl-v1-multipart-common_test.go b/cmd/xl-v1-multipart-common_test.go index 41d9c1f11..b5eb77c7c 100644 --- a/cmd/xl-v1-multipart-common_test.go +++ b/cmd/xl-v1-multipart-common_test.go @@ -44,17 +44,19 @@ func TestUpdateUploadJSON(t *testing.T) { } testCases := []struct { - uCh uploadIDChange - errVal error + uploadID string + initiated time.Time + isRemove bool + errVal error }{ - {uploadIDChange{"111abc", time.Now().UTC(), false}, nil}, - {uploadIDChange{"222abc", time.Now().UTC(), false}, nil}, - {uploadIDChange{uploadID: "111abc", isRemove: true}, nil}, + {"111abc", time.Now().UTC(), false, nil}, + {"222abc", time.Now().UTC(), false, nil}, + {"111abc", time.Time{}, true, nil}, } xl := obj.(*xlObjects) for i, test := range testCases { - testErrVal := xl.updateUploadJSON(bucket, object, test.uCh) + testErrVal := xl.updateUploadJSON(bucket, object, test.uploadID, test.initiated, test.isRemove) if testErrVal != test.errVal { t.Errorf("Test %d: Expected error value %v, but got %v", i+1, test.errVal, testErrVal) @@ -66,7 +68,7 @@ func TestUpdateUploadJSON(t *testing.T) { xl.storageDisks[i] = newNaughtyDisk(xl.storageDisks[i].(*posix), nil, errFaultyDisk) } - testErrVal := xl.updateUploadJSON(bucket, object, uploadIDChange{"222abc", time.Now().UTC(), false}) + testErrVal := xl.updateUploadJSON(bucket, object, "222abc", time.Now().UTC(), false) if testErrVal == nil || testErrVal.Error() != errXLWriteQuorum.Error() { t.Errorf("Expected write quorum error, but got: %v", testErrVal) } diff --git a/cmd/xl-v1-multipart.go b/cmd/xl-v1-multipart.go index 61f6fcd55..89f0bfe93 100644 --- a/cmd/xl-v1-multipart.go +++ b/cmd/xl-v1-multipart.go @@ -306,7 +306,7 @@ func (xl xlObjects) newMultipartUpload(bucket string, object string, meta map[st initiated := time.Now().UTC() // Create or update 'uploads.json' - if err := xl.updateUploadJSON(bucket, object, uploadIDChange{uploadID, initiated, false}); err != nil { + if err := xl.addUploadID(bucket, object, uploadID, initiated); err != nil { return "", err } // Return success. @@ -839,7 +839,7 @@ func (xl xlObjects) CompleteMultipartUpload(bucket string, object string, upload defer objectMPartPathLock.Unlock() // remove entry from uploads.json with quorum - if err = xl.updateUploadJSON(bucket, object, uploadIDChange{uploadID: uploadID, isRemove: true}); err != nil { + if err = xl.removeUploadID(bucket, object, uploadID); err != nil { return "", toObjectErr(err, minioMetaMultipartBucket, path.Join(bucket, object)) } @@ -865,7 +865,7 @@ func (xl xlObjects) abortMultipartUpload(bucket, object, uploadID string) (err e defer objectMPartPathLock.Unlock() // remove entry from uploads.json with quorum - if err = xl.updateUploadJSON(bucket, object, uploadIDChange{uploadID: uploadID, isRemove: true}); err != nil { + if err = xl.removeUploadID(bucket, object, uploadID); err != nil { return toObjectErr(err, bucket, object) }