From bedff1ed6d7402759ba57d4de4b8c5fc80889dfb Mon Sep 17 00:00:00 2001 From: Michael Eischer Date: Sat, 20 Jan 2024 15:40:09 +0100 Subject: [PATCH] split deleteFiles into UI and logic parts --- cmd/restic/delete.go | 56 ++++++++++--------------------------- internal/restic/parallel.go | 42 ++++++++++++++++++++++++++++ 2 files changed, 56 insertions(+), 42 deletions(-) diff --git a/cmd/restic/delete.go b/cmd/restic/delete.go index 1b7937bd3..c3a7e039d 100644 --- a/cmd/restic/delete.go +++ b/cmd/restic/delete.go @@ -3,9 +3,6 @@ package main import ( "context" - "golang.org/x/sync/errgroup" - - "github.com/restic/restic/internal/backend" "github.com/restic/restic/internal/restic" ) @@ -24,46 +21,21 @@ func DeleteFilesChecked(ctx context.Context, gopts GlobalOptions, repo restic.Re // deleteFiles deletes the given fileList of fileType in parallel // if ignoreError=true, it will print a warning if there was an error, else it will abort. func deleteFiles(ctx context.Context, gopts GlobalOptions, ignoreError bool, repo restic.Repository, fileList restic.IDSet, fileType restic.FileType) error { - totalCount := len(fileList) - fileChan := make(chan restic.ID) - wg, ctx := errgroup.WithContext(ctx) - wg.Go(func() error { - defer close(fileChan) - for id := range fileList { - select { - case fileChan <- id: - case <-ctx.Done(): - return ctx.Err() + bar := newProgressMax(!gopts.JSON && !gopts.Quiet, 0, "files deleted") + defer bar.Done() + + return restic.ParallelRemove(ctx, repo, fileList, fileType, func(id restic.ID, err error) error { + if err != nil { + if !gopts.JSON { + Warnf("unable to remove %v/%v from the repository\n", fileType, id) + } + if !ignoreError { + return err } } + if !gopts.JSON && gopts.verbosity > 2 { + Verbosef("removed %v/%v\n", fileType, id) + } return nil - }) - - bar := newProgressMax(!gopts.JSON && !gopts.Quiet, uint64(totalCount), "files deleted") - defer bar.Done() - // deleting files is IO-bound - workerCount := repo.Connections() - for i := 0; i < int(workerCount); i++ { - wg.Go(func() error { - for id := range fileChan { - h := backend.Handle{Type: fileType, Name: id.String()} - err := repo.Backend().Remove(ctx, h) - if err != nil { - if !gopts.JSON { - Warnf("unable to remove %v from the repository\n", h) - } - if !ignoreError { - return err - } - } - if !gopts.JSON && gopts.verbosity > 2 { - Verbosef("removed %v\n", h) - } - bar.Add(1) - } - return nil - }) - } - err := wg.Wait() - return err + }, bar) } diff --git a/internal/restic/parallel.go b/internal/restic/parallel.go index b22a249fe..cefbf0358 100644 --- a/internal/restic/parallel.go +++ b/internal/restic/parallel.go @@ -3,7 +3,9 @@ package restic import ( "context" + "github.com/restic/restic/internal/backend" "github.com/restic/restic/internal/debug" + "github.com/restic/restic/internal/ui/progress" "golang.org/x/sync/errgroup" ) @@ -50,3 +52,43 @@ func ParallelList(ctx context.Context, r Lister, t FileType, parallelism uint, f return wg.Wait() } + +// ParallelRemove deletes the given fileList of fileType in parallel +// if callback returns an error, then it will abort. +func ParallelRemove(ctx context.Context, repo Repository, fileList IDSet, fileType FileType, report func(id ID, err error) error, bar *progress.Counter) error { + fileChan := make(chan ID) + wg, ctx := errgroup.WithContext(ctx) + wg.Go(func() error { + defer close(fileChan) + for id := range fileList { + select { + case fileChan <- id: + case <-ctx.Done(): + return ctx.Err() + } + } + return nil + }) + + bar.SetMax(uint64(len(fileList))) + + // deleting files is IO-bound + workerCount := repo.Connections() + for i := 0; i < int(workerCount); i++ { + wg.Go(func() error { + for id := range fileChan { + h := backend.Handle{Type: fileType, Name: id.String()} + err := repo.Backend().Remove(ctx, h) + if report != nil { + err = report(id, err) + } + if err != nil { + return err + } + bar.Add(1) + } + return nil + }) + } + return wg.Wait() +}