2015-07-04 15:47:42 +00:00
|
|
|
package repository
|
|
|
|
|
|
|
|
import (
|
|
|
|
"sync"
|
|
|
|
|
|
|
|
"github.com/restic/restic/backend"
|
|
|
|
)
|
|
|
|
|
|
|
|
func closeIfOpen(ch chan struct{}) {
|
|
|
|
// only close ch when it is not already closed, in which the case statement runs.
|
|
|
|
select {
|
|
|
|
case <-ch:
|
|
|
|
return
|
|
|
|
default:
|
|
|
|
close(ch)
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2015-07-04 16:20:37 +00:00
|
|
|
// ParallelWorkFunc gets one file ID to work on. If an error is returned,
|
|
|
|
// processing stops. If done is closed, the function should return.
|
|
|
|
type ParallelWorkFunc func(id string, done <-chan struct{}) error
|
|
|
|
|
2015-08-08 11:47:08 +00:00
|
|
|
// ParallelIDWorkFunc gets one backend.ID to work on. If an error is returned,
|
|
|
|
// processing stops. If done is closed, the function should return.
|
|
|
|
type ParallelIDWorkFunc func(id backend.ID, done <-chan struct{}) error
|
|
|
|
|
2015-07-04 15:47:42 +00:00
|
|
|
// FilesInParallel runs n workers of f in parallel, on the IDs that
|
|
|
|
// repo.List(t) yield. If f returns an error, the process is aborted and the
|
|
|
|
// first error is returned.
|
2015-07-04 16:20:37 +00:00
|
|
|
func FilesInParallel(repo backend.Lister, t backend.Type, n uint, f ParallelWorkFunc) error {
|
2015-07-04 15:47:42 +00:00
|
|
|
done := make(chan struct{})
|
|
|
|
defer closeIfOpen(done)
|
|
|
|
|
|
|
|
wg := &sync.WaitGroup{}
|
|
|
|
|
|
|
|
ch := repo.List(t, done)
|
|
|
|
|
|
|
|
errors := make(chan error, n)
|
|
|
|
|
|
|
|
for i := 0; uint(i) < n; i++ {
|
|
|
|
wg.Add(1)
|
|
|
|
go func() {
|
|
|
|
defer wg.Done()
|
|
|
|
|
|
|
|
for {
|
|
|
|
select {
|
2015-07-04 16:20:37 +00:00
|
|
|
case id, ok := <-ch:
|
2015-07-04 15:47:42 +00:00
|
|
|
if !ok {
|
|
|
|
return
|
|
|
|
}
|
|
|
|
|
2015-07-04 16:20:37 +00:00
|
|
|
err := f(id, done)
|
2015-07-04 15:47:42 +00:00
|
|
|
if err != nil {
|
|
|
|
closeIfOpen(done)
|
|
|
|
errors <- err
|
|
|
|
return
|
|
|
|
}
|
|
|
|
case <-done:
|
|
|
|
return
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}()
|
|
|
|
}
|
|
|
|
|
|
|
|
wg.Wait()
|
|
|
|
|
|
|
|
select {
|
|
|
|
case err := <-errors:
|
|
|
|
return err
|
|
|
|
default:
|
|
|
|
break
|
|
|
|
}
|
|
|
|
|
|
|
|
return nil
|
|
|
|
}
|
2015-08-08 11:47:08 +00:00
|
|
|
|
|
|
|
// ParallelWorkFuncParseID converts a function that takes a backend.ID to a
|
|
|
|
// function that takes a string.
|
|
|
|
func ParallelWorkFuncParseID(f ParallelIDWorkFunc) ParallelWorkFunc {
|
|
|
|
return func(s string, done <-chan struct{}) error {
|
|
|
|
id, err := backend.ParseID(s)
|
|
|
|
if err != nil {
|
|
|
|
return err
|
|
|
|
}
|
|
|
|
|
|
|
|
return f(id, done)
|
|
|
|
}
|
|
|
|
}
|