From 76f5e273d2a7fe6f6d6f4ee6eb99ee794048bcae Mon Sep 17 00:00:00 2001 From: Nick Craig-Wood Date: Thu, 17 Oct 2019 14:41:55 +0100 Subject: [PATCH] vfs: stop change notify polling clearing so much of the directory cache Before this change, change notify polls would clear the directory cache recursively. So uploading a file to the root would clear the entire directory cache. After this change we just invalidate the directory cache of the parent directory of the item and if the item was a directory we invalidate it too. --- vfs/dir.go | 43 +++++++++++++++++++++++++++++-------------- vfs/vfs.go | 2 +- 2 files changed, 30 insertions(+), 15 deletions(-) diff --git a/vfs/dir.go b/vfs/dir.go index 9f96b02da..97190a1a2 100644 --- a/vfs/dir.go +++ b/vfs/dir.go @@ -13,6 +13,7 @@ import ( "github.com/rclone/rclone/fs" "github.com/rclone/rclone/fs/dirtree" "github.com/rclone/rclone/fs/list" + "github.com/rclone/rclone/fs/log" "github.com/rclone/rclone/fs/operations" "github.com/rclone/rclone/fs/walk" ) @@ -119,6 +120,32 @@ func (d *Dir) ForgetAll() { d.forgetDirPath("") } +// invalidateDir invalidates the directory cache for absPath relative to this dir +func (d *Dir) invalidateDir(absPath string) { + node := d.vfs.root.cachedNode(absPath) + if dir, ok := node.(*Dir); ok { + dir.mu.Lock() + if !dir.read.IsZero() { + fs.Debugf(dir.path, "invalidating directory cache") + dir.read = time.Time{} + } + dir.mu.Unlock() + } +} + +// changeNotify invalidates the directory cache for the relativePath +// passed in. +// +// if entryType is a directory it invalidates the parent of the directory too. +func (d *Dir) changeNotify(relativePath string, entryType fs.EntryType) { + defer log.Trace(d.path, "relativePath=%q, type=%v", relativePath, entryType)("") + absPath := path.Join(d.path, relativePath) + d.invalidateDir(findParent(absPath)) + if entryType == fs.EntryDirectory { + d.invalidateDir(absPath) + } +} + // ForgetPath clears the cache for itself and all subdirectories if // they match the given path. The path is specified relative from the // directory it is called from. The cache of the parent directory is @@ -126,22 +153,10 @@ func (d *Dir) ForgetAll() { // It is not possible to traverse the directory tree upwards, i.e. // you cannot clear the cache for the Dir's ancestors or siblings. func (d *Dir) ForgetPath(relativePath string, entryType fs.EntryType) { + defer log.Trace(d.path, "relativePath=%q, type=%v", relativePath, entryType)("") if absPath := path.Join(d.path, relativePath); absPath != "" { - parent := path.Dir(absPath) - if parent == "." || parent == "/" { - parent = "" - } - parentNode := d.vfs.root.cachedNode(parent) - if dir, ok := parentNode.(*Dir); ok { - dir.mu.Lock() - if !dir.read.IsZero() { - fs.Debugf(dir.path, "invalidating directory cache") - dir.read = time.Time{} - } - dir.mu.Unlock() - } + d.invalidateDir(findParent(absPath)) } - if entryType == fs.EntryDirectory { d.forgetDirPath(relativePath) } diff --git a/vfs/vfs.go b/vfs/vfs.go index 889d1c949..1bab8810a 100644 --- a/vfs/vfs.go +++ b/vfs/vfs.go @@ -232,7 +232,7 @@ func New(f fs.Fs, opt *Options) *VFS { // Start polling function if do := vfs.f.Features().ChangeNotify; do != nil { vfs.pollChan = make(chan time.Duration) - do(context.TODO(), vfs.root.ForgetPath, vfs.pollChan) + do(context.TODO(), vfs.root.changeNotify, vfs.pollChan) vfs.pollChan <- vfs.Opt.PollInterval } else { fs.Infof(f, "poll-interval is not supported by this remote")