diff --git a/cmd/erasure-server-pool.go b/cmd/erasure-server-pool.go index 4796c64f0..c128aa556 100644 --- a/cmd/erasure-server-pool.go +++ b/cmd/erasure-server-pool.go @@ -1730,14 +1730,13 @@ func (z *erasureServerPools) Walk(ctx context.Context, bucket, prefix string, re // HealObjectFn closure function heals the object. type HealObjectFn func(bucket, object, versionID string) error -func listAndHeal(ctx context.Context, bucket, prefix string, set *erasureObjects, healEntry func(metaCacheEntry) error, errCh chan<- error) { +func listAndHeal(ctx context.Context, bucket, prefix string, set *erasureObjects, healEntry func(metaCacheEntry) error) error { ctx, cancel := context.WithCancel(ctx) defer cancel() disks, _ := set.getOnlineDisksWithHealing() if len(disks) == 0 { - errCh <- errors.New("listAndHeal: No non-healing disks found") - return + return errors.New("listAndHeal: No non-healing disks found") } // How to resolve partial results. @@ -1763,8 +1762,8 @@ func listAndHeal(ctx context.Context, bucket, prefix string, set *erasureObjects reportNotFound: false, agreed: func(entry metaCacheEntry) { if err := healEntry(entry); err != nil { - errCh <- err - return + logger.LogIf(ctx, err) + cancel() } }, partial: func(entries metaCacheEntries, nAgreed int, errs []error) { @@ -1776,7 +1775,8 @@ func listAndHeal(ctx context.Context, bucket, prefix string, set *erasureObjects } if err := healEntry(*entry); err != nil { - errCh <- err + logger.LogIf(ctx, err) + cancel() return } }, @@ -1784,13 +1784,13 @@ func listAndHeal(ctx context.Context, bucket, prefix string, set *erasureObjects } if err := listPathRaw(ctx, lopts); err != nil { - errCh <- fmt.Errorf("listPathRaw returned %w: opts(%#v)", err, lopts) - return + return fmt.Errorf("listPathRaw returned %w: opts(%#v)", err, lopts) } + + return nil } func (z *erasureServerPools) HealObjects(ctx context.Context, bucket, prefix string, opts madmin.HealOpts, healObjectFn HealObjectFn) error { - errCh := make(chan error) healEntry := func(entry metaCacheEntry) error { if entry.isDir() { return nil @@ -1829,34 +1829,33 @@ func (z *erasureServerPools) HealObjects(ctx context.Context, bucket, prefix str ctx, cancel := context.WithCancel(ctx) defer cancel() - go func() { - defer close(errCh) - + var poolErrs [][]error + for idx, erasureSet := range z.serverPools { + if z.IsSuspended(idx) { + continue + } + errs := make([]error, len(erasureSet.sets)) var wg sync.WaitGroup - for idx, erasureSet := range z.serverPools { - if z.IsSuspended(idx) { - continue - } - for _, set := range erasureSet.sets { - wg.Add(1) - go func(set *erasureObjects) { - defer wg.Done() + for idx, set := range erasureSet.sets { + wg.Add(1) + go func(idx int, set *erasureObjects) { + defer wg.Done() - listAndHeal(ctx, bucket, prefix, set, healEntry, errCh) - }(set) - } + errs[idx] = listAndHeal(ctx, bucket, prefix, set, healEntry) + }(idx, set) } wg.Wait() - }() - var err error - for e := range errCh { - // Save first non-nil error. - if e != nil && err != nil { - err = e - cancel() + poolErrs = append(poolErrs, errs) + } + for _, errs := range poolErrs { + for _, err := range errs { + if err == nil { + continue + } + return err } } - return err + return nil } func (z *erasureServerPools) HealObject(ctx context.Context, bucket, object, versionID string, opts madmin.HealOpts) (madmin.HealResultItem, error) {