mirror of
https://github.com/rclone/rclone.git
synced 2024-11-25 09:41:44 +08:00
vfs: make dir.ForgetAll and friends not forget virtual entries
Before this change dir.ForgetAll and vfs/forget would forget about virtual directory entries. This change preserves them.
This commit is contained in:
parent
06a12f5e27
commit
5db15cb157
55
vfs/dir.go
55
vfs/dir.go
|
@ -127,33 +127,48 @@ func (d *Dir) Node() Node {
|
||||||
return d
|
return d
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// ForgetAll forgets directory entries for this directory and any children.
|
||||||
|
//
|
||||||
|
// It does not invalidate or clear the cache of the parent directory.
|
||||||
|
//
|
||||||
|
// It returns true if the directory or any of its children had virtual entries
|
||||||
|
// 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.
|
||||||
|
func (d *Dir) ForgetAll() (hasVirtual bool) {
|
||||||
|
d.mu.Lock()
|
||||||
|
defer d.mu.Unlock()
|
||||||
|
fs.Debugf(d.path, "forgetting directory cache")
|
||||||
|
for _, node := range d.items {
|
||||||
|
if dir, ok := node.(*Dir); ok {
|
||||||
|
if dir.ForgetAll() {
|
||||||
|
hasVirtual = true
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
d.read = time.Time{}
|
||||||
|
// Check if this dir has virtual entries
|
||||||
|
if len(d.virtual) != 0 {
|
||||||
|
hasVirtual = true
|
||||||
|
}
|
||||||
|
// Don't clear directory entries if there are virtual entries in this
|
||||||
|
// directory or any children
|
||||||
|
if !hasVirtual {
|
||||||
|
d.items = make(map[string]Node)
|
||||||
|
}
|
||||||
|
return hasVirtual
|
||||||
|
}
|
||||||
|
|
||||||
// forgetDirPath clears the cache for itself and all subdirectories if
|
// forgetDirPath clears the cache for itself and all subdirectories if
|
||||||
// they match the given path. The path is specified relative from the
|
// they match the given path. The path is specified relative from the
|
||||||
// directory it is called from.
|
// directory it is called from.
|
||||||
//
|
//
|
||||||
// It does not invalidate or clear the cache of the parent directory.
|
// It does not invalidate or clear the cache of the parent directory.
|
||||||
func (d *Dir) forgetDirPath(relativePath string) {
|
func (d *Dir) forgetDirPath(relativePath string) {
|
||||||
if dir := d.cachedDir(relativePath); dir != nil {
|
dir := d.cachedDir(relativePath)
|
||||||
dir.walk(func(dir *Dir) {
|
if dir == nil {
|
||||||
// this is called with the mutex held
|
return
|
||||||
fs.Debugf(dir.path, "forgetting directory cache")
|
|
||||||
dir.read = time.Time{}
|
|
||||||
// Don't clear directory entries if there are virtual
|
|
||||||
// items in there.
|
|
||||||
if len(dir.virtual) == 0 {
|
|
||||||
dir.items = make(map[string]Node)
|
|
||||||
dir.virtual = nil
|
|
||||||
}
|
}
|
||||||
})
|
dir.ForgetAll()
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// ForgetAll ensures the directory and all its children are purged
|
|
||||||
// from the cache.
|
|
||||||
//
|
|
||||||
// It does not invalidate or clear the cache of the parent directory.
|
|
||||||
func (d *Dir) ForgetAll() {
|
|
||||||
d.forgetDirPath("")
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// invalidateDir invalidates the directory cache for absPath relative to the root
|
// invalidateDir invalidates the directory cache for absPath relative to the root
|
||||||
|
|
|
@ -269,21 +269,17 @@ func TestDirReadDirAll(t *testing.T) {
|
||||||
|
|
||||||
node, err = vfs.Stat("")
|
node, err = vfs.Stat("")
|
||||||
require.NoError(t, err)
|
require.NoError(t, err)
|
||||||
dir = node.(*Dir)
|
root := node.(*Dir)
|
||||||
|
|
||||||
checkListing(t, dir, []string{"dir,0,true"})
|
checkListing(t, root, []string{"dir,0,true"})
|
||||||
|
|
||||||
node, err = vfs.Stat("dir/subdir")
|
node, err = vfs.Stat("dir/subdir")
|
||||||
require.NoError(t, err)
|
require.NoError(t, err)
|
||||||
dir = node.(*Dir)
|
subdir := node.(*Dir)
|
||||||
|
|
||||||
checkListing(t, dir, []string{"file3,16,false"})
|
checkListing(t, subdir, []string{"file3,16,false"})
|
||||||
|
|
||||||
t.Run("Virtual", func(t *testing.T) {
|
t.Run("Virtual", func(t *testing.T) {
|
||||||
node, err := vfs.Stat("dir")
|
|
||||||
require.NoError(t, err)
|
|
||||||
dir := node.(*Dir)
|
|
||||||
|
|
||||||
// Add some virtual entries and check what happens
|
// Add some virtual entries and check what happens
|
||||||
dir.AddVirtual("virtualFile", 17, false)
|
dir.AddVirtual("virtualFile", 17, false)
|
||||||
dir.AddVirtual("virtualDir", 0, true)
|
dir.AddVirtual("virtualDir", 0, true)
|
||||||
|
@ -298,6 +294,11 @@ func TestDirReadDirAll(t *testing.T) {
|
||||||
|
|
||||||
checkListing(t, dir, []string{"file1,14,false", "virtualDir,0,true", "virtualFile,17,false"})
|
checkListing(t, dir, []string{"file1,14,false", "virtualDir,0,true", "virtualFile,17,false"})
|
||||||
|
|
||||||
|
// Check that forgetting the root doesn't invalidate the virtual entries
|
||||||
|
root.ForgetAll()
|
||||||
|
|
||||||
|
checkListing(t, dir, []string{"file1,14,false", "virtualDir,0,true", "virtualFile,17,false"})
|
||||||
|
|
||||||
// Now action the deletes and uploads
|
// Now action the deletes and uploads
|
||||||
_ = r.WriteObject(context.Background(), "dir/virtualFile", "virtualFile contents", t1)
|
_ = r.WriteObject(context.Background(), "dir/virtualFile", "virtualFile contents", t1)
|
||||||
_ = r.WriteObject(context.Background(), "dir/virtualDir/testFile", "testFile contents", t1)
|
_ = r.WriteObject(context.Background(), "dir/virtualDir/testFile", "testFile contents", t1)
|
||||||
|
|
Loading…
Reference in New Issue
Block a user