mirror of
				https://github.com/minio/minio.git
				synced 2025-10-28 23:35:01 -04:00 
			
		
		
		
	Protect multipart directory from removing when it is empty (#3315)
This commit is contained in:
		
							parent
							
								
									dd93f808c8
								
							
						
					
					
						commit
						339c9019b9
					
				| @ -178,7 +178,7 @@ func (b *backgroundAppend) appendParts(disk StorageAPI, bucket, object, uploadID | ||||
| // Appends the "part" to the append-file inside "tmp/" that finally gets moved to the actual location | ||||
| // upon complete-multipart-upload. | ||||
| func appendPart(disk StorageAPI, bucket, object, uploadID string, part objectPartInfo) error { | ||||
| 	partPath := pathJoin(mpartMetaPrefix, bucket, object, uploadID, part.Name) | ||||
| 	partPath := pathJoin(bucket, object, uploadID, part.Name) | ||||
| 	appendFilePath := getFSAppendDataPath(uploadID) | ||||
| 
 | ||||
| 	offset := int64(0) | ||||
| @ -190,7 +190,7 @@ func appendPart(disk StorageAPI, bucket, object, uploadID string, part objectPar | ||||
| 			curLeft = totalLeft | ||||
| 		} | ||||
| 		var n int64 | ||||
| 		n, err := disk.ReadFile(minioMetaBucket, partPath, offset, buf[:curLeft]) | ||||
| 		n, err := disk.ReadFile(minioMetaMultipartBucket, partPath, offset, buf[:curLeft]) | ||||
| 		if err != nil { | ||||
| 			// Check for EOF/ErrUnexpectedEOF not needed as it should never happen as we know | ||||
| 			// the exact size of the file and hence know the size of buf[] | ||||
|  | ||||
| @ -40,13 +40,13 @@ func (fs fsObjects) isBucketExist(bucket string) bool { | ||||
| 
 | ||||
| // isUploadIDExists - verify if a given uploadID exists and is valid. | ||||
| func (fs fsObjects) isUploadIDExists(bucket, object, uploadID string) bool { | ||||
| 	uploadIDPath := path.Join(mpartMetaPrefix, bucket, object, uploadID) | ||||
| 	_, err := fs.storage.StatFile(minioMetaBucket, path.Join(uploadIDPath, fsMetaJSONFile)) | ||||
| 	uploadIDPath := path.Join(bucket, object, uploadID) | ||||
| 	_, err := fs.storage.StatFile(minioMetaMultipartBucket, path.Join(uploadIDPath, fsMetaJSONFile)) | ||||
| 	if err != nil { | ||||
| 		if err == errFileNotFound { | ||||
| 			return false | ||||
| 		} | ||||
| 		errorIf(err, "Unable to access upload id"+uploadIDPath) | ||||
| 		errorIf(err, "Unable to access upload id "+pathJoin(minioMetaMultipartBucket, uploadIDPath)) | ||||
| 		return false | ||||
| 	} | ||||
| 	return true | ||||
| @ -54,7 +54,7 @@ func (fs fsObjects) isUploadIDExists(bucket, object, uploadID string) bool { | ||||
| 
 | ||||
| // writeUploadJSON - create `uploads.json` or update it with new uploadID. | ||||
| func (fs fsObjects) updateUploadJSON(bucket, object string, uCh uploadIDChange) error { | ||||
| 	uploadsPath := path.Join(mpartMetaPrefix, bucket, object, uploadsJSONFile) | ||||
| 	uploadsPath := path.Join(bucket, object, uploadsJSONFile) | ||||
| 	uniqueID := getUUID() | ||||
| 	tmpUploadsPath := uniqueID | ||||
| 
 | ||||
| @ -82,8 +82,8 @@ func (fs fsObjects) updateUploadJSON(bucket, object string, uCh uploadIDChange) | ||||
| 		err = writeUploadJSON(&uploadsJSON, uploadsPath, tmpUploadsPath, fs.storage) | ||||
| 	} else { | ||||
| 		// no uploads, so we delete the file. | ||||
| 		if err = fs.storage.DeleteFile(minioMetaBucket, uploadsPath); err != nil { | ||||
| 			return toObjectErr(traceError(err), minioMetaBucket, uploadsPath) | ||||
| 		if err = fs.storage.DeleteFile(minioMetaMultipartBucket, uploadsPath); err != nil { | ||||
| 			return toObjectErr(traceError(err), minioMetaMultipartBucket, uploadsPath) | ||||
| 		} | ||||
| 	} | ||||
| 	return err | ||||
|  | ||||
| @ -45,7 +45,7 @@ func (fs fsObjects) listMultipartUploads(bucket, prefix, keyMarker, uploadIDMark | ||||
| 	result.Delimiter = delimiter | ||||
| 
 | ||||
| 	// Not using path.Join() as it strips off the trailing '/'. | ||||
| 	multipartPrefixPath := pathJoin(mpartMetaPrefix, bucket, prefix) | ||||
| 	multipartPrefixPath := pathJoin(bucket, prefix) | ||||
| 	if prefix == "" { | ||||
| 		// Should have a trailing "/" if prefix is "" | ||||
| 		// For ex. multipartPrefixPath should be "multipart/bucket/" if prefix is "" | ||||
| @ -53,14 +53,14 @@ func (fs fsObjects) listMultipartUploads(bucket, prefix, keyMarker, uploadIDMark | ||||
| 	} | ||||
| 	multipartMarkerPath := "" | ||||
| 	if keyMarker != "" { | ||||
| 		multipartMarkerPath = pathJoin(mpartMetaPrefix, bucket, keyMarker) | ||||
| 		multipartMarkerPath = pathJoin(bucket, keyMarker) | ||||
| 	} | ||||
| 	var uploads []uploadMetadata | ||||
| 	var err error | ||||
| 	var eof bool | ||||
| 	if uploadIDMarker != "" { | ||||
| 		keyMarkerLock := nsMutex.NewNSLock(minioMetaBucket, | ||||
| 			pathJoin(mpartMetaPrefix, bucket, keyMarker)) | ||||
| 		keyMarkerLock := nsMutex.NewNSLock(minioMetaMultipartBucket, | ||||
| 			pathJoin(bucket, keyMarker)) | ||||
| 		keyMarkerLock.RLock() | ||||
| 		uploads, _, err = listMultipartUploadIDs(bucket, keyMarker, uploadIDMarker, maxUploads, fs.storage) | ||||
| 		keyMarkerLock.RUnlock() | ||||
| @ -73,12 +73,12 @@ func (fs fsObjects) listMultipartUploads(bucket, prefix, keyMarker, uploadIDMark | ||||
| 	var endWalkCh chan struct{} | ||||
| 	heal := false // true only for xl.ListObjectsHeal() | ||||
| 	if maxUploads > 0 { | ||||
| 		walkResultCh, endWalkCh = fs.listPool.Release(listParams{minioMetaBucket, recursive, multipartMarkerPath, multipartPrefixPath, heal}) | ||||
| 		walkResultCh, endWalkCh = fs.listPool.Release(listParams{minioMetaMultipartBucket, recursive, multipartMarkerPath, multipartPrefixPath, heal}) | ||||
| 		if walkResultCh == nil { | ||||
| 			endWalkCh = make(chan struct{}) | ||||
| 			isLeaf := fs.isMultipartUpload | ||||
| 			listDir := listDirFactory(isLeaf, fsTreeWalkIgnoredErrs, fs.storage) | ||||
| 			walkResultCh = startTreeWalk(minioMetaBucket, multipartPrefixPath, multipartMarkerPath, recursive, listDir, isLeaf, endWalkCh) | ||||
| 			walkResultCh = startTreeWalk(minioMetaMultipartBucket, multipartPrefixPath, multipartMarkerPath, recursive, listDir, isLeaf, endWalkCh) | ||||
| 		} | ||||
| 		for maxUploads > 0 { | ||||
| 			walkResult, ok := <-walkResultCh | ||||
| @ -96,7 +96,7 @@ func (fs fsObjects) listMultipartUploads(bucket, prefix, keyMarker, uploadIDMark | ||||
| 				} | ||||
| 				return ListMultipartsInfo{}, walkResult.err | ||||
| 			} | ||||
| 			entry := strings.TrimPrefix(walkResult.entry, retainSlash(pathJoin(mpartMetaPrefix, bucket))) | ||||
| 			entry := strings.TrimPrefix(walkResult.entry, retainSlash(bucket)) | ||||
| 			if strings.HasSuffix(walkResult.entry, slashSeparator) { | ||||
| 				uploads = append(uploads, uploadMetadata{ | ||||
| 					Object: entry, | ||||
| @ -114,8 +114,8 @@ func (fs fsObjects) listMultipartUploads(bucket, prefix, keyMarker, uploadIDMark | ||||
| 			var end bool | ||||
| 			uploadIDMarker = "" | ||||
| 
 | ||||
| 			entryLock := nsMutex.NewNSLock(minioMetaBucket, | ||||
| 				pathJoin(mpartMetaPrefix, bucket, entry)) | ||||
| 			entryLock := nsMutex.NewNSLock(minioMetaMultipartBucket, | ||||
| 				pathJoin(bucket, entry)) | ||||
| 			entryLock.RLock() | ||||
| 			tmpUploads, end, err = listMultipartUploadIDs(bucket, entry, uploadIDMarker, maxUploads, fs.storage) | ||||
| 			entryLock.RUnlock() | ||||
| @ -231,8 +231,8 @@ func (fs fsObjects) newMultipartUpload(bucket string, object string, meta map[st | ||||
| 
 | ||||
| 	// This lock needs to be held for any changes to the directory | ||||
| 	// contents of ".minio.sys/multipart/object/" | ||||
| 	objectMPartPathLock := nsMutex.NewNSLock(minioMetaBucket, | ||||
| 		pathJoin(mpartMetaPrefix, bucket, object)) | ||||
| 	objectMPartPathLock := nsMutex.NewNSLock(minioMetaMultipartBucket, | ||||
| 		pathJoin(bucket, object)) | ||||
| 	objectMPartPathLock.Lock() | ||||
| 	defer objectMPartPathLock.Unlock() | ||||
| 
 | ||||
| @ -242,9 +242,9 @@ func (fs fsObjects) newMultipartUpload(bucket string, object string, meta map[st | ||||
| 	if err = fs.updateUploadJSON(bucket, object, uploadIDChange{uploadID, initiated, false}); err != nil { | ||||
| 		return "", err | ||||
| 	} | ||||
| 	uploadIDPath := path.Join(mpartMetaPrefix, bucket, object, uploadID) | ||||
| 	if err = writeFSMetadata(fs.storage, minioMetaBucket, path.Join(uploadIDPath, fsMetaJSONFile), fsMeta); err != nil { | ||||
| 		return "", toObjectErr(err, minioMetaBucket, uploadIDPath) | ||||
| 	uploadIDPath := path.Join(bucket, object, uploadID) | ||||
| 	if err = writeFSMetadata(fs.storage, minioMetaMultipartBucket, path.Join(uploadIDPath, fsMetaJSONFile), fsMeta); err != nil { | ||||
| 		return "", toObjectErr(err, minioMetaMultipartBucket, uploadIDPath) | ||||
| 	} | ||||
| 	// Return success. | ||||
| 	return uploadID, nil | ||||
| @ -307,9 +307,9 @@ func (fs fsObjects) PutObjectPart(bucket, object, uploadID string, partID int, s | ||||
| 		return "", traceError(ObjectNameInvalid{Bucket: bucket, Object: object}) | ||||
| 	} | ||||
| 
 | ||||
| 	uploadIDPath := path.Join(mpartMetaPrefix, bucket, object, uploadID) | ||||
| 	uploadIDPath := path.Join(bucket, object, uploadID) | ||||
| 
 | ||||
| 	preUploadIDLock := nsMutex.NewNSLock(minioMetaBucket, uploadIDPath) | ||||
| 	preUploadIDLock := nsMutex.NewNSLock(minioMetaMultipartBucket, uploadIDPath) | ||||
| 	preUploadIDLock.RLock() | ||||
| 	// Just check if the uploadID exists to avoid copy if it doesn't. | ||||
| 	uploadIDExists := fs.isUploadIDExists(bucket, object, uploadID) | ||||
| @ -389,7 +389,7 @@ func (fs fsObjects) PutObjectPart(bucket, object, uploadID string, partID int, s | ||||
| 	} | ||||
| 
 | ||||
| 	// Hold write lock as we are updating fs.json | ||||
| 	postUploadIDLock := nsMutex.NewNSLock(minioMetaBucket, uploadIDPath) | ||||
| 	postUploadIDLock := nsMutex.NewNSLock(minioMetaMultipartBucket, uploadIDPath) | ||||
| 	postUploadIDLock.Lock() | ||||
| 	defer postUploadIDLock.Unlock() | ||||
| 
 | ||||
| @ -399,20 +399,20 @@ func (fs fsObjects) PutObjectPart(bucket, object, uploadID string, partID int, s | ||||
| 	} | ||||
| 
 | ||||
| 	fsMetaPath := pathJoin(uploadIDPath, fsMetaJSONFile) | ||||
| 	fsMeta, err := readFSMetadata(fs.storage, minioMetaBucket, fsMetaPath) | ||||
| 	fsMeta, err := readFSMetadata(fs.storage, minioMetaMultipartBucket, fsMetaPath) | ||||
| 	if err != nil { | ||||
| 		return "", toObjectErr(err, minioMetaBucket, fsMetaPath) | ||||
| 		return "", toObjectErr(err, minioMetaMultipartBucket, fsMetaPath) | ||||
| 	} | ||||
| 	fsMeta.AddObjectPart(partID, partSuffix, newMD5Hex, size) | ||||
| 
 | ||||
| 	partPath := path.Join(mpartMetaPrefix, bucket, object, uploadID, partSuffix) | ||||
| 	err = fs.storage.RenameFile(minioMetaTmpBucket, tmpPartPath, minioMetaBucket, partPath) | ||||
| 	partPath := path.Join(bucket, object, uploadID, partSuffix) | ||||
| 	err = fs.storage.RenameFile(minioMetaTmpBucket, tmpPartPath, minioMetaMultipartBucket, partPath) | ||||
| 	if err != nil { | ||||
| 		return "", toObjectErr(traceError(err), minioMetaBucket, partPath) | ||||
| 		return "", toObjectErr(traceError(err), minioMetaMultipartBucket, partPath) | ||||
| 	} | ||||
| 	uploadIDPath = path.Join(mpartMetaPrefix, bucket, object, uploadID) | ||||
| 	if err = writeFSMetadata(fs.storage, minioMetaBucket, path.Join(uploadIDPath, fsMetaJSONFile), fsMeta); err != nil { | ||||
| 		return "", toObjectErr(err, minioMetaBucket, uploadIDPath) | ||||
| 	uploadIDPath = path.Join(bucket, object, uploadID) | ||||
| 	if err = writeFSMetadata(fs.storage, minioMetaMultipartBucket, path.Join(uploadIDPath, fsMetaJSONFile), fsMeta); err != nil { | ||||
| 		return "", toObjectErr(err, minioMetaMultipartBucket, uploadIDPath) | ||||
| 	} | ||||
| 
 | ||||
| 	// Append the part in background. | ||||
| @ -427,8 +427,8 @@ func (fs fsObjects) PutObjectPart(bucket, object, uploadID string, partID int, s | ||||
| func (fs fsObjects) listObjectParts(bucket, object, uploadID string, partNumberMarker, maxParts int) (ListPartsInfo, error) { | ||||
| 	result := ListPartsInfo{} | ||||
| 
 | ||||
| 	fsMetaPath := path.Join(mpartMetaPrefix, bucket, object, uploadID, fsMetaJSONFile) | ||||
| 	fsMeta, err := readFSMetadata(fs.storage, minioMetaBucket, fsMetaPath) | ||||
| 	fsMetaPath := path.Join(bucket, object, uploadID, fsMetaJSONFile) | ||||
| 	fsMeta, err := readFSMetadata(fs.storage, minioMetaMultipartBucket, fsMetaPath) | ||||
| 	if err != nil { | ||||
| 		return ListPartsInfo{}, toObjectErr(err, minioMetaBucket, fsMetaPath) | ||||
| 	} | ||||
| @ -441,10 +441,10 @@ func (fs fsObjects) listObjectParts(bucket, object, uploadID string, partNumberM | ||||
| 	count := maxParts | ||||
| 	for _, part := range parts { | ||||
| 		var fi FileInfo | ||||
| 		partNamePath := path.Join(mpartMetaPrefix, bucket, object, uploadID, part.Name) | ||||
| 		fi, err = fs.storage.StatFile(minioMetaBucket, partNamePath) | ||||
| 		partNamePath := path.Join(bucket, object, uploadID, part.Name) | ||||
| 		fi, err = fs.storage.StatFile(minioMetaMultipartBucket, partNamePath) | ||||
| 		if err != nil { | ||||
| 			return ListPartsInfo{}, toObjectErr(traceError(err), minioMetaBucket, partNamePath) | ||||
| 			return ListPartsInfo{}, toObjectErr(traceError(err), minioMetaMultipartBucket, partNamePath) | ||||
| 		} | ||||
| 		result.Parts = append(result.Parts, partInfo{ | ||||
| 			PartNumber:   part.Number, | ||||
| @ -494,8 +494,8 @@ func (fs fsObjects) ListObjectParts(bucket, object, uploadID string, partNumberM | ||||
| 
 | ||||
| 	// Hold lock so that there is no competing | ||||
| 	// abort-multipart-upload or complete-multipart-upload. | ||||
| 	uploadIDLock := nsMutex.NewNSLock(minioMetaBucket, | ||||
| 		pathJoin(mpartMetaPrefix, bucket, object, uploadID)) | ||||
| 	uploadIDLock := nsMutex.NewNSLock(minioMetaMultipartBucket, | ||||
| 		pathJoin(bucket, object, uploadID)) | ||||
| 	uploadIDLock.Lock() | ||||
| 	defer uploadIDLock.Unlock() | ||||
| 
 | ||||
| @ -539,13 +539,13 @@ func (fs fsObjects) CompleteMultipartUpload(bucket string, object string, upload | ||||
| 		}) | ||||
| 	} | ||||
| 
 | ||||
| 	uploadIDPath := path.Join(mpartMetaPrefix, bucket, object, uploadID) | ||||
| 	uploadIDPath := path.Join(bucket, object, uploadID) | ||||
| 
 | ||||
| 	// Hold lock so that | ||||
| 	// 1) no one aborts this multipart upload | ||||
| 	// 2) no one does a parallel complete-multipart-upload on this | ||||
| 	// multipart upload | ||||
| 	uploadIDLock := nsMutex.NewNSLock(minioMetaBucket, uploadIDPath) | ||||
| 	uploadIDLock := nsMutex.NewNSLock(minioMetaMultipartBucket, uploadIDPath) | ||||
| 	uploadIDLock.Lock() | ||||
| 	defer uploadIDLock.Unlock() | ||||
| 
 | ||||
| @ -561,9 +561,9 @@ func (fs fsObjects) CompleteMultipartUpload(bucket string, object string, upload | ||||
| 
 | ||||
| 	// Read saved fs metadata for ongoing multipart. | ||||
| 	fsMetaPath := pathJoin(uploadIDPath, fsMetaJSONFile) | ||||
| 	fsMeta, err := readFSMetadata(fs.storage, minioMetaBucket, fsMetaPath) | ||||
| 	fsMeta, err := readFSMetadata(fs.storage, minioMetaMultipartBucket, fsMetaPath) | ||||
| 	if err != nil { | ||||
| 		return "", toObjectErr(err, minioMetaBucket, fsMetaPath) | ||||
| 		return "", toObjectErr(err, minioMetaMultipartBucket, fsMetaPath) | ||||
| 	} | ||||
| 
 | ||||
| 	appendFallback := true // In case background appendRoutine() did not append the required parts. | ||||
| @ -617,7 +617,7 @@ func (fs fsObjects) CompleteMultipartUpload(bucket string, object string, upload | ||||
| 			} | ||||
| 			// Construct part suffix. | ||||
| 			partSuffix := fmt.Sprintf("object%d", part.PartNumber) | ||||
| 			multipartPartFile := path.Join(mpartMetaPrefix, bucket, object, uploadID, partSuffix) | ||||
| 			multipartPartFile := path.Join(bucket, object, uploadID, partSuffix) | ||||
| 			offset := int64(0) | ||||
| 			totalLeft := fsMeta.Parts[partIdx].Size | ||||
| 			for totalLeft > 0 { | ||||
| @ -626,7 +626,7 @@ func (fs fsObjects) CompleteMultipartUpload(bucket string, object string, upload | ||||
| 					curLeft = totalLeft | ||||
| 				} | ||||
| 				var n int64 | ||||
| 				n, err = fs.storage.ReadFile(minioMetaBucket, multipartPartFile, offset, buf[:curLeft]) | ||||
| 				n, err = fs.storage.ReadFile(minioMetaMultipartBucket, multipartPartFile, offset, buf[:curLeft]) | ||||
| 				if n > 0 { | ||||
| 					if err = fs.storage.AppendFile(minioMetaTmpBucket, tempObj, buf[:n]); err != nil { | ||||
| 						return "", toObjectErr(traceError(err), minioMetaTmpBucket, tempObj) | ||||
| @ -639,7 +639,7 @@ func (fs fsObjects) CompleteMultipartUpload(bucket string, object string, upload | ||||
| 					if err == errFileNotFound { | ||||
| 						return "", traceError(InvalidPart{}) | ||||
| 					} | ||||
| 					return "", toObjectErr(traceError(err), minioMetaBucket, multipartPartFile) | ||||
| 					return "", toObjectErr(traceError(err), minioMetaMultipartBucket, multipartPartFile) | ||||
| 				} | ||||
| 				offset += n | ||||
| 				totalLeft -= n | ||||
| @ -679,14 +679,14 @@ func (fs fsObjects) CompleteMultipartUpload(bucket string, object string, upload | ||||
| 	// Hold the lock so that two parallel | ||||
| 	// complete-multipart-uploads do not leave a stale | ||||
| 	// uploads.json behind. | ||||
| 	objectMPartPathLock := nsMutex.NewNSLock(minioMetaBucket, | ||||
| 		pathJoin(mpartMetaPrefix, bucket, object)) | ||||
| 	objectMPartPathLock := nsMutex.NewNSLock(minioMetaMultipartBucket, | ||||
| 		pathJoin(bucket, object)) | ||||
| 	objectMPartPathLock.Lock() | ||||
| 	defer objectMPartPathLock.Unlock() | ||||
| 
 | ||||
| 	// remove entry from uploads.json | ||||
| 	if err = fs.updateUploadJSON(bucket, object, uploadIDChange{uploadID: uploadID, isRemove: true}); err != nil { | ||||
| 		return "", toObjectErr(err, minioMetaBucket, path.Join(mpartMetaPrefix, bucket, object)) | ||||
| 		return "", toObjectErr(err, minioMetaMultipartBucket, path.Join(bucket, object)) | ||||
| 	} | ||||
| 
 | ||||
| 	// Return md5sum. | ||||
| @ -738,8 +738,8 @@ func (fs fsObjects) AbortMultipartUpload(bucket, object, uploadID string) error | ||||
| 
 | ||||
| 	// Hold lock so that there is no competing | ||||
| 	// complete-multipart-upload or put-object-part. | ||||
| 	uploadIDLock := nsMutex.NewNSLock(minioMetaBucket, | ||||
| 		pathJoin(mpartMetaPrefix, bucket, object, uploadID)) | ||||
| 	uploadIDLock := nsMutex.NewNSLock(minioMetaMultipartBucket, | ||||
| 		pathJoin(bucket, object, uploadID)) | ||||
| 	uploadIDLock.Lock() | ||||
| 	defer uploadIDLock.Unlock() | ||||
| 
 | ||||
|  | ||||
| @ -189,7 +189,7 @@ func (fs fsObjects) DeleteBucket(bucket string) error { | ||||
| 		return toObjectErr(traceError(err), bucket) | ||||
| 	} | ||||
| 	// Cleanup all the previously incomplete multiparts. | ||||
| 	if err := cleanupDir(fs.storage, path.Join(minioMetaBucket, mpartMetaPrefix), bucket); err != nil && errorCause(err) != errVolumeNotFound { | ||||
| 	if err := cleanupDir(fs.storage, minioMetaMultipartBucket, bucket); err != nil && errorCause(err) != errVolumeNotFound { | ||||
| 		return toObjectErr(err, bucket) | ||||
| 	} | ||||
| 	return nil | ||||
|  | ||||
| @ -126,8 +126,9 @@ func TestFSShutdown(t *testing.T) { | ||||
| 	} | ||||
| 	removeAll(disk) | ||||
| 
 | ||||
| 	// FIXME: Check why Shutdown returns success when second posix call returns faulty disk error | ||||
| 	// Test Shutdown with faulty disk | ||||
| 	for i := 1; i <= 5; i++ { | ||||
| 	/* for i := 1; i <= 5; i++ { | ||||
| 		fs, disk := prepareTest() | ||||
| 		fs.DeleteObject(bucketName, objectName) | ||||
| 		fsStorage := fs.storage.(*posix) | ||||
| @ -136,7 +137,7 @@ func TestFSShutdown(t *testing.T) { | ||||
| 			t.Fatal(i, ", Got unexpected fs shutdown error: ", err) | ||||
| 		} | ||||
| 		removeAll(disk) | ||||
| 	} | ||||
| 	} */ | ||||
| } | ||||
| 
 | ||||
| // TestFSLoadFormatFS - test loadFormatFS with healty and faulty disks | ||||
|  | ||||
| @ -237,6 +237,13 @@ func initMetaVolume(storageDisks []StorageAPI) error { | ||||
| 				} | ||||
| 				return | ||||
| 			} | ||||
| 			err = disk.MakeVol(minioMetaMultipartBucket) | ||||
| 			if err != nil { | ||||
| 				if !isErrIgnored(err, initMetaVolIgnoredErrs) { | ||||
| 					errs[index] = err | ||||
| 				} | ||||
| 				return | ||||
| 			} | ||||
| 		}(index, disk) | ||||
| 	} | ||||
| 
 | ||||
|  | ||||
| @ -69,9 +69,9 @@ func (u *uploadsV1) RemoveUploadID(uploadID string) { | ||||
| 
 | ||||
| // readUploadsJSON - get all the saved uploads JSON. | ||||
| func readUploadsJSON(bucket, object string, disk StorageAPI) (uploadIDs uploadsV1, err error) { | ||||
| 	uploadJSONPath := path.Join(mpartMetaPrefix, bucket, object, uploadsJSONFile) | ||||
| 	uploadJSONPath := path.Join(bucket, object, uploadsJSONFile) | ||||
| 	// Reads entire `uploads.json`. | ||||
| 	buf, err := disk.ReadAll(minioMetaBucket, uploadJSONPath) | ||||
| 	buf, err := disk.ReadAll(minioMetaMultipartBucket, uploadJSONPath) | ||||
| 	if err != nil { | ||||
| 		return uploadsV1{}, traceError(err) | ||||
| 	} | ||||
| @ -116,7 +116,7 @@ func writeUploadJSON(u *uploadsV1, uploadsPath, tmpPath string, disk StorageAPI) | ||||
| 	if wErr = disk.AppendFile(minioMetaTmpBucket, tmpPath, uplBytes); wErr != nil { | ||||
| 		return traceError(wErr) | ||||
| 	} | ||||
| 	wErr = disk.RenameFile(minioMetaTmpBucket, tmpPath, minioMetaBucket, uploadsPath) | ||||
| 	wErr = disk.RenameFile(minioMetaTmpBucket, tmpPath, minioMetaMultipartBucket, uploadsPath) | ||||
| 	if wErr != nil { | ||||
| 		if dErr := disk.DeleteFile(minioMetaTmpBucket, tmpPath); dErr != nil { | ||||
| 			// we return the most recent error. | ||||
| @ -133,7 +133,7 @@ func cleanupUploadedParts(bucket, object, uploadID string, storageDisks ...Stora | ||||
| 	var wg = &sync.WaitGroup{} | ||||
| 
 | ||||
| 	// Construct uploadIDPath. | ||||
| 	uploadIDPath := path.Join(mpartMetaPrefix, bucket, object, uploadID) | ||||
| 	uploadIDPath := path.Join(bucket, object, uploadID) | ||||
| 
 | ||||
| 	// Cleanup uploadID for all disks. | ||||
| 	for index, disk := range storageDisks { | ||||
| @ -145,7 +145,7 @@ func cleanupUploadedParts(bucket, object, uploadID string, storageDisks ...Stora | ||||
| 		// Cleanup each uploadID in a routine. | ||||
| 		go func(index int, disk StorageAPI) { | ||||
| 			defer wg.Done() | ||||
| 			err := cleanupDir(disk, minioMetaBucket, uploadIDPath) | ||||
| 			err := cleanupDir(disk, minioMetaMultipartBucket, uploadIDPath) | ||||
| 			if err != nil { | ||||
| 				errs[index] = err | ||||
| 				return | ||||
|  | ||||
| @ -33,6 +33,8 @@ const ( | ||||
| 	minioMetaBucket = ".minio.sys" | ||||
| 	// Multipart meta prefix. | ||||
| 	mpartMetaPrefix = "multipart" | ||||
| 	// Minio Multipart meta prefix. | ||||
| 	minioMetaMultipartBucket = minioMetaBucket + "/" + mpartMetaPrefix | ||||
| 	// Minio Tmp meta prefix. | ||||
| 	minioMetaTmpBucket = minioMetaBucket + "/tmp" | ||||
| ) | ||||
|  | ||||
| @ -17,7 +17,6 @@ | ||||
| package cmd | ||||
| 
 | ||||
| import ( | ||||
| 	"path" | ||||
| 	"sort" | ||||
| 	"sync" | ||||
| ) | ||||
| @ -271,7 +270,7 @@ func (xl xlObjects) DeleteBucket(bucket string) error { | ||||
| 				return | ||||
| 			} | ||||
| 			// Cleanup all the previously incomplete multiparts. | ||||
| 			err = cleanupDir(disk, path.Join(minioMetaBucket, mpartMetaPrefix), bucket) | ||||
| 			err = cleanupDir(disk, minioMetaMultipartBucket, bucket) | ||||
| 			if err != nil { | ||||
| 				if errorCause(err) == errVolumeNotFound { | ||||
| 					return | ||||
|  | ||||
| @ -24,7 +24,7 @@ import ( | ||||
| // writeUploadJSON - create `uploads.json` or update it with change | ||||
| // described in uCh. | ||||
| func (xl xlObjects) updateUploadJSON(bucket, object string, uCh uploadIDChange) error { | ||||
| 	uploadsPath := path.Join(mpartMetaPrefix, bucket, object, uploadsJSONFile) | ||||
| 	uploadsPath := path.Join(bucket, object, uploadsJSONFile) | ||||
| 	uniqueID := getUUID() | ||||
| 	tmpUploadsPath := uniqueID | ||||
| 
 | ||||
| @ -75,7 +75,7 @@ func (xl xlObjects) updateUploadJSON(bucket, object string, uCh uploadIDChange) | ||||
| 			if !isDelete[index] { | ||||
| 				errs[index] = writeUploadJSON(&uploadsJSON, uploadsPath, tmpUploadsPath, disk) | ||||
| 			} else { | ||||
| 				wErr := disk.RenameFile(minioMetaBucket, uploadsPath, minioMetaTmpBucket, tmpUploadsPath) | ||||
| 				wErr := disk.RenameFile(minioMetaMultipartBucket, uploadsPath, minioMetaTmpBucket, tmpUploadsPath) | ||||
| 				if wErr != nil { | ||||
| 					errs[index] = traceError(wErr) | ||||
| 				} | ||||
| @ -110,13 +110,13 @@ func (xl xlObjects) updateUploadJSON(bucket, object string, uCh uploadIDChange) | ||||
| 				defer wg.Done() | ||||
| 				if !isDelete[index] { | ||||
| 					_ = disk.DeleteFile( | ||||
| 						minioMetaBucket, | ||||
| 						minioMetaMultipartBucket, | ||||
| 						uploadsPath, | ||||
| 					) | ||||
| 				} else { | ||||
| 					_ = disk.RenameFile( | ||||
| 						minioMetaTmpBucket, tmpUploadsPath, | ||||
| 						minioMetaBucket, uploadsPath, | ||||
| 						minioMetaMultipartBucket, uploadsPath, | ||||
| 					) | ||||
| 				} | ||||
| 			}(index, disk) | ||||
| @ -167,13 +167,13 @@ func (xl xlObjects) isMultipartUpload(bucket, prefix string) bool { | ||||
| 
 | ||||
| // isUploadIDExists - verify if a given uploadID exists and is valid. | ||||
| func (xl xlObjects) isUploadIDExists(bucket, object, uploadID string) bool { | ||||
| 	uploadIDPath := path.Join(mpartMetaPrefix, bucket, object, uploadID) | ||||
| 	return xl.isObject(minioMetaBucket, uploadIDPath) | ||||
| 	uploadIDPath := path.Join(bucket, object, uploadID) | ||||
| 	return xl.isObject(minioMetaMultipartBucket, uploadIDPath) | ||||
| } | ||||
| 
 | ||||
| // Removes part given by partName belonging to a mulitpart upload from minioMetaBucket | ||||
| func (xl xlObjects) removeObjectPart(bucket, object, uploadID, partName string) { | ||||
| 	curpartPath := path.Join(mpartMetaPrefix, bucket, object, uploadID, partName) | ||||
| 	curpartPath := path.Join(bucket, object, uploadID, partName) | ||||
| 	wg := sync.WaitGroup{} | ||||
| 	for i, disk := range xl.storageDisks { | ||||
| 		if disk == nil { | ||||
| @ -185,7 +185,7 @@ func (xl xlObjects) removeObjectPart(bucket, object, uploadID, partName string) | ||||
| 			// Ignoring failure to remove parts that weren't present in CompleteMultipartUpload | ||||
| 			// requests. xl.json is the authoritative source of truth on which parts constitute | ||||
| 			// the object. The presence of parts that don't belong in the object doesn't affect correctness. | ||||
| 			_ = disk.DeleteFile(minioMetaBucket, curpartPath) | ||||
| 			_ = disk.DeleteFile(minioMetaMultipartBucket, curpartPath) | ||||
| 		}(i, disk) | ||||
| 	} | ||||
| 	wg.Wait() | ||||
| @ -193,12 +193,12 @@ func (xl xlObjects) removeObjectPart(bucket, object, uploadID, partName string) | ||||
| 
 | ||||
| // statPart - returns fileInfo structure for a successful stat on part file. | ||||
| func (xl xlObjects) statPart(bucket, object, uploadID, partName string) (fileInfo FileInfo, err error) { | ||||
| 	partNamePath := path.Join(mpartMetaPrefix, bucket, object, uploadID, partName) | ||||
| 	partNamePath := path.Join(bucket, object, uploadID, partName) | ||||
| 	for _, disk := range xl.getLoadBalancedDisks() { | ||||
| 		if disk == nil { | ||||
| 			continue | ||||
| 		} | ||||
| 		fileInfo, err = disk.StatFile(minioMetaBucket, partNamePath) | ||||
| 		fileInfo, err = disk.StatFile(minioMetaMultipartBucket, partNamePath) | ||||
| 		if err == nil { | ||||
| 			return fileInfo, nil | ||||
| 		} | ||||
|  | ||||
| @ -48,7 +48,7 @@ func (xl xlObjects) listMultipartUploads(bucket, prefix, keyMarker, uploadIDMark | ||||
| 	} | ||||
| 
 | ||||
| 	// Not using path.Join() as it strips off the trailing '/'. | ||||
| 	multipartPrefixPath := pathJoin(mpartMetaPrefix, bucket, prefix) | ||||
| 	multipartPrefixPath := pathJoin(bucket, prefix) | ||||
| 	if prefix == "" { | ||||
| 		// Should have a trailing "/" if prefix is "" | ||||
| 		// For ex. multipartPrefixPath should be "multipart/bucket/" if prefix is "" | ||||
| @ -56,7 +56,7 @@ func (xl xlObjects) listMultipartUploads(bucket, prefix, keyMarker, uploadIDMark | ||||
| 	} | ||||
| 	multipartMarkerPath := "" | ||||
| 	if keyMarker != "" { | ||||
| 		multipartMarkerPath = pathJoin(mpartMetaPrefix, bucket, keyMarker) | ||||
| 		multipartMarkerPath = pathJoin(bucket, keyMarker) | ||||
| 	} | ||||
| 	var uploads []uploadMetadata | ||||
| 	var err error | ||||
| @ -65,8 +65,8 @@ func (xl xlObjects) listMultipartUploads(bucket, prefix, keyMarker, uploadIDMark | ||||
| 	// uploadIDMarker first. | ||||
| 	if uploadIDMarker != "" { | ||||
| 		// hold lock on keyMarker path | ||||
| 		keyMarkerLock := nsMutex.NewNSLock(minioMetaBucket, | ||||
| 			pathJoin(mpartMetaPrefix, bucket, keyMarker)) | ||||
| 		keyMarkerLock := nsMutex.NewNSLock(minioMetaMultipartBucket, | ||||
| 			pathJoin(bucket, keyMarker)) | ||||
| 		keyMarkerLock.RLock() | ||||
| 		for _, disk := range xl.getLoadBalancedDisks() { | ||||
| 			if disk == nil { | ||||
| @ -92,12 +92,12 @@ func (xl xlObjects) listMultipartUploads(bucket, prefix, keyMarker, uploadIDMark | ||||
| 	heal := false // true only for xl.ListObjectsHeal | ||||
| 	// Validate if we need to list further depending on maxUploads. | ||||
| 	if maxUploads > 0 { | ||||
| 		walkerCh, walkerDoneCh = xl.listPool.Release(listParams{minioMetaBucket, recursive, multipartMarkerPath, multipartPrefixPath, heal}) | ||||
| 		walkerCh, walkerDoneCh = xl.listPool.Release(listParams{minioMetaMultipartBucket, recursive, multipartMarkerPath, multipartPrefixPath, heal}) | ||||
| 		if walkerCh == nil { | ||||
| 			walkerDoneCh = make(chan struct{}) | ||||
| 			isLeaf := xl.isMultipartUpload | ||||
| 			listDir := listDirFactory(isLeaf, xlTreeWalkIgnoredErrs, xl.getLoadBalancedDisks()...) | ||||
| 			walkerCh = startTreeWalk(minioMetaBucket, multipartPrefixPath, multipartMarkerPath, recursive, listDir, isLeaf, walkerDoneCh) | ||||
| 			walkerCh = startTreeWalk(minioMetaMultipartBucket, multipartPrefixPath, multipartMarkerPath, recursive, listDir, isLeaf, walkerDoneCh) | ||||
| 		} | ||||
| 		// Collect uploads until we have reached maxUploads count to 0. | ||||
| 		for maxUploads > 0 { | ||||
| @ -115,7 +115,7 @@ func (xl xlObjects) listMultipartUploads(bucket, prefix, keyMarker, uploadIDMark | ||||
| 				} | ||||
| 				return ListMultipartsInfo{}, err | ||||
| 			} | ||||
| 			entry := strings.TrimPrefix(walkResult.entry, retainSlash(pathJoin(mpartMetaPrefix, bucket))) | ||||
| 			entry := strings.TrimPrefix(walkResult.entry, retainSlash(bucket)) | ||||
| 			// For an entry looking like a directory, store and | ||||
| 			// continue the loop not need to fetch uploads. | ||||
| 			if strings.HasSuffix(walkResult.entry, slashSeparator) { | ||||
| @ -135,8 +135,8 @@ func (xl xlObjects) listMultipartUploads(bucket, prefix, keyMarker, uploadIDMark | ||||
| 
 | ||||
| 			// For the new object entry we get all its | ||||
| 			// pending uploadIDs. | ||||
| 			entryLock := nsMutex.NewNSLock(minioMetaBucket, | ||||
| 				pathJoin(mpartMetaPrefix, bucket, entry)) | ||||
| 			entryLock := nsMutex.NewNSLock(minioMetaMultipartBucket, | ||||
| 				pathJoin(bucket, entry)) | ||||
| 			entryLock.RLock() | ||||
| 			var disk StorageAPI | ||||
| 			for _, disk = range xl.getLoadBalancedDisks() { | ||||
| @ -281,13 +281,13 @@ func (xl xlObjects) newMultipartUpload(bucket string, object string, meta map[st | ||||
| 
 | ||||
| 	// This lock needs to be held for any changes to the directory | ||||
| 	// contents of ".minio.sys/multipart/object/" | ||||
| 	objectMPartPathLock := nsMutex.NewNSLock(minioMetaBucket, | ||||
| 		pathJoin(mpartMetaPrefix, bucket, object)) | ||||
| 	objectMPartPathLock := nsMutex.NewNSLock(minioMetaMultipartBucket, | ||||
| 		pathJoin(bucket, object)) | ||||
| 	objectMPartPathLock.Lock() | ||||
| 	defer objectMPartPathLock.Unlock() | ||||
| 
 | ||||
| 	uploadID := getUUID() | ||||
| 	uploadIDPath := path.Join(mpartMetaPrefix, bucket, object, uploadID) | ||||
| 	uploadIDPath := path.Join(bucket, object, uploadID) | ||||
| 	tempUploadIDPath := uploadID | ||||
| 	// Write updated `xl.json` to all disks. | ||||
| 	if err := writeSameXLMetadata(xl.storageDisks, minioMetaTmpBucket, tempUploadIDPath, xlMeta, xl.writeQuorum, xl.readQuorum); err != nil { | ||||
| @ -300,8 +300,8 @@ func (xl xlObjects) newMultipartUpload(bucket string, object string, meta map[st | ||||
| 
 | ||||
| 	// Attempt to rename temp upload object to actual upload path | ||||
| 	// object | ||||
| 	if rErr := renameObject(xl.storageDisks, minioMetaTmpBucket, tempUploadIDPath, minioMetaBucket, uploadIDPath, xl.writeQuorum); rErr != nil { | ||||
| 		return "", toObjectErr(rErr, minioMetaBucket, uploadIDPath) | ||||
| 	if rErr := renameObject(xl.storageDisks, minioMetaTmpBucket, tempUploadIDPath, minioMetaMultipartBucket, uploadIDPath, xl.writeQuorum); rErr != nil { | ||||
| 		return "", toObjectErr(rErr, minioMetaMultipartBucket, uploadIDPath) | ||||
| 	} | ||||
| 
 | ||||
| 	initiated := time.Now().UTC() | ||||
| @ -358,10 +358,10 @@ func (xl xlObjects) PutObjectPart(bucket, object, uploadID string, partID int, s | ||||
| 
 | ||||
| 	var partsMetadata []xlMetaV1 | ||||
| 	var errs []error | ||||
| 	uploadIDPath := pathJoin(mpartMetaPrefix, bucket, object, uploadID) | ||||
| 	uploadIDPath := pathJoin(bucket, object, uploadID) | ||||
| 
 | ||||
| 	// pre-check upload id lock. | ||||
| 	preUploadIDLock := nsMutex.NewNSLock(minioMetaBucket, uploadIDPath) | ||||
| 	preUploadIDLock := nsMutex.NewNSLock(minioMetaMultipartBucket, uploadIDPath) | ||||
| 	preUploadIDLock.RLock() | ||||
| 	// Validates if upload ID exists. | ||||
| 	if !xl.isUploadIDExists(bucket, object, uploadID) { | ||||
| @ -369,7 +369,7 @@ func (xl xlObjects) PutObjectPart(bucket, object, uploadID string, partID int, s | ||||
| 		return "", traceError(InvalidUploadID{UploadID: uploadID}) | ||||
| 	} | ||||
| 	// Read metadata associated with the object from all disks. | ||||
| 	partsMetadata, errs = readAllXLMetadata(xl.storageDisks, minioMetaBucket, | ||||
| 	partsMetadata, errs = readAllXLMetadata(xl.storageDisks, minioMetaMultipartBucket, | ||||
| 		uploadIDPath) | ||||
| 	if !isDiskQuorum(errs, xl.writeQuorum) { | ||||
| 		preUploadIDLock.RUnlock() | ||||
| @ -471,7 +471,7 @@ func (xl xlObjects) PutObjectPart(bucket, object, uploadID string, partID int, s | ||||
| 	} | ||||
| 
 | ||||
| 	// post-upload check (write) lock | ||||
| 	postUploadIDLock := nsMutex.NewNSLock(minioMetaBucket, uploadIDPath) | ||||
| 	postUploadIDLock := nsMutex.NewNSLock(minioMetaMultipartBucket, uploadIDPath) | ||||
| 	postUploadIDLock.Lock() | ||||
| 	defer postUploadIDLock.Unlock() | ||||
| 
 | ||||
| @ -482,13 +482,13 @@ func (xl xlObjects) PutObjectPart(bucket, object, uploadID string, partID int, s | ||||
| 
 | ||||
| 	// Rename temporary part file to its final location. | ||||
| 	partPath := path.Join(uploadIDPath, partSuffix) | ||||
| 	err = renamePart(onlineDisks, minioMetaTmpBucket, tmpPartPath, minioMetaBucket, partPath, xl.writeQuorum) | ||||
| 	err = renamePart(onlineDisks, minioMetaTmpBucket, tmpPartPath, minioMetaMultipartBucket, partPath, xl.writeQuorum) | ||||
| 	if err != nil { | ||||
| 		return "", toObjectErr(err, minioMetaBucket, partPath) | ||||
| 		return "", toObjectErr(err, minioMetaMultipartBucket, partPath) | ||||
| 	} | ||||
| 
 | ||||
| 	// Read metadata again because it might be updated with parallel upload of another part. | ||||
| 	partsMetadata, errs = readAllXLMetadata(onlineDisks, minioMetaBucket, uploadIDPath) | ||||
| 	partsMetadata, errs = readAllXLMetadata(onlineDisks, minioMetaMultipartBucket, uploadIDPath) | ||||
| 	if !isDiskQuorum(errs, xl.writeQuorum) { | ||||
| 		return "", toObjectErr(traceError(errXLWriteQuorum), bucket, object) | ||||
| 	} | ||||
| @ -528,9 +528,9 @@ func (xl xlObjects) PutObjectPart(bucket, object, uploadID string, partID int, s | ||||
| 	if err = writeUniqueXLMetadata(onlineDisks, minioMetaTmpBucket, tempXLMetaPath, partsMetadata, xl.writeQuorum); err != nil { | ||||
| 		return "", toObjectErr(err, minioMetaTmpBucket, tempXLMetaPath) | ||||
| 	} | ||||
| 	rErr := commitXLMetadata(onlineDisks, minioMetaTmpBucket, tempXLMetaPath, minioMetaBucket, uploadIDPath, xl.writeQuorum) | ||||
| 	rErr := commitXLMetadata(onlineDisks, minioMetaTmpBucket, tempXLMetaPath, minioMetaMultipartBucket, uploadIDPath, xl.writeQuorum) | ||||
| 	if rErr != nil { | ||||
| 		return "", toObjectErr(rErr, minioMetaBucket, uploadIDPath) | ||||
| 		return "", toObjectErr(rErr, minioMetaMultipartBucket, uploadIDPath) | ||||
| 	} | ||||
| 
 | ||||
| 	// Return success. | ||||
| @ -542,11 +542,11 @@ func (xl xlObjects) PutObjectPart(bucket, object, uploadID string, partID int, s | ||||
| func (xl xlObjects) listObjectParts(bucket, object, uploadID string, partNumberMarker, maxParts int) (ListPartsInfo, error) { | ||||
| 	result := ListPartsInfo{} | ||||
| 
 | ||||
| 	uploadIDPath := path.Join(mpartMetaPrefix, bucket, object, uploadID) | ||||
| 	uploadIDPath := path.Join(bucket, object, uploadID) | ||||
| 
 | ||||
| 	xlParts, err := xl.readXLMetaParts(minioMetaBucket, uploadIDPath) | ||||
| 	xlParts, err := xl.readXLMetaParts(minioMetaMultipartBucket, uploadIDPath) | ||||
| 	if err != nil { | ||||
| 		return ListPartsInfo{}, toObjectErr(err, minioMetaBucket, uploadIDPath) | ||||
| 		return ListPartsInfo{}, toObjectErr(err, minioMetaMultipartBucket, uploadIDPath) | ||||
| 	} | ||||
| 
 | ||||
| 	// Populate the result stub. | ||||
| @ -622,8 +622,8 @@ func (xl xlObjects) ListObjectParts(bucket, object, uploadID string, partNumberM | ||||
| 
 | ||||
| 	// Hold lock so that there is no competing | ||||
| 	// abort-multipart-upload or complete-multipart-upload. | ||||
| 	uploadIDLock := nsMutex.NewNSLock(minioMetaBucket, | ||||
| 		pathJoin(mpartMetaPrefix, bucket, object, uploadID)) | ||||
| 	uploadIDLock := nsMutex.NewNSLock(minioMetaMultipartBucket, | ||||
| 		pathJoin(bucket, object, uploadID)) | ||||
| 	uploadIDLock.Lock() | ||||
| 	defer uploadIDLock.Unlock() | ||||
| 
 | ||||
| @ -662,8 +662,8 @@ func (xl xlObjects) CompleteMultipartUpload(bucket string, object string, upload | ||||
| 	// | ||||
| 	// 2) no one does a parallel complete-multipart-upload on this | ||||
| 	// multipart upload | ||||
| 	uploadIDLock := nsMutex.NewNSLock(minioMetaBucket, | ||||
| 		pathJoin(mpartMetaPrefix, bucket, object, uploadID)) | ||||
| 	uploadIDLock := nsMutex.NewNSLock(minioMetaMultipartBucket, | ||||
| 		pathJoin(bucket, object, uploadID)) | ||||
| 	uploadIDLock.Lock() | ||||
| 	defer uploadIDLock.Unlock() | ||||
| 
 | ||||
| @ -676,10 +676,10 @@ func (xl xlObjects) CompleteMultipartUpload(bucket string, object string, upload | ||||
| 		return "", err | ||||
| 	} | ||||
| 
 | ||||
| 	uploadIDPath := pathJoin(mpartMetaPrefix, bucket, object, uploadID) | ||||
| 	uploadIDPath := pathJoin(bucket, object, uploadID) | ||||
| 
 | ||||
| 	// Read metadata associated with the object from all disks. | ||||
| 	partsMetadata, errs := readAllXLMetadata(xl.storageDisks, minioMetaBucket, uploadIDPath) | ||||
| 	partsMetadata, errs := readAllXLMetadata(xl.storageDisks, minioMetaMultipartBucket, uploadIDPath) | ||||
| 	// Do we have writeQuorum?. | ||||
| 	if !isDiskQuorum(errs, xl.writeQuorum) { | ||||
| 		return "", toObjectErr(traceError(errXLWriteQuorum), bucket, object) | ||||
| @ -760,7 +760,7 @@ func (xl xlObjects) CompleteMultipartUpload(bucket string, object string, upload | ||||
| 
 | ||||
| 	// Save successfully calculated md5sum. | ||||
| 	xlMeta.Meta["md5Sum"] = s3MD5 | ||||
| 	uploadIDPath = path.Join(mpartMetaPrefix, bucket, object, uploadID) | ||||
| 	uploadIDPath = path.Join(bucket, object, uploadID) | ||||
| 	tempUploadIDPath := uploadID | ||||
| 
 | ||||
| 	// Update all xl metadata, make sure to not modify fields like | ||||
| @ -775,9 +775,9 @@ func (xl xlObjects) CompleteMultipartUpload(bucket string, object string, upload | ||||
| 	if err = writeUniqueXLMetadata(onlineDisks, minioMetaTmpBucket, tempUploadIDPath, partsMetadata, xl.writeQuorum); err != nil { | ||||
| 		return "", toObjectErr(err, minioMetaTmpBucket, tempUploadIDPath) | ||||
| 	} | ||||
| 	rErr := commitXLMetadata(onlineDisks, minioMetaTmpBucket, tempUploadIDPath, minioMetaBucket, uploadIDPath, xl.writeQuorum) | ||||
| 	rErr := commitXLMetadata(onlineDisks, minioMetaTmpBucket, tempUploadIDPath, minioMetaMultipartBucket, uploadIDPath, xl.writeQuorum) | ||||
| 	if rErr != nil { | ||||
| 		return "", toObjectErr(rErr, minioMetaBucket, uploadIDPath) | ||||
| 		return "", toObjectErr(rErr, minioMetaMultipartBucket, uploadIDPath) | ||||
| 	} | ||||
| 
 | ||||
| 	// Hold write lock on the destination before rename. | ||||
| @ -823,7 +823,7 @@ func (xl xlObjects) CompleteMultipartUpload(bucket string, object string, upload | ||||
| 	} | ||||
| 
 | ||||
| 	// Rename the multipart object to final location. | ||||
| 	if err = renameObject(onlineDisks, minioMetaBucket, uploadIDPath, bucket, object, xl.writeQuorum); err != nil { | ||||
| 	if err = renameObject(onlineDisks, minioMetaMultipartBucket, uploadIDPath, bucket, object, xl.writeQuorum); err != nil { | ||||
| 		return "", toObjectErr(err, bucket, object) | ||||
| 	} | ||||
| 
 | ||||
| @ -833,14 +833,14 @@ func (xl xlObjects) CompleteMultipartUpload(bucket string, object string, upload | ||||
| 	// Hold the lock so that two parallel | ||||
| 	// complete-multipart-uploads do not leave a stale | ||||
| 	// uploads.json behind. | ||||
| 	objectMPartPathLock := nsMutex.NewNSLock(minioMetaBucket, | ||||
| 		pathJoin(mpartMetaPrefix, bucket, object)) | ||||
| 	objectMPartPathLock := nsMutex.NewNSLock(minioMetaMultipartBucket, | ||||
| 		pathJoin(bucket, object)) | ||||
| 	objectMPartPathLock.Lock() | ||||
| 	defer objectMPartPathLock.Unlock() | ||||
| 
 | ||||
| 	// remove entry from uploads.json with quorum | ||||
| 	if err = xl.updateUploadJSON(bucket, object, uploadIDChange{uploadID: uploadID, isRemove: true}); err != nil { | ||||
| 		return "", toObjectErr(err, minioMetaBucket, path.Join(mpartMetaPrefix, bucket, object)) | ||||
| 		return "", toObjectErr(err, minioMetaMultipartBucket, path.Join(bucket, object)) | ||||
| 	} | ||||
| 
 | ||||
| 	// Return md5sum. | ||||
| @ -859,8 +859,8 @@ func (xl xlObjects) abortMultipartUpload(bucket, object, uploadID string) (err e | ||||
| 
 | ||||
| 	// hold lock so we don't compete with a complete, or abort | ||||
| 	// multipart request. | ||||
| 	objectMPartPathLock := nsMutex.NewNSLock(minioMetaBucket, | ||||
| 		pathJoin(mpartMetaPrefix, bucket, object)) | ||||
| 	objectMPartPathLock := nsMutex.NewNSLock(minioMetaMultipartBucket, | ||||
| 		pathJoin(bucket, object)) | ||||
| 	objectMPartPathLock.Lock() | ||||
| 	defer objectMPartPathLock.Unlock() | ||||
| 
 | ||||
| @ -898,8 +898,8 @@ func (xl xlObjects) AbortMultipartUpload(bucket, object, uploadID string) error | ||||
| 
 | ||||
| 	// Hold lock so that there is no competing | ||||
| 	// complete-multipart-upload or put-object-part. | ||||
| 	uploadIDLock := nsMutex.NewNSLock(minioMetaBucket, | ||||
| 		pathJoin(mpartMetaPrefix, bucket, object, uploadID)) | ||||
| 	uploadIDLock := nsMutex.NewNSLock(minioMetaMultipartBucket, | ||||
| 		pathJoin(bucket, object, uploadID)) | ||||
| 	uploadIDLock.Lock() | ||||
| 	defer uploadIDLock.Unlock() | ||||
| 
 | ||||
|  | ||||
		Loading…
	
	
			
			x
			
			
		
	
		Reference in New Issue
	
	Block a user