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) {
|
||||
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)
|
||||
defer cancel()
|
||||
|
||||
@@ -102,11 +106,7 @@ func processOneDirectory(ctx context.Context, filerClient FilerClient, parentPat
|
||||
}
|
||||
|
||||
if entry.IsDirectory {
|
||||
subDir := fmt.Sprintf("%s/%s", parentPath, entry.Name)
|
||||
if parentPath == "/" {
|
||||
subDir = "/" + entry.Name
|
||||
}
|
||||
if !enqueue(util.FullPath(subDir)) {
|
||||
if !enqueue(parentPath.Child(entry.Name)) {
|
||||
return ctx.Err()
|
||||
}
|
||||
}
|
||||
|
||||
@@ -4,6 +4,8 @@ import (
|
||||
"context"
|
||||
"fmt"
|
||||
"net"
|
||||
"reflect"
|
||||
"sort"
|
||||
"strings"
|
||||
"sync"
|
||||
"testing"
|
||||
@@ -150,3 +152,40 @@ func TestReadDirAllEntriesStuckPagination(t *testing.T) {
|
||||
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