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"
 | 
			
		||||
	"errors"
 | 
			
		||||
	"sort"
 | 
			
		||||
 | 
			
		||||
	"github.com/sirupsen/logrus"
 | 
			
		||||
)
 | 
			
		||||
 | 
			
		||||
// 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.
 | 
			
		||||
		fileInfo, err := driver.Stat(ctx, child)
 | 
			
		||||
		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)
 | 
			
		||||
		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