mirror of
https://github.com/minio/minio.git
synced 2025-05-21 17:43:48 -04:00
heal: Fix healing delete markers (#9989)
This commit is contained in:
parent
72e0745e2f
commit
fa211f6a10
@ -242,8 +242,8 @@ func (er erasureObjects) healObject(ctx context.Context, bucket string, object s
|
|||||||
Bucket: bucket,
|
Bucket: bucket,
|
||||||
Object: object,
|
Object: object,
|
||||||
DiskCount: len(storageDisks),
|
DiskCount: len(storageDisks),
|
||||||
ParityBlocks: latestFileInfo.Erasure.ParityBlocks,
|
ParityBlocks: len(storageDisks) / 2,
|
||||||
DataBlocks: latestFileInfo.Erasure.DataBlocks,
|
DataBlocks: len(storageDisks) / 2,
|
||||||
|
|
||||||
// Initialize object size to -1, so we can detect if we are
|
// Initialize object size to -1, so we can detect if we are
|
||||||
// unable to reliably find the object size.
|
// unable to reliably find the object size.
|
||||||
@ -265,8 +265,10 @@ func (er erasureObjects) healObject(ctx context.Context, bucket string, object s
|
|||||||
// If data is sane on any one disk, we can
|
// If data is sane on any one disk, we can
|
||||||
// extract the correct object size.
|
// extract the correct object size.
|
||||||
result.ObjectSize = partsMetadata[i].Size
|
result.ObjectSize = partsMetadata[i].Size
|
||||||
|
if partsMetadata[i].Erasure.ParityBlocks > 0 && partsMetadata[i].Erasure.DataBlocks > 0 {
|
||||||
result.ParityBlocks = partsMetadata[i].Erasure.ParityBlocks
|
result.ParityBlocks = partsMetadata[i].Erasure.ParityBlocks
|
||||||
result.DataBlocks = partsMetadata[i].Erasure.DataBlocks
|
result.DataBlocks = partsMetadata[i].Erasure.DataBlocks
|
||||||
|
}
|
||||||
case errs[i] == errDiskNotFound, dataErrs[i] == errDiskNotFound:
|
case errs[i] == errDiskNotFound, dataErrs[i] == errDiskNotFound:
|
||||||
driveState = madmin.DriveStateOffline
|
driveState = madmin.DriveStateOffline
|
||||||
case errs[i] == errFileNotFound, errs[i] == errVolumeNotFound:
|
case errs[i] == errFileNotFound, errs[i] == errVolumeNotFound:
|
||||||
@ -315,7 +317,11 @@ func (er erasureObjects) healObject(ctx context.Context, bucket string, object s
|
|||||||
writeQuorum = getWriteQuorum(len(storageDisks))
|
writeQuorum = getWriteQuorum(len(storageDisks))
|
||||||
}
|
}
|
||||||
if !dryRun && remove {
|
if !dryRun && remove {
|
||||||
|
if latestFileInfo.VersionID == "" {
|
||||||
err = er.deleteObject(ctx, bucket, object, writeQuorum)
|
err = er.deleteObject(ctx, bucket, object, writeQuorum)
|
||||||
|
} else {
|
||||||
|
err = er.deleteObjectVersion(ctx, bucket, object, writeQuorum, FileInfo{VersionID: latestFileInfo.VersionID})
|
||||||
|
}
|
||||||
}
|
}
|
||||||
return defaultHealResult(latestFileInfo, storageDisks, storageEndpoints, errs, bucket, object), err
|
return defaultHealResult(latestFileInfo, storageDisks, storageEndpoints, errs, bucket, object), err
|
||||||
}
|
}
|
||||||
@ -348,10 +354,9 @@ func (er erasureObjects) healObject(ctx context.Context, bucket string, object s
|
|||||||
return nfi
|
return nfi
|
||||||
}
|
}
|
||||||
|
|
||||||
// Reorder so that we have data disks first and parity disks next.
|
// We write at temporary location and then rename to final location.
|
||||||
latestDisks = shuffleDisks(availableDisks, latestMeta.Erasure.Distribution)
|
tmpID := mustGetUUID()
|
||||||
outDatedDisks = shuffleDisks(outDatedDisks, latestMeta.Erasure.Distribution)
|
|
||||||
partsMetadata = shufflePartsMetadata(partsMetadata, latestMeta.Erasure.Distribution)
|
|
||||||
for i := range outDatedDisks {
|
for i := range outDatedDisks {
|
||||||
if outDatedDisks[i] == nil {
|
if outDatedDisks[i] == nil {
|
||||||
continue
|
continue
|
||||||
@ -359,8 +364,14 @@ func (er erasureObjects) healObject(ctx context.Context, bucket string, object s
|
|||||||
partsMetadata[i] = cleanFileInfo(latestMeta)
|
partsMetadata[i] = cleanFileInfo(latestMeta)
|
||||||
}
|
}
|
||||||
|
|
||||||
// We write at temporary location and then rename to final location.
|
if !latestMeta.Deleted {
|
||||||
tmpID := mustGetUUID()
|
result.DataBlocks = latestMeta.Erasure.DataBlocks
|
||||||
|
result.ParityBlocks = latestMeta.Erasure.ParityBlocks
|
||||||
|
|
||||||
|
// Reorder so that we have data disks first and parity disks next.
|
||||||
|
latestDisks = shuffleDisks(availableDisks, latestMeta.Erasure.Distribution)
|
||||||
|
outDatedDisks = shuffleDisks(outDatedDisks, latestMeta.Erasure.Distribution)
|
||||||
|
partsMetadata = shufflePartsMetadata(partsMetadata, latestMeta.Erasure.Distribution)
|
||||||
|
|
||||||
// Heal each part. erasureHealFile() will write the healed
|
// Heal each part. erasureHealFile() will write the healed
|
||||||
// part to .minio/tmp/uuid/ which needs to be renamed later to
|
// part to .minio/tmp/uuid/ which needs to be renamed later to
|
||||||
@ -429,10 +440,9 @@ func (er erasureObjects) healObject(ctx context.Context, bucket string, object s
|
|||||||
return result, fmt.Errorf("all disks had write errors, unable to heal")
|
return result, fmt.Errorf("all disks had write errors, unable to heal")
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
|
||||||
// Cleanup in case of er.meta writing failure
|
defer er.deleteObject(ctx, minioMetaTmpBucket, tmpID, len(storageDisks)/2+1)
|
||||||
writeQuorum := latestMeta.Erasure.DataBlocks + 1
|
|
||||||
defer er.deleteObject(ctx, minioMetaTmpBucket, tmpID, writeQuorum)
|
|
||||||
|
|
||||||
// Generate and write `xl.meta` generated from other disks.
|
// Generate and write `xl.meta` generated from other disks.
|
||||||
outDatedDisks, err = writeUniqueFileInfo(ctx, outDatedDisks, minioMetaTmpBucket, tmpID,
|
outDatedDisks, err = writeUniqueFileInfo(ctx, outDatedDisks, minioMetaTmpBucket, tmpID,
|
||||||
@ -659,12 +669,12 @@ func isObjectDangling(metaArr []FileInfo, errs []error, dataErrs []error) (valid
|
|||||||
// We can consider an object data not reliable
|
// We can consider an object data not reliable
|
||||||
// when er.meta is not found in read quorum disks.
|
// when er.meta is not found in read quorum disks.
|
||||||
// or when er.meta is not readable in read quorum disks.
|
// or when er.meta is not readable in read quorum disks.
|
||||||
var notFoundErasureJSON, corruptedErasureJSON int
|
var notFoundErasureMeta, corruptedErasureMeta int
|
||||||
for _, readErr := range errs {
|
for _, readErr := range errs {
|
||||||
if readErr == errFileNotFound {
|
if readErr == errFileNotFound || readErr == errFileVersionNotFound {
|
||||||
notFoundErasureJSON++
|
notFoundErasureMeta++
|
||||||
} else if readErr == errCorruptedFormat {
|
} else if readErr == errCorruptedFormat {
|
||||||
corruptedErasureJSON++
|
corruptedErasureMeta++
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
var notFoundParts int
|
var notFoundParts int
|
||||||
@ -674,7 +684,7 @@ func isObjectDangling(metaArr []FileInfo, errs []error, dataErrs []error) (valid
|
|||||||
// double counting when both parts and er.meta
|
// double counting when both parts and er.meta
|
||||||
// are not available.
|
// are not available.
|
||||||
if errs[i] != dataErrs[i] {
|
if errs[i] != dataErrs[i] {
|
||||||
if dataErrs[i] == errFileNotFound {
|
if dataErrs[i] == errFileNotFound || dataErrs[i] == errFileVersionNotFound {
|
||||||
notFoundParts++
|
notFoundParts++
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -688,13 +698,17 @@ func isObjectDangling(metaArr []FileInfo, errs []error, dataErrs []error) (valid
|
|||||||
break
|
break
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if validMeta.Deleted {
|
||||||
|
return validMeta, false
|
||||||
|
}
|
||||||
|
|
||||||
// We couldn't find any valid meta we are indeed corrupted, return true right away.
|
// We couldn't find any valid meta we are indeed corrupted, return true right away.
|
||||||
if validMeta.Erasure.DataBlocks == 0 {
|
if validMeta.Erasure.DataBlocks == 0 {
|
||||||
return validMeta, true
|
return validMeta, true
|
||||||
}
|
}
|
||||||
|
|
||||||
// We have valid meta, now verify if we have enough files with parity blocks.
|
// We have valid meta, now verify if we have enough files with parity blocks.
|
||||||
return validMeta, corruptedErasureJSON+notFoundErasureJSON+notFoundParts > validMeta.Erasure.ParityBlocks
|
return validMeta, corruptedErasureMeta+notFoundErasureMeta+notFoundParts > validMeta.Erasure.ParityBlocks
|
||||||
}
|
}
|
||||||
|
|
||||||
// HealObject - heal the given object, automatically deletes the object if stale/corrupted if `remove` is true.
|
// HealObject - heal the given object, automatically deletes the object if stale/corrupted if `remove` is true.
|
||||||
@ -729,7 +743,11 @@ func (er erasureObjects) HealObject(ctx context.Context, bucket, object, version
|
|||||||
writeQuorum = getWriteQuorum(len(storageDisks))
|
writeQuorum = getWriteQuorum(len(storageDisks))
|
||||||
}
|
}
|
||||||
if !opts.DryRun && opts.Remove {
|
if !opts.DryRun && opts.Remove {
|
||||||
|
if versionID == "" {
|
||||||
er.deleteObject(healCtx, bucket, object, writeQuorum)
|
er.deleteObject(healCtx, bucket, object, writeQuorum)
|
||||||
|
} else {
|
||||||
|
er.deleteObjectVersion(healCtx, bucket, object, writeQuorum, FileInfo{VersionID: versionID})
|
||||||
|
}
|
||||||
}
|
}
|
||||||
err = reduceReadQuorumErrs(ctx, errs, nil, writeQuorum-1)
|
err = reduceReadQuorumErrs(ctx, errs, nil, writeQuorum-1)
|
||||||
return defaultHealResult(FileInfo{}, storageDisks, storageEndpoints, errs, bucket, object), toObjectErr(err, bucket, object)
|
return defaultHealResult(FileInfo{}, storageDisks, storageEndpoints, errs, bucket, object), toObjectErr(err, bucket, object)
|
||||||
@ -758,7 +776,11 @@ func (er erasureObjects) HealObject(ctx context.Context, bucket, object, version
|
|||||||
writeQuorum = getWriteQuorum(len(storageDisks))
|
writeQuorum = getWriteQuorum(len(storageDisks))
|
||||||
}
|
}
|
||||||
if !opts.DryRun && opts.Remove {
|
if !opts.DryRun && opts.Remove {
|
||||||
|
if versionID == "" {
|
||||||
er.deleteObject(ctx, bucket, object, writeQuorum)
|
er.deleteObject(ctx, bucket, object, writeQuorum)
|
||||||
|
} else {
|
||||||
|
er.deleteObjectVersion(ctx, bucket, object, writeQuorum, FileInfo{VersionID: versionID})
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
return defaultHealResult(latestFileInfo, storageDisks, storageEndpoints, errs, bucket, object), toObjectErr(err, bucket, object)
|
return defaultHealResult(latestFileInfo, storageDisks, storageEndpoints, errs, bucket, object), toObjectErr(err, bucket, object)
|
||||||
|
Loading…
x
Reference in New Issue
Block a user