mirror of
https://github.com/seaweedfs/seaweedfs.git
synced 2026-09-08 15:41:15 +02:00
mount: reuse the listed entry's path instead of rebuilding it (#10817)
readdir built dirPath.Child(name) for every child while entry.FullPath was already that exact string, from NewFullPath in the meta cache store or from FromPbEntry on the read-through path. One allocation per entry, and on a wide tree with long paths that is most of what a listing allocates. BenchmarkReadDirectory/kernel_readdirplus over 200k entries: 2,039,656 -> 1,839,318 allocs/op, 174.5 -> 167.8 MB/op, 152.6 -> 135.1 ms/op.
This commit is contained in:
@@ -3,6 +3,7 @@ package mount
|
||||
import (
|
||||
"context"
|
||||
"errors"
|
||||
"strings"
|
||||
"sync"
|
||||
"time"
|
||||
|
||||
@@ -219,7 +220,11 @@ func (wfs *WFS) doReadDirectory(input *fuse.ReadIn, out DirEntrySink, isPlusMode
|
||||
processEachEntryFn := func(entry *filer.Entry, index int64) bool {
|
||||
dirEntry.Name = entry.Name()
|
||||
dirEntry.Mode = toSyscallMode(entry.Mode)
|
||||
childPath := dirPath.Child(dirEntry.Name)
|
||||
// Rebuild only for a sanitized name: that is the one a LOOKUP carries.
|
||||
childPath := entry.FullPath
|
||||
if !strings.HasSuffix(string(childPath), dirEntry.Name) {
|
||||
childPath = dirPath.Child(dirEntry.Name)
|
||||
}
|
||||
var inode uint64
|
||||
if takesLookupRef {
|
||||
inode = wfs.inodeToPath.Lookup(childPath, entry.Crtime.Unix(), entry.IsDirectory(), len(entry.HardLinkId) > 0, entry.Inode, false)
|
||||
|
||||
@@ -336,3 +336,24 @@ func TestReadDirDirectTrimsConsumedEntries(t *testing.T) {
|
||||
t.Errorf("handle held %d entries at peak, want well under the %d in the directory", peak, total)
|
||||
}
|
||||
}
|
||||
|
||||
// The table has to key on the sanitized name, not the stored bytes.
|
||||
func TestReadDirPlusSanitizedName(t *testing.T) {
|
||||
dir := util.FullPath("/images")
|
||||
const rawName = "bad\xffname.jpg"
|
||||
wfs := newPagingWFS(t, dir, []string{"good.jpg", rawName}, 0)
|
||||
dirInode, _ := wfs.inodeToPath.GetInode(dir)
|
||||
|
||||
sink := &benchSink{plus: true, takesRef: true, sinkLimit: 16}
|
||||
if got := walkOnce(t, wfs, dirInode, sink, false); got != 4 {
|
||||
t.Fatalf("listed %d entries, want 4 (. .. and two children)", got)
|
||||
}
|
||||
|
||||
sanitized := dir.Child(util.SanitizeUTF8Name(rawName))
|
||||
if !wfs.inodeToPath.HasPath(sanitized) {
|
||||
t.Errorf("%s not in the inode table", sanitized)
|
||||
}
|
||||
if wfs.inodeToPath.HasPath(dir.Child(rawName)) {
|
||||
t.Errorf("%s keyed on the unsanitized name", dir.Child(rawName))
|
||||
}
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user