vfs: fix very high load caused by slow directory listings

In this commit (released in v1.52.0)

6ca7198f mount: fix disappearing cwd problem

SetSys was introduced to cache node lookups.

Unfortunately taking the vfs.(*Dir) lock in SetSys causes any FUSE
operations on a directory to pile up behind slow directory listings.

In some situations this leads to very high load.

This commit fixes it by using atomic operations to read and write the
Sys value make it independent of the lock.

See: https://forum.rclone.org/t/high-cpu-load-with-rclone-mount/17604
See: #4104
This commit is contained in:
Nick Craig-Wood 2020-07-08 10:27:26 +01:00
parent 59770a4953
commit 2adc057d95
2 changed files with 7 additions and 14 deletions

View file

@ -7,6 +7,7 @@ import (
"sort"
"strings"
"sync"
"sync/atomic"
"time"
"github.com/pkg/errors"
@ -33,7 +34,7 @@ type Dir struct {
read time.Time // time directory entry last read
items map[string]Node // directory entries - can be empty but not nil
virtual map[string]vState // virtual directory entries - may be nil
sys interface{} // user defined info to be attached here
sys atomic.Value // user defined info to be attached here
}
//go:generate stringer -type=vState
@ -105,16 +106,12 @@ func (d *Dir) Path() (name string) {
// Sys returns underlying data source (can be nil) - satisfies Node interface
func (d *Dir) Sys() interface{} {
d.mu.RLock()
defer d.mu.RUnlock()
return d.sys
return d.sys.Load()
}
// SetSys sets the underlying data source (can be nil) - satisfies Node interface
func (d *Dir) SetSys(x interface{}) {
d.mu.Lock()
d.sys = x
d.mu.Unlock()
d.sys.Store(x)
}
// Inode returns the inode number - satisfies Node interface

View file

@ -48,7 +48,7 @@ type File struct {
pendingModTime time.Time // will be applied once o becomes available, i.e. after file was written
pendingRenameFun func(ctx context.Context) error // will be run/renamed after all writers close
appendMode bool // file was opened with O_APPEND
sys interface{} // user defined info to be attached here
sys atomic.Value // user defined info to be attached here
muRW sync.Mutex // synchronize RWFileHandle.openPending(), RWFileHandle.close() and File.Remove
}
@ -122,16 +122,12 @@ func (f *File) Path() string {
// Sys returns underlying data source (can be nil) - satisfies Node interface
func (f *File) Sys() interface{} {
f.mu.RLock()
defer f.mu.RUnlock()
return f.sys
return f.sys.Load()
}
// SetSys sets the underlying data source (can be nil) - satisfies Node interface
func (f *File) SetSys(x interface{}) {
f.mu.Lock()
f.sys = x
f.mu.Unlock()
f.sys.Store(x)
}
// Inode returns the inode number - satisfies Node interface