mirror of
https://github.com/rclone/rclone.git
synced 2024-11-22 08:46:24 +08:00
vfs: Added cache cleaner for directories to reduce memory usage
This empties the directory cache after twice the directory cache period to release memory. Signed-off-by: Anagh Kumar Baranwal <6824881+darthShadow@users.noreply.github.com>
This commit is contained in:
parent
9a66563fc6
commit
52e25c43b9
46
vfs/dir.go
46
vfs/dir.go
|
@ -22,9 +22,10 @@ import (
|
||||||
|
|
||||||
// Dir represents a directory entry
|
// Dir represents a directory entry
|
||||||
type Dir struct {
|
type Dir struct {
|
||||||
vfs *VFS // read only
|
vfs *VFS // read only
|
||||||
inode uint64 // read only: inode number
|
inode uint64 // read only: inode number
|
||||||
f fs.Fs // read only
|
f fs.Fs // read only
|
||||||
|
cleanupTimer *time.Timer // read only: timer to call cacheCleanup
|
||||||
|
|
||||||
mu sync.RWMutex // protects the following
|
mu sync.RWMutex // protects the following
|
||||||
parent *Dir // parent, nil for root
|
parent *Dir // parent, nil for root
|
||||||
|
@ -52,7 +53,7 @@ const (
|
||||||
)
|
)
|
||||||
|
|
||||||
func newDir(vfs *VFS, f fs.Fs, parent *Dir, fsDir fs.Directory) *Dir {
|
func newDir(vfs *VFS, f fs.Fs, parent *Dir, fsDir fs.Directory) *Dir {
|
||||||
return &Dir{
|
d := &Dir{
|
||||||
vfs: vfs,
|
vfs: vfs,
|
||||||
f: f,
|
f: f,
|
||||||
parent: parent,
|
parent: parent,
|
||||||
|
@ -62,6 +63,25 @@ func newDir(vfs *VFS, f fs.Fs, parent *Dir, fsDir fs.Directory) *Dir {
|
||||||
inode: newInode(),
|
inode: newInode(),
|
||||||
items: make(map[string]Node),
|
items: make(map[string]Node),
|
||||||
}
|
}
|
||||||
|
d.cleanupTimer = time.AfterFunc(vfs.Opt.DirCacheTime*2, d.cacheCleanup)
|
||||||
|
return d
|
||||||
|
}
|
||||||
|
|
||||||
|
func (d *Dir) cacheCleanup() {
|
||||||
|
defer func() {
|
||||||
|
// We should never panic here
|
||||||
|
_ = recover()
|
||||||
|
}()
|
||||||
|
|
||||||
|
when := time.Now()
|
||||||
|
|
||||||
|
d.mu.Lock()
|
||||||
|
_, stale := d._age(when)
|
||||||
|
d.mu.Unlock()
|
||||||
|
|
||||||
|
if stale {
|
||||||
|
d.ForgetAll()
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// String converts it to printable
|
// String converts it to printable
|
||||||
|
@ -182,8 +202,8 @@ func (d *Dir) Node() Node {
|
||||||
// so could not be forgotten. Children which didn't have virtual entries and
|
// so could not be forgotten. Children which didn't have virtual entries and
|
||||||
// children with virtual entries will be forgotten even if true is returned.
|
// children with virtual entries will be forgotten even if true is returned.
|
||||||
func (d *Dir) ForgetAll() (hasVirtual bool) {
|
func (d *Dir) ForgetAll() (hasVirtual bool) {
|
||||||
d.mu.Lock()
|
d.mu.RLock()
|
||||||
defer d.mu.Unlock()
|
|
||||||
fs.Debugf(d.path, "forgetting directory cache")
|
fs.Debugf(d.path, "forgetting directory cache")
|
||||||
for _, node := range d.items {
|
for _, node := range d.items {
|
||||||
if dir, ok := node.(*Dir); ok {
|
if dir, ok := node.(*Dir); ok {
|
||||||
|
@ -192,19 +212,29 @@ func (d *Dir) ForgetAll() (hasVirtual bool) {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
d.mu.RUnlock()
|
||||||
|
|
||||||
|
d.mu.Lock()
|
||||||
|
defer d.mu.Unlock()
|
||||||
|
|
||||||
// Purge any unnecessary virtual entries
|
// Purge any unnecessary virtual entries
|
||||||
d._purgeVirtual()
|
d._purgeVirtual()
|
||||||
|
|
||||||
d.read = time.Time{}
|
d.read = time.Time{}
|
||||||
|
|
||||||
// Check if this dir has virtual entries
|
// Check if this dir has virtual entries
|
||||||
if len(d.virtual) != 0 {
|
if len(d.virtual) != 0 {
|
||||||
hasVirtual = true
|
hasVirtual = true
|
||||||
}
|
}
|
||||||
|
|
||||||
// Don't clear directory entries if there are virtual entries in this
|
// Don't clear directory entries if there are virtual entries in this
|
||||||
// directory or any children
|
// directory or any children
|
||||||
if !hasVirtual {
|
if !hasVirtual {
|
||||||
d.items = make(map[string]Node)
|
d.items = make(map[string]Node)
|
||||||
|
d.cleanupTimer.Stop()
|
||||||
}
|
}
|
||||||
|
|
||||||
return hasVirtual
|
return hasVirtual
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -475,6 +505,8 @@ func (d *Dir) _readDir() error {
|
||||||
}
|
}
|
||||||
|
|
||||||
d.read = when
|
d.read = when
|
||||||
|
d.cleanupTimer.Reset(d.vfs.Opt.DirCacheTime * 2)
|
||||||
|
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -654,6 +686,7 @@ func (d *Dir) _readDirFromEntries(entries fs.DirEntries, dirTree dirtree.DirTree
|
||||||
dir.read = time.Time{}
|
dir.read = time.Time{}
|
||||||
} else {
|
} else {
|
||||||
dir.read = when
|
dir.read = when
|
||||||
|
dir.cleanupTimer.Reset(d.vfs.Opt.DirCacheTime * 2)
|
||||||
}
|
}
|
||||||
dir.mu.Unlock()
|
dir.mu.Unlock()
|
||||||
if err != nil {
|
if err != nil {
|
||||||
|
@ -691,6 +724,7 @@ func (d *Dir) readDirTree() error {
|
||||||
}
|
}
|
||||||
fs.Debugf(d.path, "Reading directory tree done in %s", time.Since(when))
|
fs.Debugf(d.path, "Reading directory tree done in %s", time.Since(when))
|
||||||
d.read = when
|
d.read = when
|
||||||
|
d.cleanupTimer.Reset(d.vfs.Opt.DirCacheTime * 2)
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
Loading…
Reference in New Issue
Block a user