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>master
							parent
							
								
									9930542dc5
								
							
						
					
					
						commit
						6b73a9ab89
					
				| 
						 | 
					@ -4,6 +4,8 @@ import (
 | 
				
			||||||
	"context"
 | 
						"context"
 | 
				
			||||||
	"errors"
 | 
						"errors"
 | 
				
			||||||
	"sort"
 | 
						"sort"
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						"github.com/sirupsen/logrus"
 | 
				
			||||||
)
 | 
					)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
// ErrSkipDir is used as a return value from onFileFunc to indicate that
 | 
					// ErrSkipDir is used as a return value from onFileFunc to indicate that
 | 
				
			||||||
| 
						 | 
					@ -32,7 +34,14 @@ func WalkFallback(ctx context.Context, driver StorageDriver, from string, f Walk
 | 
				
			||||||
		// performance bottleneck.
 | 
							// performance bottleneck.
 | 
				
			||||||
		fileInfo, err := driver.Stat(ctx, child)
 | 
							fileInfo, err := driver.Stat(ctx, child)
 | 
				
			||||||
		if err != nil {
 | 
							if err != nil {
 | 
				
			||||||
			return err
 | 
								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)
 | 
							err = f(fileInfo)
 | 
				
			||||||
		if err == nil && fileInfo.IsDir() {
 | 
							if err == nil && fileInfo.IsDir() {
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
| 
						 | 
					@ -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 New Issue