mirror of
https://github.com/seaweedfs/seaweedfs.git
synced 2026-09-08 15:41:15 +02:00
filer_pb: walk the whole tree when the BFS start path ends in a slash (#11099)
* filer_pb: build BFS child paths with FullPath.Child A start path with a trailing slash produced "/dir//sub" for every subdirectory, and the filer only trims a trailing slash, so those listings came back empty and the walk stopped after the first level. Claude-Session: https://claude.ai/code/session_01Jp9tXRpBv9gvh8fkaVFqxQ * filer_pb: normalize the BFS start path Entries directly under the start path were reported with the caller's trailing slash, so filer.meta.backup wrote them under a directory the incremental stream never names again. Claude-Session: https://claude.ai/code/session_01Jp9tXRpBv9gvh8fkaVFqxQ
This commit is contained in:
@@ -15,6 +15,10 @@ import (
|
|||||||
func TraverseBfs(ctx context.Context, filerClient FilerClient, parentPath util.FullPath, fn func(parentPath util.FullPath, entry *Entry) error) (err error) {
|
func TraverseBfs(ctx context.Context, filerClient FilerClient, parentPath util.FullPath, fn func(parentPath util.FullPath, entry *Entry) error) (err error) {
|
||||||
K := 5
|
K := 5
|
||||||
|
|
||||||
|
// callers hand in user-typed paths, and every entry is reported relative
|
||||||
|
// to this one, so a trailing slash must not reach the callback
|
||||||
|
parentPath = util.NormalizePath(string(parentPath))
|
||||||
|
|
||||||
ctx, cancel := context.WithCancel(ctx)
|
ctx, cancel := context.WithCancel(ctx)
|
||||||
defer cancel()
|
defer cancel()
|
||||||
|
|
||||||
@@ -102,11 +106,7 @@ func processOneDirectory(ctx context.Context, filerClient FilerClient, parentPat
|
|||||||
}
|
}
|
||||||
|
|
||||||
if entry.IsDirectory {
|
if entry.IsDirectory {
|
||||||
subDir := fmt.Sprintf("%s/%s", parentPath, entry.Name)
|
if !enqueue(parentPath.Child(entry.Name)) {
|
||||||
if parentPath == "/" {
|
|
||||||
subDir = "/" + entry.Name
|
|
||||||
}
|
|
||||||
if !enqueue(util.FullPath(subDir)) {
|
|
||||||
return ctx.Err()
|
return ctx.Err()
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -4,6 +4,8 @@ import (
|
|||||||
"context"
|
"context"
|
||||||
"fmt"
|
"fmt"
|
||||||
"net"
|
"net"
|
||||||
|
"reflect"
|
||||||
|
"sort"
|
||||||
"strings"
|
"strings"
|
||||||
"sync"
|
"sync"
|
||||||
"testing"
|
"testing"
|
||||||
@@ -150,3 +152,40 @@ func TestReadDirAllEntriesStuckPagination(t *testing.T) {
|
|||||||
t.Fatal("listing loops forever on a non-advancing store")
|
t.Fatal("listing loops forever on a non-advancing store")
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// A start path with a trailing slash must still descend into subdirectories.
|
||||||
|
func TestTraverseBfsTrailingSlashRoot(t *testing.T) {
|
||||||
|
server := &stubFiler{}
|
||||||
|
server.listings = func(req *ListEntriesRequest, send func(*Entry) error) error {
|
||||||
|
if req.StartFromFileName != "" {
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
// the filer trims a single trailing slash, nothing more
|
||||||
|
switch strings.TrimSuffix(req.Directory, "/") {
|
||||||
|
case "/buckets/data":
|
||||||
|
return send(&Entry{Name: "sub", IsDirectory: true})
|
||||||
|
case "/buckets/data/sub":
|
||||||
|
return send(&Entry{Name: "a.txt"})
|
||||||
|
}
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
filerClient := startStubFiler(t, server)
|
||||||
|
|
||||||
|
var mu sync.Mutex
|
||||||
|
var seen []string
|
||||||
|
err := TraverseBfs(context.Background(), filerClient, "/buckets/data/", func(parentPath util.FullPath, entry *Entry) error {
|
||||||
|
mu.Lock()
|
||||||
|
seen = append(seen, fmt.Sprintf("%s -> %s", parentPath, entry.Name))
|
||||||
|
mu.Unlock()
|
||||||
|
return nil
|
||||||
|
})
|
||||||
|
if err != nil {
|
||||||
|
t.Fatal(err)
|
||||||
|
}
|
||||||
|
|
||||||
|
sort.Strings(seen)
|
||||||
|
want := []string{"/buckets/data -> sub", "/buckets/data/sub -> a.txt"}
|
||||||
|
if !reflect.DeepEqual(seen, want) {
|
||||||
|
t.Fatalf("visited %v, want %v", seen, want)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|||||||
Reference in New Issue
Block a user