Fix multipart restore to remove part match (#12161)

Part ETags are not available after multipart finalizes, removing this
check as not useful.

Signed-off-by: Poorna Krishnamoorthy <poorna@minio.io>
Co-authored-by: Harshavardhana <harsha@minio.io>
This commit is contained in:
Poorna Krishnamoorthy 2021-04-26 18:24:06 -07:00 committed by GitHub
parent 26544848ea
commit 4be0f92067
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
5 changed files with 13 additions and 31 deletions

View File

@ -505,6 +505,11 @@ func (er erasureObjects) healObject(ctx context.Context, bucket string, object s
// record the index of the updated disks // record the index of the updated disks
partsMetadata[i].Erasure.Index = i + 1 partsMetadata[i].Erasure.Index = i + 1
// dataDir should be empty when
// - transitionStatus is complete and not in restored state
if partsMetadata[i].TransitionStatus == lifecycle.TransitionComplete && !isRestoredObjectOnDisk(partsMetadata[i].Metadata) {
partsMetadata[i].DataDir = ""
}
// Attempt a rename now from healed data to final location. // Attempt a rename now from healed data to final location.
if err = disk.RenameData(ctx, minioMetaTmpBucket, tmpID, partsMetadata[i], bucket, object); err != nil { if err = disk.RenameData(ctx, minioMetaTmpBucket, tmpID, partsMetadata[i], bucket, object); err != nil {
logger.LogIf(ctx, err) logger.LogIf(ctx, err)

View File

@ -575,7 +575,7 @@ func (er erasureObjects) PutObjectPart(ctx context.Context, bucket, object, uplo
PartNumber: partID, PartNumber: partID,
ETag: md5hex, ETag: md5hex,
LastModified: fi.ModTime, LastModified: fi.ModTime,
Size: fi.Size, Size: n,
ActualSize: data.ActualSize(), ActualSize: data.ActualSize(),
}, nil }, nil
} }

View File

@ -1475,37 +1475,15 @@ func (er erasureObjects) restoreTransitionedObject(ctx context.Context, bucket s
if err != nil { if err != nil {
return setRestoreHeaderFn(oi, err) return setRestoreHeaderFn(oi, err)
} }
if pInfo.Size != partInfo.Size {
return setRestoreHeaderFn(oi, InvalidObjectState{Bucket: bucket, Object: object})
}
uploadedParts = append(uploadedParts, CompletePart{ uploadedParts = append(uploadedParts, CompletePart{
PartNumber: pInfo.PartNumber, PartNumber: pInfo.PartNumber,
ETag: pInfo.ETag, ETag: pInfo.ETag,
}) })
} }
partsMatch := true
// validate parts created via multipart
if len(oi.Parts) == len(uploadedParts) {
for i, pi := range oi.Parts {
if uploadedParts[i].ETag != pi.ETag {
partsMatch = false
break
}
}
} else {
partsMatch = false
}
if !partsMatch {
return setRestoreHeaderFn(oi, InvalidObjectState{Bucket: bucket, Object: object})
}
_, err = er.CompleteMultipartUpload(ctx, bucket, object, uploadID, uploadedParts, ObjectOptions{ _, err = er.CompleteMultipartUpload(ctx, bucket, object, uploadID, uploadedParts, ObjectOptions{
MTime: oi.ModTime, MTime: oi.ModTime})
Versioned: globalBucketVersioningSys.Enabled(bucket), return setRestoreHeaderFn(oi, err)
VersionSuspended: globalBucketVersioningSys.Suspended(bucket),
})
if err != nil {
uploadIDPath := er.getUploadIDDir(bucket, object, uploadID)
return setRestoreHeaderFn(oi, toObjectErr(err, minioMetaMultipartBucket, uploadIDPath))
}
return setRestoreHeaderFn(oi, nil)
} }

View File

@ -495,7 +495,7 @@ func (e TransitionStorageClassNotFound) Error() string {
type InvalidObjectState GenericError type InvalidObjectState GenericError
func (e InvalidObjectState) Error() string { func (e InvalidObjectState) Error() string {
return "The operation is not valid for the current state of the object" + e.Bucket + "/" + e.Object return "The operation is not valid for the current state of the object " + e.Bucket + "/" + e.Object + "(" + e.VersionID + ")"
} }
/// Bucket related errors. /// Bucket related errors.

View File

@ -1858,8 +1858,7 @@ func (s *xlStorage) RenameData(ctx context.Context, srcVolume, srcPath string, f
var srcDataPath string var srcDataPath string
var dstDataPath string var dstDataPath string
dataDir := retainSlash(fi.DataDir) dataDir := retainSlash(fi.DataDir)
// no need to rename dataDir paths for objects that are in transitionComplete state. if dataDir != "" {
if dataDir != "" && fi.TransitionStatus != lifecycle.TransitionComplete {
srcDataPath = retainSlash(pathJoin(srcVolumeDir, srcPath, dataDir)) srcDataPath = retainSlash(pathJoin(srcVolumeDir, srcPath, dataDir))
// make sure to always use path.Join here, do not use pathJoin as // make sure to always use path.Join here, do not use pathJoin as
// it would additionally add `/` at the end and it comes in the // it would additionally add `/` at the end and it comes in the