mirror of
https://github.com/minio/minio.git
synced 2025-03-03 15:20:08 -05:00
Handle corrupted files correctly by fixing quorum (#6670)
This PR completes the missing functionality from #6592
This commit is contained in:
parent
8a6c3aa3cd
commit
989d7af9ac
@ -448,21 +448,7 @@ func (xl xlObjects) GetObjectInfo(ctx context.Context, bucket, object string, op
|
|||||||
return info, nil
|
return info, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
// getObjectInfo - wrapper for reading object metadata and constructs ObjectInfo.
|
func (xl xlObjects) isObjectCorrupted(metaArr []xlMetaV1, errs []error) (validMeta xlMetaV1, ok bool) {
|
||||||
func (xl xlObjects) getObjectInfo(ctx context.Context, bucket, object string) (objInfo ObjectInfo, err error) {
|
|
||||||
// Read metadata associated with the object from all disks.
|
|
||||||
metaArr, errs := readAllXLMetadata(ctx, xl.getDisks(), bucket, object)
|
|
||||||
|
|
||||||
// Get quorum for this object
|
|
||||||
readQuorum, _, err := objectQuorumFromMeta(ctx, xl, metaArr, errs)
|
|
||||||
if err != nil {
|
|
||||||
return objInfo, err
|
|
||||||
}
|
|
||||||
|
|
||||||
const xlCorruptedSuffix = ".CORRUPTED"
|
|
||||||
|
|
||||||
// Having read quorum means we have xl.json in at least N/2 disks.
|
|
||||||
if !strings.HasSuffix(object, xlCorruptedSuffix) {
|
|
||||||
// We can consider an object data not reliable
|
// We can consider an object data not reliable
|
||||||
// when xl.json is not found in read quorum disks.
|
// when xl.json is not found in read quorum disks.
|
||||||
var notFoundXLJSON int
|
var notFoundXLJSON int
|
||||||
@ -471,15 +457,93 @@ func (xl xlObjects) getObjectInfo(ctx context.Context, bucket, object string) (o
|
|||||||
notFoundXLJSON++
|
notFoundXLJSON++
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
// If xl.json is not present in read quorum disks,
|
|
||||||
// add .CORRUPTED prefix to the current object.
|
for _, m := range metaArr {
|
||||||
if len(xl.getDisks())-notFoundXLJSON < readQuorum {
|
if !m.IsValid() {
|
||||||
writeQuorum := readQuorum + 1
|
continue
|
||||||
rename(ctx, xl.getDisks(), bucket, object, bucket, object+xlCorruptedSuffix, true, writeQuorum, []error{errFileNotFound})
|
}
|
||||||
|
validMeta = m
|
||||||
|
break
|
||||||
|
}
|
||||||
|
|
||||||
|
// Return if the object is indeed corrupted.
|
||||||
|
return validMeta, len(xl.getDisks())-notFoundXLJSON < validMeta.Erasure.DataBlocks
|
||||||
|
}
|
||||||
|
|
||||||
|
const xlCorruptedSuffix = ".CORRUPTED"
|
||||||
|
|
||||||
|
// Renames the corrupted object and makes it visible.
|
||||||
|
func renameCorruptedObject(ctx context.Context, bucket, object string, validMeta xlMetaV1, disks []StorageAPI, errs []error) {
|
||||||
|
writeQuorum := validMeta.Erasure.DataBlocks + 1
|
||||||
|
|
||||||
|
// Move all existing objects into corrupted suffix.
|
||||||
|
rename(ctx, disks, bucket, object, bucket, object+xlCorruptedSuffix, true, writeQuorum, []error{errFileNotFound})
|
||||||
|
|
||||||
|
tempObj := mustGetUUID()
|
||||||
|
|
||||||
|
// Get all the disks which do not have the file.
|
||||||
|
var cdisks = make([]StorageAPI, len(disks))
|
||||||
|
for i, merr := range errs {
|
||||||
|
if merr == errFileNotFound {
|
||||||
|
cdisks[i] = disks[i]
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
for _, disk := range cdisks {
|
||||||
|
if disk == nil {
|
||||||
|
continue
|
||||||
|
}
|
||||||
|
|
||||||
|
// Write empty part file on missing disks.
|
||||||
|
disk.AppendFile(minioMetaTmpBucket, pathJoin(tempObj, "part.1"), []byte{})
|
||||||
|
|
||||||
|
// Write algorithm hash for empty part file.
|
||||||
|
alg := validMeta.Erasure.Checksums[0].Algorithm.New()
|
||||||
|
alg.Write([]byte{})
|
||||||
|
|
||||||
|
// Update the checksums and part info.
|
||||||
|
validMeta.Erasure.Checksums[0] = ChecksumInfo{
|
||||||
|
Name: validMeta.Erasure.Checksums[0].Name,
|
||||||
|
Algorithm: validMeta.Erasure.Checksums[0].Algorithm,
|
||||||
|
Hash: alg.Sum(nil),
|
||||||
|
}
|
||||||
|
validMeta.Parts[0] = objectPartInfo{
|
||||||
|
Number: 1,
|
||||||
|
Name: "part.1",
|
||||||
|
}
|
||||||
|
|
||||||
|
// Write the `xl.json` with the newly calculated metadata.
|
||||||
|
writeXLMetadata(ctx, disk, minioMetaTmpBucket, tempObj, validMeta)
|
||||||
|
}
|
||||||
|
|
||||||
|
// Finally rename all the parts into their respective locations.
|
||||||
|
rename(ctx, cdisks, minioMetaTmpBucket, tempObj, bucket, object+xlCorruptedSuffix, true, writeQuorum, []error{errFileNotFound})
|
||||||
|
}
|
||||||
|
|
||||||
|
// getObjectInfo - wrapper for reading object metadata and constructs ObjectInfo.
|
||||||
|
func (xl xlObjects) getObjectInfo(ctx context.Context, bucket, object string) (objInfo ObjectInfo, err error) {
|
||||||
|
disks := xl.getDisks()
|
||||||
|
|
||||||
|
// Read metadata associated with the object from all disks.
|
||||||
|
metaArr, errs := readAllXLMetadata(ctx, disks, bucket, object)
|
||||||
|
|
||||||
|
var readQuorum int
|
||||||
|
// Having read quorum means we have xl.json in at least N/2 disks.
|
||||||
|
if !strings.HasSuffix(object, xlCorruptedSuffix) {
|
||||||
|
if validMeta, ok := xl.isObjectCorrupted(metaArr, errs); ok {
|
||||||
|
renameCorruptedObject(ctx, bucket, object, validMeta, disks, errs)
|
||||||
// Return err file not found since we renamed now the corrupted object
|
// Return err file not found since we renamed now the corrupted object
|
||||||
return objInfo, errFileNotFound
|
return objInfo, errFileNotFound
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Not a corrupted object, attempt to get readquorum properly.
|
||||||
|
readQuorum, _, err = objectQuorumFromMeta(ctx, xl, metaArr, errs)
|
||||||
|
if err != nil {
|
||||||
|
return objInfo, err
|
||||||
|
}
|
||||||
|
|
||||||
} else {
|
} else {
|
||||||
|
|
||||||
// If this is a corrupted object, change read quorum to N/2 disks
|
// If this is a corrupted object, change read quorum to N/2 disks
|
||||||
// so it will be visible to users, so they can delete it.
|
// so it will be visible to users, so they can delete it.
|
||||||
readQuorum = len(xl.getDisks()) / 2
|
readQuorum = len(xl.getDisks()) / 2
|
||||||
|
Loading…
x
Reference in New Issue
Block a user