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 {