mirror of
https://github.com/octoleo/restic.git
synced 2025-01-27 09:08:26 +00:00
checker: use channel of error instead of slice
This commit is contained in:
parent
7e6174126f
commit
af02c323cd
@ -192,28 +192,22 @@ outer:
|
|||||||
}
|
}
|
||||||
|
|
||||||
// Packs checks that all packs referenced in the index are still available and
|
// Packs checks that all packs referenced in the index are still available and
|
||||||
// there are no packs that aren't in an index.
|
// there are no packs that aren't in an index. errChan is closed after all
|
||||||
func (c *Checker) Packs() []error {
|
// packs have been checked.
|
||||||
|
func (c *Checker) Packs(errChan chan<- error, done <-chan struct{}) {
|
||||||
|
defer close(errChan)
|
||||||
|
|
||||||
debug.Log("Checker.Packs", "checking for %d packs", len(c.packs))
|
debug.Log("Checker.Packs", "checking for %d packs", len(c.packs))
|
||||||
seenPacks := make(map[mapID]struct{})
|
seenPacks := make(map[mapID]struct{})
|
||||||
|
|
||||||
done := make(chan struct{})
|
|
||||||
defer close(done)
|
|
||||||
|
|
||||||
var workerWG sync.WaitGroup
|
var workerWG sync.WaitGroup
|
||||||
|
|
||||||
IDChan := make(chan mapID)
|
IDChan := make(chan mapID)
|
||||||
errChan := make(chan error)
|
|
||||||
|
|
||||||
for i := 0; i < defaultParallelism; i++ {
|
for i := 0; i < defaultParallelism; i++ {
|
||||||
workerWG.Add(1)
|
workerWG.Add(1)
|
||||||
go packIDTester(c.repo, IDChan, errChan, &workerWG, done)
|
go packIDTester(c.repo, IDChan, errChan, &workerWG, done)
|
||||||
}
|
}
|
||||||
|
|
||||||
errsChan := make(chan []error, 1)
|
|
||||||
|
|
||||||
go collectErrors(errChan, errsChan, done)
|
|
||||||
|
|
||||||
for id := range c.packs {
|
for id := range c.packs {
|
||||||
seenPacks[id] = struct{}{}
|
seenPacks[id] = struct{}{}
|
||||||
IDChan <- id
|
IDChan <- id
|
||||||
@ -223,19 +217,17 @@ func (c *Checker) Packs() []error {
|
|||||||
debug.Log("Checker.Packs", "waiting for %d workers to terminate", defaultParallelism)
|
debug.Log("Checker.Packs", "waiting for %d workers to terminate", defaultParallelism)
|
||||||
workerWG.Wait()
|
workerWG.Wait()
|
||||||
debug.Log("Checker.Packs", "workers terminated")
|
debug.Log("Checker.Packs", "workers terminated")
|
||||||
close(errChan)
|
|
||||||
|
|
||||||
errs := <-errsChan
|
|
||||||
debug.Log("Checker.Packs", "error worker terminated")
|
|
||||||
|
|
||||||
for id := range c.repo.List(backend.Data, done) {
|
for id := range c.repo.List(backend.Data, done) {
|
||||||
debug.Log("Checker.Packs", "check data blob %v", id)
|
debug.Log("Checker.Packs", "check data blob %v", id)
|
||||||
if _, ok := seenPacks[id2map(id)]; !ok {
|
if _, ok := seenPacks[id2map(id)]; !ok {
|
||||||
errs = append(errs, PackError{id, errors.New("not referenced in any index")})
|
select {
|
||||||
|
case <-done:
|
||||||
|
return
|
||||||
|
case errChan <- PackError{id, errors.New("not referenced in any index")}:
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
return errs
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// Error is an error that occurred while checking a repository.
|
// Error is an error that occurred while checking a repository.
|
||||||
@ -276,10 +268,9 @@ func loadTreeFromSnapshot(repo *repository.Repository, id backend.ID) (backend.I
|
|||||||
}
|
}
|
||||||
|
|
||||||
// Structure checks that for all snapshots all referenced blobs are available
|
// Structure checks that for all snapshots all referenced blobs are available
|
||||||
// in the index.
|
// in the index. errChan is closed after all trees have been traversed.
|
||||||
func (c *Checker) Structure() (errs []error) {
|
func (c *Checker) Structure(errChan chan<- error, done <-chan struct{}) {
|
||||||
done := make(chan struct{})
|
defer close(errChan)
|
||||||
defer close(done)
|
|
||||||
|
|
||||||
var todo backend.IDs
|
var todo backend.IDs
|
||||||
|
|
||||||
@ -288,7 +279,11 @@ func (c *Checker) Structure() (errs []error) {
|
|||||||
|
|
||||||
treeID, err := loadTreeFromSnapshot(c.repo, id)
|
treeID, err := loadTreeFromSnapshot(c.repo, id)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
errs = append(errs, err)
|
select {
|
||||||
|
case <-done:
|
||||||
|
return
|
||||||
|
case errChan <- err:
|
||||||
|
}
|
||||||
continue
|
continue
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -296,8 +291,13 @@ func (c *Checker) Structure() (errs []error) {
|
|||||||
todo = append(todo, treeID)
|
todo = append(todo, treeID)
|
||||||
}
|
}
|
||||||
|
|
||||||
errs = append(errs, c.trees(todo)...)
|
for _, err := range c.trees(todo) {
|
||||||
return errs
|
select {
|
||||||
|
case <-done:
|
||||||
|
return
|
||||||
|
case errChan <- err:
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
func (c *Checker) trees(treeIDs backend.IDs) (errs []error) {
|
func (c *Checker) trees(treeIDs backend.IDs) (errs []error) {
|
||||||
|
@ -24,14 +24,44 @@ func list(repo *repository.Repository, t backend.Type) (IDs []string) {
|
|||||||
return IDs
|
return IDs
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func checkPacks(chkr *checker.Checker) (errs []error) {
|
||||||
|
done := make(chan struct{})
|
||||||
|
defer close(done)
|
||||||
|
|
||||||
|
errChan := make(chan error)
|
||||||
|
|
||||||
|
go chkr.Packs(errChan, done)
|
||||||
|
|
||||||
|
for err := range errChan {
|
||||||
|
errs = append(errs, err)
|
||||||
|
}
|
||||||
|
|
||||||
|
return errs
|
||||||
|
}
|
||||||
|
|
||||||
|
func checkStruct(chkr *checker.Checker) (errs []error) {
|
||||||
|
done := make(chan struct{})
|
||||||
|
defer close(done)
|
||||||
|
|
||||||
|
errChan := make(chan error)
|
||||||
|
|
||||||
|
go chkr.Structure(errChan, done)
|
||||||
|
|
||||||
|
for err := range errChan {
|
||||||
|
errs = append(errs, err)
|
||||||
|
}
|
||||||
|
|
||||||
|
return errs
|
||||||
|
}
|
||||||
|
|
||||||
func TestCheckRepo(t *testing.T) {
|
func TestCheckRepo(t *testing.T) {
|
||||||
WithTestEnvironment(t, checkerTestData, func(repodir string) {
|
WithTestEnvironment(t, checkerTestData, func(repodir string) {
|
||||||
repo := OpenLocalRepo(t, repodir)
|
repo := OpenLocalRepo(t, repodir)
|
||||||
|
|
||||||
chkr := checker.New(repo)
|
chkr := checker.New(repo)
|
||||||
OK(t, chkr.LoadIndex())
|
OK(t, chkr.LoadIndex())
|
||||||
OKs(t, chkr.Packs())
|
OKs(t, checkPacks(chkr))
|
||||||
OKs(t, chkr.Structure())
|
OKs(t, checkStruct(chkr))
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -44,7 +74,7 @@ func TestMissingPack(t *testing.T) {
|
|||||||
|
|
||||||
chkr := checker.New(repo)
|
chkr := checker.New(repo)
|
||||||
OK(t, chkr.LoadIndex())
|
OK(t, chkr.LoadIndex())
|
||||||
errs := chkr.Packs()
|
errs := checkPacks(chkr)
|
||||||
|
|
||||||
Assert(t, len(errs) == 1,
|
Assert(t, len(errs) == 1,
|
||||||
"expected exactly one error, got %v", len(errs))
|
"expected exactly one error, got %v", len(errs))
|
||||||
@ -68,7 +98,7 @@ func TestUnreferencedPack(t *testing.T) {
|
|||||||
|
|
||||||
chkr := checker.New(repo)
|
chkr := checker.New(repo)
|
||||||
OK(t, chkr.LoadIndex())
|
OK(t, chkr.LoadIndex())
|
||||||
errs := chkr.Packs()
|
errs := checkPacks(chkr)
|
||||||
|
|
||||||
Assert(t, len(errs) == 1,
|
Assert(t, len(errs) == 1,
|
||||||
"expected exactly one error, got %v", len(errs))
|
"expected exactly one error, got %v", len(errs))
|
||||||
@ -101,8 +131,8 @@ func TestUnreferencedBlobs(t *testing.T) {
|
|||||||
|
|
||||||
chkr := checker.New(repo)
|
chkr := checker.New(repo)
|
||||||
OK(t, chkr.LoadIndex())
|
OK(t, chkr.LoadIndex())
|
||||||
OKs(t, chkr.Packs())
|
OKs(t, checkPacks(chkr))
|
||||||
OKs(t, chkr.Structure())
|
OKs(t, checkStruct(chkr))
|
||||||
|
|
||||||
blobs := chkr.UnusedBlobs()
|
blobs := chkr.UnusedBlobs()
|
||||||
sort.Sort(blobs)
|
sort.Sort(blobs)
|
||||||
|
@ -52,15 +52,25 @@ func (cmd CmdCheck) Execute(args []string) error {
|
|||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
|
|
||||||
|
done := make(chan struct{})
|
||||||
|
defer close(done)
|
||||||
|
|
||||||
errorsFound := false
|
errorsFound := false
|
||||||
|
errChan := make(chan error)
|
||||||
|
|
||||||
cmd.global.Verbosef("Check all packs\n")
|
cmd.global.Verbosef("Check all packs\n")
|
||||||
for _, err := range checker.Packs() {
|
go checker.Packs(errChan, done)
|
||||||
|
|
||||||
|
for err := range errChan {
|
||||||
errorsFound = true
|
errorsFound = true
|
||||||
fmt.Fprintf(os.Stderr, "error: %v\n", err)
|
fmt.Fprintf(os.Stderr, "error: %v\n", err)
|
||||||
}
|
}
|
||||||
|
|
||||||
cmd.global.Verbosef("Check snapshots, trees and blobs\n")
|
cmd.global.Verbosef("Check snapshots, trees and blobs\n")
|
||||||
for _, err := range checker.Structure() {
|
errChan = make(chan error)
|
||||||
|
go checker.Structure(errChan, done)
|
||||||
|
|
||||||
|
for err := range errChan {
|
||||||
errorsFound = true
|
errorsFound = true
|
||||||
fmt.Fprintf(os.Stderr, "error: %v\n", err)
|
fmt.Fprintf(os.Stderr, "error: %v\n", err)
|
||||||
}
|
}
|
||||||
|
Loading…
x
Reference in New Issue
Block a user