forked from TrueCloudLab/distribution
Ignore missing paths during enumeration
It's possible to run into a race condition in which the enumerator lists lots of repositories and then starts the long process of enumerating through them. In that time if someone deletes a repo, the enumerator may error out. Signed-off-by: Ryan Abrams <rdabrams@gmail.com>
This commit is contained in:
parent
9930542dc5
commit
6b73a9ab89
2 changed files with 57 additions and 1 deletions
|
@ -4,6 +4,8 @@ import (
|
|||
"context"
|
||||
"errors"
|
||||
"sort"
|
||||
|
||||
"github.com/sirupsen/logrus"
|
||||
)
|
||||
|
||||
// ErrSkipDir is used as a return value from onFileFunc to indicate that
|
||||
|
@ -32,8 +34,15 @@ func WalkFallback(ctx context.Context, driver StorageDriver, from string, f Walk
|
|||
// performance bottleneck.
|
||||
fileInfo, err := driver.Stat(ctx, child)
|
||||
if err != nil {
|
||||
switch err.(type) {
|
||||
case PathNotFoundError:
|
||||
// repository was removed in between listing and enumeration. Ignore it.
|
||||
logrus.WithField("path", child).Infof("ignoring deleted path")
|
||||
continue
|
||||
default:
|
||||
return err
|
||||
}
|
||||
}
|
||||
err = f(fileInfo)
|
||||
if err == nil && fileInfo.IsDir() {
|
||||
if err := WalkFallback(ctx, driver, child, f); err != nil {
|
||||
|
|
47
registry/storage/driver/walk_test.go
Normal file
47
registry/storage/driver/walk_test.go
Normal file
|
@ -0,0 +1,47 @@
|
|||
package driver
|
||||
|
||||
import (
|
||||
"context"
|
||||
"fmt"
|
||||
"testing"
|
||||
)
|
||||
|
||||
type changingFileSystem struct {
|
||||
StorageDriver
|
||||
fileset []string
|
||||
keptFiles map[string]bool
|
||||
}
|
||||
|
||||
func (cfs *changingFileSystem) List(ctx context.Context, path string) ([]string, error) {
|
||||
return cfs.fileset, nil
|
||||
}
|
||||
func (cfs *changingFileSystem) Stat(ctx context.Context, path string) (FileInfo, error) {
|
||||
kept, ok := cfs.keptFiles[path]
|
||||
if ok && kept {
|
||||
return &FileInfoInternal{
|
||||
FileInfoFields: FileInfoFields{
|
||||
Path: path,
|
||||
},
|
||||
}, nil
|
||||
}
|
||||
return nil, PathNotFoundError{}
|
||||
}
|
||||
func TestWalkFileRemoved(t *testing.T) {
|
||||
d := &changingFileSystem{
|
||||
fileset: []string{"zoidberg", "bender"},
|
||||
keptFiles: map[string]bool{
|
||||
"zoidberg": true,
|
||||
},
|
||||
}
|
||||
infos := []FileInfo{}
|
||||
err := WalkFallback(context.Background(), d, "", func(fileInfo FileInfo) error {
|
||||
infos = append(infos, fileInfo)
|
||||
return nil
|
||||
})
|
||||
if len(infos) != 1 || infos[0].Path() != "zoidberg" {
|
||||
t.Errorf(fmt.Sprintf("unexpected path set during walk: %s", infos))
|
||||
}
|
||||
if err != nil {
|
||||
t.Fatalf(err.Error())
|
||||
}
|
||||
}
|
Loading…
Reference in a new issue