1
0
mirror of https://github.com/minio/minio.git synced 2025-04-05 12:20:34 -04:00

allow bitrot files to be healed in MRF ()

bitrot scanMode was ignored in MRF,
allow it to heal relevant content if
needed when seen as an error.
This commit is contained in:
Harshavardhana 2023-12-08 12:26:01 -08:00 committed by GitHub
parent 6f97663174
commit 196e7e072b
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
6 changed files with 29 additions and 23 deletions

@ -810,7 +810,7 @@ func (h *healSequence) healMinioSysMeta(objAPI ObjectLayer, metaPrefix string) f
// NOTE: Healing on meta is run regardless // NOTE: Healing on meta is run regardless
// of any bucket being selected, this is to ensure that // of any bucket being selected, this is to ensure that
// meta are always upto date and correct. // meta are always upto date and correct.
return objAPI.HealObjects(h.ctx, minioMetaBucket, metaPrefix, h.settings, func(bucket, object, versionID string) error { return objAPI.HealObjects(h.ctx, minioMetaBucket, metaPrefix, h.settings, func(bucket, object, versionID string, scanMode madmin.HealScanMode) error {
if h.isQuitting() { if h.isQuitting() {
return errHealStopSignalled return errHealStopSignalled
} }
@ -867,7 +867,7 @@ func (h *healSequence) healBucket(objAPI ObjectLayer, bucket string, bucketsOnly
if !h.settings.Recursive { if !h.settings.Recursive {
if h.object != "" { if h.object != "" {
if err := h.healObject(bucket, h.object, ""); err != nil { if err := h.healObject(bucket, h.object, "", h.settings.ScanMode); err != nil {
return err return err
} }
} }
@ -882,7 +882,7 @@ func (h *healSequence) healBucket(objAPI ObjectLayer, bucket string, bucketsOnly
} }
// healObject - heal the given object and record result // healObject - heal the given object and record result
func (h *healSequence) healObject(bucket, object, versionID string) error { func (h *healSequence) healObject(bucket, object, versionID string, scanMode madmin.HealScanMode) error {
if h.isQuitting() { if h.isQuitting() {
return errHealStopSignalled return errHealStopSignalled
} }

@ -68,7 +68,7 @@ func (fi FileInfo) DataShardFixed() bool {
return fi.Metadata[reservedMetadataPrefixLowerDataShardFix] == "true" return fi.Metadata[reservedMetadataPrefixLowerDataShardFix] == "true"
} }
func (er erasureObjects) listAndHeal(bucket, prefix string, healEntry func(string, metaCacheEntry) error) error { func (er erasureObjects) listAndHeal(bucket, prefix string, scanMode madmin.HealScanMode, healEntry func(string, metaCacheEntry, madmin.HealScanMode) error) error {
ctx, cancel := context.WithCancel(context.Background()) ctx, cancel := context.WithCancel(context.Background())
defer cancel() defer cancel()
@ -101,7 +101,7 @@ func (er erasureObjects) listAndHeal(bucket, prefix string, healEntry func(strin
minDisks: 1, minDisks: 1,
reportNotFound: false, reportNotFound: false,
agreed: func(entry metaCacheEntry) { agreed: func(entry metaCacheEntry) {
if err := healEntry(bucket, entry); err != nil { if err := healEntry(bucket, entry, scanMode); err != nil {
cancel() cancel()
} }
}, },
@ -113,7 +113,7 @@ func (er erasureObjects) listAndHeal(bucket, prefix string, healEntry func(strin
entry, _ = entries.firstFound() entry, _ = entries.firstFound()
} }
if err := healEntry(bucket, *entry); err != nil { if err := healEntry(bucket, *entry, scanMode); err != nil {
cancel() cancel()
return return
} }

@ -647,8 +647,8 @@ func TestHealingDanglingObject(t *testing.T) {
} }
if err = objLayer.HealObjects(ctx, bucket, "", madmin.HealOpts{Remove: true}, if err = objLayer.HealObjects(ctx, bucket, "", madmin.HealOpts{Remove: true},
func(bucket, object, vid string) error { func(bucket, object, vid string, scanMode madmin.HealScanMode) error {
_, err := objLayer.HealObject(ctx, bucket, object, vid, madmin.HealOpts{Remove: true}) _, err := objLayer.HealObject(ctx, bucket, object, vid, madmin.HealOpts{ScanMode: scanMode, Remove: true})
return err return err
}); err != nil { }); err != nil {
t.Fatal(err) t.Fatal(err)
@ -694,8 +694,8 @@ func TestHealingDanglingObject(t *testing.T) {
} }
if err = objLayer.HealObjects(ctx, bucket, "", madmin.HealOpts{Remove: true}, if err = objLayer.HealObjects(ctx, bucket, "", madmin.HealOpts{Remove: true},
func(bucket, object, vid string) error { func(bucket, object, vid string, scanMode madmin.HealScanMode) error {
_, err := objLayer.HealObject(ctx, bucket, object, vid, madmin.HealOpts{Remove: true}) _, err := objLayer.HealObject(ctx, bucket, object, vid, madmin.HealOpts{ScanMode: scanMode, Remove: true})
return err return err
}); err != nil { }); err != nil {
t.Fatal(err) t.Fatal(err)
@ -743,8 +743,8 @@ func TestHealingDanglingObject(t *testing.T) {
} }
if err = objLayer.HealObjects(ctx, bucket, "", madmin.HealOpts{Remove: true}, if err = objLayer.HealObjects(ctx, bucket, "", madmin.HealOpts{Remove: true},
func(bucket, object, vid string) error { func(bucket, object, vid string, scanMode madmin.HealScanMode) error {
_, err := objLayer.HealObject(ctx, bucket, object, vid, madmin.HealOpts{Remove: true}) _, err := objLayer.HealObject(ctx, bucket, object, vid, madmin.HealOpts{ScanMode: scanMode, Remove: true})
return err return err
}); err != nil { }); err != nil {
t.Fatal(err) t.Fatal(err)

@ -413,6 +413,7 @@ func (er erasureObjects) getObjectWithFileInfo(ctx context.Context, bucket, obje
queued: time.Now(), queued: time.Now(),
setIndex: er.setIndex, setIndex: er.setIndex,
poolIndex: er.poolIndex, poolIndex: er.poolIndex,
scanMode: scan,
}) })
}) })
// Healing is triggered and we have written // Healing is triggered and we have written
@ -1217,7 +1218,7 @@ func (er erasureObjects) PutObject(ctx context.Context, bucket string, object st
} }
// Heal up to two versions of one object when there is disparity between disks // Heal up to two versions of one object when there is disparity between disks
func healObjectVersionsDisparity(bucket string, entry metaCacheEntry) error { func healObjectVersionsDisparity(bucket string, entry metaCacheEntry, scanMode madmin.HealScanMode) error {
if entry.isDir() { if entry.isDir() {
return nil return nil
} }
@ -1241,13 +1242,13 @@ func healObjectVersionsDisparity(bucket string, entry metaCacheEntry) error {
fivs, err := entry.fileInfoVersions(bucket) fivs, err := entry.fileInfoVersions(bucket)
if err != nil { if err != nil {
go healObject(bucket, entry.name, "", madmin.HealDeepScan) healObject(bucket, entry.name, "", madmin.HealDeepScan)
return err return err
} }
if len(fivs.Versions) <= 2 { if len(fivs.Versions) <= 2 {
for _, version := range fivs.Versions { for _, version := range fivs.Versions {
go healObject(bucket, entry.name, version.VersionID, madmin.HealNormalScan) healObject(bucket, entry.name, version.VersionID, scanMode)
} }
} }

@ -2108,10 +2108,10 @@ func (z *erasureServerPools) Walk(ctx context.Context, bucket, prefix string, re
} }
// HealObjectFn closure function heals the object. // HealObjectFn closure function heals the object.
type HealObjectFn func(bucket, object, versionID string) error type HealObjectFn func(bucket, object, versionID string, scanMode madmin.HealScanMode) error
func (z *erasureServerPools) HealObjects(ctx context.Context, bucket, prefix string, opts madmin.HealOpts, healObjectFn HealObjectFn) error { func (z *erasureServerPools) HealObjects(ctx context.Context, bucket, prefix string, opts madmin.HealOpts, healObjectFn HealObjectFn) error {
healEntry := func(bucket string, entry metaCacheEntry) error { healEntry := func(bucket string, entry metaCacheEntry, scanMode madmin.HealScanMode) error {
if entry.isDir() { if entry.isDir() {
return nil return nil
} }
@ -2134,7 +2134,7 @@ func (z *erasureServerPools) HealObjects(ctx context.Context, bucket, prefix str
} }
fivs, err := entry.fileInfoVersions(bucket) fivs, err := entry.fileInfoVersions(bucket)
if err != nil { if err != nil {
return healObjectFn(bucket, entry.name, "") return healObjectFn(bucket, entry.name, "", scanMode)
} }
if opts.Remove && !opts.DryRun { if opts.Remove && !opts.DryRun {
err := z.CheckAbandonedParts(ctx, bucket, entry.name, opts) err := z.CheckAbandonedParts(ctx, bucket, entry.name, opts)
@ -2143,7 +2143,7 @@ func (z *erasureServerPools) HealObjects(ctx context.Context, bucket, prefix str
} }
} }
for _, version := range fivs.Versions { for _, version := range fivs.Versions {
err := healObjectFn(bucket, version.Name, version.VersionID) err := healObjectFn(bucket, version.Name, version.VersionID, scanMode)
if err != nil && !isErrObjectNotFound(err) && !isErrVersionNotFound(err) { if err != nil && !isErrObjectNotFound(err) && !isErrVersionNotFound(err) {
return err return err
} }
@ -2167,7 +2167,7 @@ func (z *erasureServerPools) HealObjects(ctx context.Context, bucket, prefix str
go func(idx int, set *erasureObjects) { go func(idx int, set *erasureObjects) {
defer wg.Done() defer wg.Done()
errs[idx] = set.listAndHeal(bucket, prefix, healEntry) errs[idx] = set.listAndHeal(bucket, prefix, opts.ScanMode, healEntry)
}(idx, set) }(idx, set)
} }
wg.Wait() wg.Wait()

@ -38,6 +38,7 @@ type partialOperation struct {
allVersions bool allVersions bool
setIndex, poolIndex int setIndex, poolIndex int
queued time.Time queued time.Time
scanMode madmin.HealScanMode
} }
// mrfState sncapsulates all the information // mrfState sncapsulates all the information
@ -103,13 +104,17 @@ func (m *mrfState) healRoutine() {
// wait on timer per heal // wait on timer per heal
wait := healSleeper.Timer(context.Background()) wait := healSleeper.Timer(context.Background())
scan := madmin.HealNormalScan
if u.scanMode != 0 {
scan = u.scanMode
}
if u.object == "" { if u.object == "" {
healBucket(u.bucket, madmin.HealNormalScan) healBucket(u.bucket, scan)
} else { } else {
if u.allVersions { if u.allVersions {
m.pools.serverPools[u.poolIndex].sets[u.setIndex].listAndHeal(u.bucket, u.object, healObjectVersionsDisparity) m.pools.serverPools[u.poolIndex].sets[u.setIndex].listAndHeal(u.bucket, u.object, u.scanMode, healObjectVersionsDisparity)
} else { } else {
healObject(u.bucket, u.object, u.versionID, madmin.HealNormalScan) healObject(u.bucket, u.object, u.versionID, scan)
} }
} }