storage: enforce sorted traversal during Walk

Signed-off-by: Stephen J Day <stephen.day@docker.com>
This commit is contained in:
Stephen J Day 2015-12-01 16:24:31 -08:00
parent 6ad10796ef
commit 5d576bc0cd
2 changed files with 14 additions and 0 deletions

View File

@ -3,6 +3,7 @@ package storage
import ( import (
"errors" "errors"
"fmt" "fmt"
"sort"
"github.com/docker/distribution/context" "github.com/docker/distribution/context"
storageDriver "github.com/docker/distribution/registry/storage/driver" storageDriver "github.com/docker/distribution/registry/storage/driver"
@ -26,7 +27,12 @@ func Walk(ctx context.Context, driver storageDriver.StorageDriver, from string,
if err != nil { if err != nil {
return err return err
} }
sort.Stable(sort.StringSlice(children))
for _, child := range children { for _, child := range children {
// TODO(stevvooe): Calling driver.Stat for every entry is quite
// expensive when running against backends with a slow Stat
// implementation, such as s3. This is very likely a serious
// performance bottleneck.
fileInfo, err := driver.Stat(ctx, child) fileInfo, err := driver.Stat(ctx, child)
if err != nil { if err != nil {
return err return err

View File

@ -2,6 +2,7 @@ package storage
import ( import (
"fmt" "fmt"
"sort"
"testing" "testing"
"github.com/docker/distribution/context" "github.com/docker/distribution/context"
@ -73,6 +74,7 @@ func TestWalkErrors(t *testing.T) {
func TestWalk(t *testing.T) { func TestWalk(t *testing.T) {
d, expected, ctx := testFS(t) d, expected, ctx := testFS(t)
var traversed []string
err := Walk(ctx, d, "/", func(fileInfo driver.FileInfo) error { err := Walk(ctx, d, "/", func(fileInfo driver.FileInfo) error {
filePath := fileInfo.Path() filePath := fileInfo.Path()
filetype, ok := expected[filePath] filetype, ok := expected[filePath]
@ -90,11 +92,17 @@ func TestWalk(t *testing.T) {
} }
} }
delete(expected, filePath) delete(expected, filePath)
traversed = append(traversed, filePath)
return nil return nil
}) })
if len(expected) > 0 { if len(expected) > 0 {
t.Errorf("Missed files in walk: %q", expected) t.Errorf("Missed files in walk: %q", expected)
} }
if !sort.StringsAreSorted(traversed) {
t.Errorf("result should be sorted: %v", traversed)
}
if err != nil { if err != nil {
t.Fatalf(err.Error()) t.Fatalf(err.Error())
} }