Commit 9723c2be authored by Han-Wen Nienhuys's avatar Han-Wen Nienhuys

example/statfs: use new nodefs library

parent afbcb85e
...@@ -13,32 +13,27 @@ import ( ...@@ -13,32 +13,27 @@ import (
"path/filepath" "path/filepath"
"runtime" "runtime"
"sort" "sort"
"syscall"
"testing" "testing"
"time" "time"
"github.com/hanwen/go-fuse/fuse/nodefs" "github.com/hanwen/go-fuse/fuse"
"github.com/hanwen/go-fuse/fuse/pathfs"
"github.com/hanwen/go-fuse/internal/testutil" "github.com/hanwen/go-fuse/internal/testutil"
"github.com/hanwen/go-fuse/nodefs"
) )
func setupFs(fs pathfs.FileSystem, N int) (string, func()) { func setupFs(fs nodefs.InodeEmbedder, N int) (string, func()) {
opts := &nodefs.Options{ opts := &nodefs.Options{}
EntryTimeout: 0.0, opts.Debug = testutil.VerboseTest()
AttrTimeout: 0.0,
NegativeTimeout: 0.0,
}
mountPoint := testutil.TempDir() mountPoint := testutil.TempDir()
nfs := pathfs.NewPathNodeFs(fs, nil) server, err := nodefs.Mount(mountPoint, fs, opts)
state, _, err := nodefs.MountRoot(mountPoint, nfs.Root(), opts)
if err != nil { if err != nil {
panic(fmt.Sprintf("cannot mount %v", err)) // ugh - benchmark has no error methods. log.Panicf("cannot mount %v", err)
} }
lmap := NewLatencyMap() lmap := NewLatencyMap()
if testutil.VerboseTest() { if testutil.VerboseTest() {
state.RecordLatencies(lmap) server.RecordLatencies(lmap)
} }
go state.Serve()
return mountPoint, func() { return mountPoint, func() {
if testutil.VerboseTest() { if testutil.VerboseTest() {
var total time.Duration var total time.Duration
...@@ -55,7 +50,7 @@ func setupFs(fs pathfs.FileSystem, N int) (string, func()) { ...@@ -55,7 +50,7 @@ func setupFs(fs pathfs.FileSystem, N int) (string, func()) {
log.Printf("total %v, %v/bench op", total, total/time.Duration(N)) log.Printf("total %v, %v/bench op", total, total/time.Duration(N))
} }
err := state.Unmount() err := server.Unmount()
if err != nil { if err != nil {
log.Println("error during unmount", err) log.Println("error during unmount", err)
} else { } else {
...@@ -65,11 +60,11 @@ func setupFs(fs pathfs.FileSystem, N int) (string, func()) { ...@@ -65,11 +60,11 @@ func setupFs(fs pathfs.FileSystem, N int) (string, func()) {
} }
func TestNewStatFs(t *testing.T) { func TestNewStatFs(t *testing.T) {
fs := NewStatFS() fs := &StatFS{}
for _, n := range []string{ for _, n := range []string{
"file.txt", "sub/dir/foo.txt", "file.txt", "sub/dir/foo.txt",
"sub/dir/bar.txt", "sub/marine.txt"} { "sub/dir/bar.txt", "sub/marine.txt"} {
fs.AddFile(n) fs.AddFile(n, fuse.Attr{Mode: syscall.S_IFREG})
} }
wd, clean := setupFs(fs, 1) wd, clean := setupFs(fs, 1)
...@@ -116,13 +111,13 @@ func TestNewStatFs(t *testing.T) { ...@@ -116,13 +111,13 @@ func TestNewStatFs(t *testing.T) {
func BenchmarkGoFuseStat(b *testing.B) { func BenchmarkGoFuseStat(b *testing.B) {
b.StopTimer() b.StopTimer()
fs := NewStatFS() fs := &StatFS{}
wd, _ := os.Getwd() wd, _ := os.Getwd()
fileList := wd + "/testpaths.txt" fileList := wd + "/testpaths.txt"
files := ReadLines(fileList) files := ReadLines(fileList)
for _, fn := range files { for _, fn := range files {
fs.AddFile(fn) fs.AddFile(fn, fuse.Attr{Mode: syscall.S_IFREG})
} }
wd, clean := setupFs(fs, b.N) wd, clean := setupFs(fs, b.N)
...@@ -151,13 +146,13 @@ func readdir(d string) error { ...@@ -151,13 +146,13 @@ func readdir(d string) error {
func BenchmarkGoFuseReaddir(b *testing.B) { func BenchmarkGoFuseReaddir(b *testing.B) {
b.StopTimer() b.StopTimer()
fs := NewStatFS() fs := &StatFS{}
wd, _ := os.Getwd() wd, _ := os.Getwd()
dirSet := map[string]struct{}{} dirSet := map[string]struct{}{}
for _, fn := range ReadLines(wd + "/testpaths.txt") { for _, fn := range ReadLines(wd + "/testpaths.txt") {
fs.AddFile(fn) fs.AddFile(fn, fuse.Attr{Mode: syscall.S_IFREG})
dirSet[filepath.Dir(fn)] = struct{}{} dirSet[filepath.Dir(fn)] = struct{}{}
} }
......
...@@ -5,65 +5,66 @@ ...@@ -5,65 +5,66 @@
package benchmark package benchmark
import ( import (
"context"
"path/filepath" "path/filepath"
"strings" "strings"
"syscall"
"github.com/hanwen/go-fuse/fuse" "github.com/hanwen/go-fuse/fuse"
"github.com/hanwen/go-fuse/fuse/pathfs" "github.com/hanwen/go-fuse/nodefs"
) )
type StatFS struct { type StatFS struct {
pathfs.FileSystem nodefs.Inode
entries map[string]*fuse.Attr
dirs map[string][]fuse.DirEntry files map[string]fuse.Attr
} }
func (fs *StatFS) Add(name string, a *fuse.Attr) { var _ = (nodefs.OnAdder)((*StatFS)(nil))
name = strings.TrimRight(name, "/")
_, ok := fs.entries[name] func (r *StatFS) OnAdd(ctx context.Context) {
if ok { for nm, a := range r.files {
return r.addFile(nm, a)
} }
r.files = nil
}
fs.entries[name] = a func (r *StatFS) AddFile(name string, a fuse.Attr) {
if name == "/" || name == "" { if r.files == nil {
return r.files = map[string]fuse.Attr{}
} }
dir, base := filepath.Split(name) r.files[name] = a
dir = strings.TrimRight(dir, "/")
fs.dirs[dir] = append(fs.dirs[dir], fuse.DirEntry{Name: base, Mode: a.Mode})
fs.Add(dir, &fuse.Attr{Mode: fuse.S_IFDIR | 0755})
} }
func (fs *StatFS) AddFile(name string) { func (r *StatFS) addFile(name string, a fuse.Attr) {
fs.Add(name, &fuse.Attr{Mode: fuse.S_IFREG | 0644}) dir, base := filepath.Split(name)
}
func (fs *StatFS) GetAttr(name string, context *fuse.Context) (*fuse.Attr, fuse.Status) { p := r.EmbeddedInode()
if d := fs.dirs[name]; d != nil {
return &fuse.Attr{Mode: 0755 | fuse.S_IFDIR}, fuse.OK // Add directories leading up to the file.
for _, component := range strings.Split(dir, "/") {
if len(component) == 0 {
continue
} }
e := fs.entries[name] ch := p.GetChild(component)
if e == nil { if ch == nil {
return nil, fuse.ENOENT // Create a directory
ch = p.NewPersistentInode(context.Background(), &nodefs.Inode{},
nodefs.NodeAttr{Mode: syscall.S_IFDIR})
// Add it
p.AddChild(component, ch, true)
} }
return e, fuse.OK p = ch
}
func (fs *StatFS) OpenDir(name string, context *fuse.Context) (stream []fuse.DirEntry, status fuse.Status) {
entries := fs.dirs[name]
if entries == nil {
return nil, fuse.ENOENT
} }
return entries, fuse.OK
}
func NewStatFS() *StatFS { // Create the file
return &StatFS{ child := p.NewPersistentInode(context.Background(), &nodefs.MemRegularFile{
FileSystem: pathfs.NewDefaultFileSystem(), Data: make([]byte, a.Size),
entries: make(map[string]*fuse.Attr), Attr: a,
dirs: make(map[string][]fuse.DirEntry), }, nodefs.NodeAttr{})
}
// And add it
p.AddChild(base, child, true)
} }
...@@ -14,11 +14,12 @@ import ( ...@@ -14,11 +14,12 @@ import (
"runtime" "runtime"
"runtime/pprof" "runtime/pprof"
"strings" "strings"
"syscall"
"time" "time"
"github.com/hanwen/go-fuse/benchmark" "github.com/hanwen/go-fuse/benchmark"
"github.com/hanwen/go-fuse/fuse/nodefs" "github.com/hanwen/go-fuse/fuse"
"github.com/hanwen/go-fuse/fuse/pathfs" "github.com/hanwen/go-fuse/nodefs"
) )
func main() { func main() {
...@@ -27,7 +28,7 @@ func main() { ...@@ -27,7 +28,7 @@ func main() {
profile := flag.String("profile", "", "record cpu profile.") profile := flag.String("profile", "", "record cpu profile.")
mem_profile := flag.String("mem-profile", "", "record memory profile.") mem_profile := flag.String("mem-profile", "", "record memory profile.")
command := flag.String("run", "", "run this command after mounting.") command := flag.String("run", "", "run this command after mounting.")
ttl := flag.Float64("ttl", 1.0, "attribute/entry cache TTL.") ttl := flag.Duration("ttl", time.Second, "attribute/entry cache TTL.")
flag.Parse() flag.Parse()
if flag.NArg() < 2 { if flag.NArg() < 2 {
fmt.Fprintf(os.Stderr, "usage: %s MOUNTPOINT FILENAMES-FILE\n", os.Args[0]) fmt.Fprintf(os.Stderr, "usage: %s MOUNTPOINT FILENAMES-FILE\n", os.Args[0])
...@@ -48,21 +49,21 @@ func main() { ...@@ -48,21 +49,21 @@ func main() {
log.Fatalf("os.Create: %v", err) log.Fatalf("os.Create: %v", err)
} }
} }
fs := benchmark.NewStatFS()
fs := &benchmark.StatFS{}
lines := benchmark.ReadLines(flag.Arg(1)) lines := benchmark.ReadLines(flag.Arg(1))
for _, l := range lines { for _, l := range lines {
fs.AddFile(l) fs.AddFile(strings.TrimSpace(l),
fuse.Attr{Mode: syscall.S_IFREG})
} }
nfs := pathfs.NewPathNodeFs(fs, nil)
opts := &nodefs.Options{ opts := &nodefs.Options{
AttrTimeout: time.Duration(*ttl * float64(time.Second)), AttrTimeout: ttl,
EntryTimeout: time.Duration(*ttl * float64(time.Second)), EntryTimeout: ttl,
Debug: *debug,
} }
state, _, err := nodefs.MountRoot(flag.Arg(0), nfs.Root(), opts) opts.Debug = *debug
server, err := nodefs.Mount(flag.Arg(0), fs, opts)
if err != nil { if err != nil {
fmt.Printf("Mount fail: %v\n", err) log.Fatalf("Mount fail: %v\n", err)
os.Exit(1)
} }
runtime.GC() runtime.GC()
...@@ -78,7 +79,7 @@ func main() { ...@@ -78,7 +79,7 @@ func main() {
cmd.Start() cmd.Start()
} }
state.Serve() server.Wait()
if memProfFile != nil { if memProfFile != nil {
pprof.WriteHeapProfile(memProfFile) pprof.WriteHeapProfile(memProfFile)
} }
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment