Return open file as FOPEN_KEEP_CACHE. This avoid having to read contents for each file through the FUSE connection over and over again. Change-Id: I5f8606516a1fda6ca66e5baf6723b964b500082b
diff --git a/fs/gitilesfs.go b/fs/gitilesfs.go index 8400832..1c0ee46 100644 --- a/fs/gitilesfs.go +++ b/fs/gitilesfs.go
@@ -22,6 +22,7 @@ "os" "path/filepath" "sync" + "sync/atomic" "syscall" "time" @@ -101,6 +102,9 @@ // The timestamp is writable; protect it with a mutex. mtimeMu sync.Mutex mtime time.Time + + // This is to verify that FOPEN_KEEP_CACHE is working as expected. + readCount uint32 } func (n *gitilesNode) Deletable() bool { @@ -155,10 +159,18 @@ if err != nil { return nil, fuse.ToStatus(err) } - return nodefs.NewLoopbackFile(f), fuse.OK + + return &nodefs.WithFlags{ + File: nodefs.NewLoopbackFile(f), + FuseFlags: fuse.FOPEN_KEEP_CACHE, + }, fuse.OK } func (n *gitilesNode) Read(file nodefs.File, dest []byte, off int64, context *fuse.Context) (fuse.ReadResult, fuse.Status) { + if off == 0 { + atomic.AddUint32(&n.readCount, 1) + } + if n.root.handleLessIO { return n.handleLessRead(file, dest, off, context) }
diff --git a/fs/gitilesfs_test.go b/fs/gitilesfs_test.go index ffb0961..f29c5e9 100644 --- a/fs/gitilesfs_test.go +++ b/fs/gitilesfs_test.go
@@ -27,6 +27,7 @@ "regexp" "strings" "sync" + "sync/atomic" "syscall" "testing" "time" @@ -428,6 +429,49 @@ } } +func TestGitilesFSCachedRead(t *testing.T) { + fix, err := newTestFixture() + if err != nil { + t.Fatal("newTestFixture", err) + } + defer fix.cleanup() + + repoService := fix.service.NewRepoService("platform/build/kati") + treeResp, err := repoService.GetTree("ce34badf691d36e8048b63f89d1a86ee5fa4325c", "", true) + if err != nil { + t.Fatal("Tree:", err) + } + + options := GitilesOptions{ + Revision: "ce34badf691d36e8048b63f89d1a86ee5fa4325c", + } + + fs := NewGitilesRoot(fix.cache, treeResp, repoService, options) + if err := fix.mount(fs); err != nil { + t.Fatal("mount", err) + } + + for i := 0; i < 2; i++ { + if _, err := ioutil.ReadFile(filepath.Join(fix.mntDir, "AUTHORS")); err != nil { + t.Fatalf("ReadFile %d: %v", i, err) + } + } + + ch := fs.Inode().GetChild("AUTHORS") + if ch == nil { + t.Fatalf("node for AUTHORS not found") + } + + giNode, ok := ch.Node().(*gitilesNode) + if !ok { + t.Fatalf("got node type %T, want *gitilesNode", ch.Node()) + } + + if c := atomic.LoadUint32(&giNode.readCount); c != 1 { + t.Errorf("inode was read %d times, want 1.", c) + } +} + func TestGitilesFSTimeStamps(t *testing.T) { fix, err := newTestFixture() if err != nil {