1
0
Fork 0
mirror of https://github.com/restic/restic.git synced 2024-12-23 00:07:25 +00:00

backup: Fix deadlock

When the archiver is faster than the scanner, restic deadlocks. This
commit adds a `finished` channel to the struct in `ui/backup.go` so that
scanner results are ignored when the archiver is already finished.

Closes #1834
This commit is contained in:
Alexander Neumann 2018-06-09 12:15:19 +02:00
parent ab37c6095a
commit c44e808aa5
2 changed files with 14 additions and 5 deletions

View file

@ -58,6 +58,9 @@ func (s *Scanner) Scan(ctx context.Context, targets []string) error {
} }
} }
if ctx.Err() != nil {
return ctx.Err()
}
s.Result("", stats) s.Result("", stats)
return nil return nil
} }
@ -107,6 +110,9 @@ func (s *Scanner) scan(ctx context.Context, stats ScanStats, target string) (Sca
stats.Others++ stats.Others++
} }
if ctx.Err() != nil {
return stats, ctx.Err()
}
s.Result(target, stats) s.Result(target, stats)
return stats, nil return stats, nil
} }

View file

@ -40,7 +40,7 @@ type Backup struct {
processedCh chan counter processedCh chan counter
errCh chan struct{} errCh chan struct{}
workerCh chan fileWorkerMessage workerCh chan fileWorkerMessage
clearStatus chan struct{} finished chan struct{}
summary struct { summary struct {
sync.Mutex sync.Mutex
@ -69,7 +69,7 @@ func NewBackup(term *termstatus.Terminal, verbosity uint) *Backup {
processedCh: make(chan counter), processedCh: make(chan counter),
errCh: make(chan struct{}), errCh: make(chan struct{}),
workerCh: make(chan fileWorkerMessage), workerCh: make(chan fileWorkerMessage),
clearStatus: make(chan struct{}), finished: make(chan struct{}),
} }
} }
@ -92,7 +92,7 @@ func (b *Backup) Run(ctx context.Context) error {
select { select {
case <-ctx.Done(): case <-ctx.Done():
return nil return nil
case <-b.clearStatus: case <-b.finished:
started = false started = false
b.term.SetStatus([]string{""}) b.term.SetStatus([]string{""})
case t, ok := <-b.totalCh: case t, ok := <-b.totalCh:
@ -333,7 +333,10 @@ func (b *Backup) CompleteItemFn(item string, previous, current *restic.Node, s a
// ReportTotal sets the total stats up to now // ReportTotal sets the total stats up to now
func (b *Backup) ReportTotal(item string, s archiver.ScanStats) { func (b *Backup) ReportTotal(item string, s archiver.ScanStats) {
b.totalCh <- counter{Files: s.Files, Dirs: s.Dirs, Bytes: s.Bytes} select {
case b.totalCh <- counter{Files: s.Files, Dirs: s.Dirs, Bytes: s.Bytes}:
case <-b.finished:
}
if item == "" { if item == "" {
b.V("scan finished in %.3fs: %v files, %s", b.V("scan finished in %.3fs: %v files, %s",
@ -347,7 +350,7 @@ func (b *Backup) ReportTotal(item string, s archiver.ScanStats) {
// Finish prints the finishing messages. // Finish prints the finishing messages.
func (b *Backup) Finish() { func (b *Backup) Finish() {
b.clearStatus <- struct{}{} close(b.finished)
b.P("\n") b.P("\n")
b.P("Files: %5d new, %5d changed, %5d unmodified\n", b.summary.Files.New, b.summary.Files.Changed, b.summary.Files.Unchanged) b.P("Files: %5d new, %5d changed, %5d unmodified\n", b.summary.Files.New, b.summary.Files.Changed, b.summary.Files.Unchanged)