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.
This commit is contained in:
Nick Craig-Wood 2019-10-17 14:41:55 +01:00
parent 2bbfcc74e9
commit 76f5e273d2
2 changed files with 30 additions and 15 deletions

View File

@ -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)
}

View File

@ -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")