diff --git a/cmd/mount/dir.go b/cmd/mount/dir.go index 0ec53e888..e6787c2af 100644 --- a/cmd/mount/dir.go +++ b/cmd/mount/dir.go @@ -30,7 +30,7 @@ type Dir struct { f fs.Fs path string mu sync.RWMutex // protects the following - read bool + read time.Time // time directory entry last read items map[string]*DirEntry } @@ -66,8 +66,15 @@ func (d *Dir) delObject(leaf string) { func (d *Dir) readDir() error { d.mu.Lock() defer d.mu.Unlock() - if d.read { - return nil + when := time.Now() + if d.read.IsZero() { + fs.Debug(d.path, "Reading directory") + } else { + age := when.Sub(d.read) + if age < dirCacheTime { + return nil + } + fs.Debug(d.path, "Re-reading directory (%v old)", age) } objs, dirs, err := fs.NewLister().SetLevel(1).Start(d.f, d.path).GetAll() if err == fs.ErrorDirNotFound { @@ -76,6 +83,13 @@ func (d *Dir) readDir() error { } else if err != nil { return err } + // NB when we re-read a directory after its cache has expired + // we drop the old files which should lead to correct + // behaviour but may not be very efficient. + + // Keep a note of the previous contents of the directory + oldItems := d.items + // Cache the items by name d.items = make(map[string]*DirEntry, len(objs)+len(dirs)) for _, obj := range objs { @@ -87,12 +101,19 @@ func (d *Dir) readDir() error { } for _, dir := range dirs { name := path.Base(dir.Remote()) + // Use old dir value if it exists + if oldItem, ok := oldItems[name]; ok { + if _, ok := oldItem.o.(*fs.Dir); ok { + d.items[name] = oldItem + continue + } + } d.items[name] = &DirEntry{ o: dir, node: nil, } } - d.read = true + d.read = when return nil } diff --git a/cmd/mount/mount.go b/cmd/mount/mount.go index 737c68d42..f2b885c3a 100644 --- a/cmd/mount/mount.go +++ b/cmd/mount/mount.go @@ -7,6 +7,7 @@ package mount import ( "log" "os" + "time" "bazil.org/fuse" "github.com/ncw/rclone/cmd" @@ -18,9 +19,10 @@ import ( // Globals var ( - noModTime = false - debugFUSE = false - noSeek = false + noModTime = false + debugFUSE = false + noSeek = false + dirCacheTime = 5 * 60 * time.Second // mount options readOnly = false allowNonEmpty = false @@ -45,6 +47,7 @@ func init() { mountCmd.Flags().BoolVarP(&noModTime, "no-modtime", "", noModTime, "Don't read the modification time (can speed things up).") mountCmd.Flags().BoolVarP(&debugFUSE, "debug-fuse", "", debugFUSE, "Debug the FUSE internals - needs -v.") mountCmd.Flags().BoolVarP(&noSeek, "no-seek", "", noSeek, "Don't allow seeking in files.") + mountCmd.Flags().DurationVarP(&dirCacheTime, "dir-cache-time", "", dirCacheTime, "Time to cache directory entries for.") // mount options mountCmd.Flags().BoolVarP(&readOnly, "read-only", "", readOnly, "Mount read-only.") mountCmd.Flags().BoolVarP(&allowNonEmpty, "allow-non-empty", "", allowNonEmpty, "Allow mounting over a non-empty directory.")