Browse Source
remove fsnode cache
remove fsnode cache
fix https://github.com/chrislusf/seaweedfs/issues/1400pull/1402/head
Chris Lu
4 years ago
6 changed files with 9 additions and 323 deletions
-
25weed/filesys/dir.go
-
1weed/filesys/dir_rename.go
-
1weed/filesys/file.go
-
207weed/filesys/fscache.go
-
96weed/filesys/fscache_test.go
-
2weed/filesys/wfs.go
@ -1,207 +0,0 @@ |
|||||
package filesys |
|
||||
|
|
||||
import ( |
|
||||
"sync" |
|
||||
|
|
||||
"github.com/chrislusf/seaweedfs/weed/util" |
|
||||
"github.com/seaweedfs/fuse/fs" |
|
||||
) |
|
||||
|
|
||||
type FsCache struct { |
|
||||
root *FsNode |
|
||||
sync.RWMutex |
|
||||
} |
|
||||
type FsNode struct { |
|
||||
parent *FsNode |
|
||||
node fs.Node |
|
||||
name string |
|
||||
childrenLock sync.RWMutex |
|
||||
children map[string]*FsNode |
|
||||
} |
|
||||
|
|
||||
func newFsCache(root fs.Node) *FsCache { |
|
||||
return &FsCache{ |
|
||||
root: &FsNode{ |
|
||||
node: root, |
|
||||
}, |
|
||||
} |
|
||||
} |
|
||||
|
|
||||
func (c *FsCache) GetFsNode(path util.FullPath) fs.Node { |
|
||||
|
|
||||
c.RLock() |
|
||||
defer c.RUnlock() |
|
||||
|
|
||||
return c.doGetFsNode(path) |
|
||||
} |
|
||||
|
|
||||
func (c *FsCache) doGetFsNode(path util.FullPath) fs.Node { |
|
||||
t := c.root |
|
||||
for _, p := range path.Split() { |
|
||||
t = t.findChild(p) |
|
||||
if t == nil { |
|
||||
return nil |
|
||||
} |
|
||||
} |
|
||||
return t.node |
|
||||
} |
|
||||
|
|
||||
func (c *FsCache) SetFsNode(path util.FullPath, node fs.Node) { |
|
||||
|
|
||||
c.Lock() |
|
||||
defer c.Unlock() |
|
||||
|
|
||||
c.doSetFsNode(path, node) |
|
||||
} |
|
||||
|
|
||||
func (c *FsCache) doSetFsNode(path util.FullPath, node fs.Node) { |
|
||||
t := c.root |
|
||||
for _, p := range path.Split() { |
|
||||
t = t.ensureChild(p) |
|
||||
} |
|
||||
t.node = node |
|
||||
} |
|
||||
|
|
||||
func (c *FsCache) EnsureFsNode(path util.FullPath, genNodeFn func() fs.Node) fs.Node { |
|
||||
|
|
||||
c.Lock() |
|
||||
defer c.Unlock() |
|
||||
|
|
||||
t := c.doGetFsNode(path) |
|
||||
if t != nil { |
|
||||
return t |
|
||||
} |
|
||||
t = genNodeFn() |
|
||||
c.doSetFsNode(path, t) |
|
||||
return t |
|
||||
} |
|
||||
|
|
||||
func (c *FsCache) DeleteFsNode(path util.FullPath) { |
|
||||
|
|
||||
c.Lock() |
|
||||
defer c.Unlock() |
|
||||
|
|
||||
t := c.root |
|
||||
for _, p := range path.Split() { |
|
||||
t = t.findChild(p) |
|
||||
if t == nil { |
|
||||
return |
|
||||
} |
|
||||
} |
|
||||
if t.parent != nil { |
|
||||
t.parent.disconnectChild(t) |
|
||||
} |
|
||||
t.deleteSelf() |
|
||||
} |
|
||||
|
|
||||
// oldPath and newPath are full path including the new name
|
|
||||
func (c *FsCache) Move(oldPath util.FullPath, newPath util.FullPath) *FsNode { |
|
||||
|
|
||||
c.Lock() |
|
||||
defer c.Unlock() |
|
||||
|
|
||||
// find old node
|
|
||||
src := c.root |
|
||||
for _, p := range oldPath.Split() { |
|
||||
src = src.findChild(p) |
|
||||
if src == nil { |
|
||||
return src |
|
||||
} |
|
||||
} |
|
||||
if src.parent != nil { |
|
||||
src.parent.disconnectChild(src) |
|
||||
} |
|
||||
|
|
||||
// find new node
|
|
||||
target := c.root |
|
||||
for _, p := range newPath.Split() { |
|
||||
target = target.ensureChild(p) |
|
||||
} |
|
||||
parent := target.parent |
|
||||
src.name = target.name |
|
||||
if dir, ok := src.node.(*Dir); ok { |
|
||||
dir.name = target.name // target is not Dir, but a shortcut
|
|
||||
} |
|
||||
if f, ok := src.node.(*File); ok { |
|
||||
f.Name = target.name |
|
||||
if f.entry != nil { |
|
||||
f.entry.Name = f.Name |
|
||||
} |
|
||||
} |
|
||||
parent.disconnectChild(target) |
|
||||
|
|
||||
target.deleteSelf() |
|
||||
|
|
||||
src.connectToParent(parent) |
|
||||
|
|
||||
return src |
|
||||
} |
|
||||
|
|
||||
func (n *FsNode) connectToParent(parent *FsNode) { |
|
||||
n.parent = parent |
|
||||
oldNode := parent.findChild(n.name) |
|
||||
if oldNode != nil { |
|
||||
oldNode.deleteSelf() |
|
||||
} |
|
||||
if dir, ok := n.node.(*Dir); ok { |
|
||||
dir.parent = parent.node.(*Dir) |
|
||||
} |
|
||||
if f, ok := n.node.(*File); ok { |
|
||||
f.dir = parent.node.(*Dir) |
|
||||
} |
|
||||
n.childrenLock.Lock() |
|
||||
parent.children[n.name] = n |
|
||||
n.childrenLock.Unlock() |
|
||||
} |
|
||||
|
|
||||
func (n *FsNode) findChild(name string) *FsNode { |
|
||||
n.childrenLock.RLock() |
|
||||
defer n.childrenLock.RUnlock() |
|
||||
|
|
||||
child, found := n.children[name] |
|
||||
if found { |
|
||||
return child |
|
||||
} |
|
||||
return nil |
|
||||
} |
|
||||
|
|
||||
func (n *FsNode) ensureChild(name string) *FsNode { |
|
||||
n.childrenLock.Lock() |
|
||||
defer n.childrenLock.Unlock() |
|
||||
|
|
||||
if n.children == nil { |
|
||||
n.children = make(map[string]*FsNode) |
|
||||
} |
|
||||
child, found := n.children[name] |
|
||||
if found { |
|
||||
return child |
|
||||
} |
|
||||
t := &FsNode{ |
|
||||
parent: n, |
|
||||
node: nil, |
|
||||
name: name, |
|
||||
children: nil, |
|
||||
} |
|
||||
n.children[name] = t |
|
||||
return t |
|
||||
} |
|
||||
|
|
||||
func (n *FsNode) disconnectChild(child *FsNode) { |
|
||||
n.childrenLock.Lock() |
|
||||
delete(n.children, child.name) |
|
||||
n.childrenLock.Unlock() |
|
||||
child.parent = nil |
|
||||
} |
|
||||
|
|
||||
func (n *FsNode) deleteSelf() { |
|
||||
n.childrenLock.Lock() |
|
||||
for _, child := range n.children { |
|
||||
child.deleteSelf() |
|
||||
} |
|
||||
n.children = nil |
|
||||
n.childrenLock.Unlock() |
|
||||
|
|
||||
n.node = nil |
|
||||
n.parent = nil |
|
||||
|
|
||||
} |
|
@ -1,96 +0,0 @@ |
|||||
package filesys |
|
||||
|
|
||||
import ( |
|
||||
"testing" |
|
||||
|
|
||||
"github.com/chrislusf/seaweedfs/weed/util" |
|
||||
) |
|
||||
|
|
||||
func TestPathSplit(t *testing.T) { |
|
||||
parts := util.FullPath("/").Split() |
|
||||
if len(parts) != 0 { |
|
||||
t.Errorf("expecting an empty list, but getting %d", len(parts)) |
|
||||
} |
|
||||
|
|
||||
parts = util.FullPath("/readme.md").Split() |
|
||||
if len(parts) != 1 { |
|
||||
t.Errorf("expecting an empty list, but getting %d", len(parts)) |
|
||||
} |
|
||||
|
|
||||
} |
|
||||
|
|
||||
func TestFsCache(t *testing.T) { |
|
||||
|
|
||||
cache := newFsCache(nil) |
|
||||
|
|
||||
x := cache.GetFsNode(util.FullPath("/y/x")) |
|
||||
if x != nil { |
|
||||
t.Errorf("wrong node!") |
|
||||
} |
|
||||
|
|
||||
p := util.FullPath("/a/b/c") |
|
||||
cache.SetFsNode(p, &File{Name: "cc"}) |
|
||||
tNode := cache.GetFsNode(p) |
|
||||
tFile := tNode.(*File) |
|
||||
if tFile.Name != "cc" { |
|
||||
t.Errorf("expecting a FsNode") |
|
||||
} |
|
||||
|
|
||||
cache.SetFsNode(util.FullPath("/a/b/d"), &File{Name: "dd"}) |
|
||||
cache.SetFsNode(util.FullPath("/a/b/e"), &File{Name: "ee"}) |
|
||||
cache.SetFsNode(util.FullPath("/a/b/f"), &File{Name: "ff"}) |
|
||||
cache.SetFsNode(util.FullPath("/z"), &File{Name: "zz"}) |
|
||||
cache.SetFsNode(util.FullPath("/a"), &File{Name: "aa"}) |
|
||||
|
|
||||
b := cache.GetFsNode(util.FullPath("/a/b")) |
|
||||
if b != nil { |
|
||||
t.Errorf("unexpected node!") |
|
||||
} |
|
||||
|
|
||||
a := cache.GetFsNode(util.FullPath("/a")) |
|
||||
if a == nil { |
|
||||
t.Errorf("missing node!") |
|
||||
} |
|
||||
|
|
||||
cache.DeleteFsNode(util.FullPath("/a")) |
|
||||
if b != nil { |
|
||||
t.Errorf("unexpected node!") |
|
||||
} |
|
||||
|
|
||||
a = cache.GetFsNode(util.FullPath("/a")) |
|
||||
if a != nil { |
|
||||
t.Errorf("wrong DeleteFsNode!") |
|
||||
} |
|
||||
|
|
||||
z := cache.GetFsNode(util.FullPath("/z")) |
|
||||
if z == nil { |
|
||||
t.Errorf("missing node!") |
|
||||
} |
|
||||
|
|
||||
y := cache.GetFsNode(util.FullPath("/x/y")) |
|
||||
if y != nil { |
|
||||
t.Errorf("wrong node!") |
|
||||
} |
|
||||
|
|
||||
} |
|
||||
|
|
||||
func TestFsCacheMove(t *testing.T) { |
|
||||
|
|
||||
cache := newFsCache(nil) |
|
||||
|
|
||||
cache.SetFsNode(util.FullPath("/a/b/d"), &File{Name: "dd"}) |
|
||||
cache.SetFsNode(util.FullPath("/a/b/e"), &File{Name: "ee"}) |
|
||||
cache.SetFsNode(util.FullPath("/z"), &File{Name: "zz"}) |
|
||||
cache.SetFsNode(util.FullPath("/a"), &File{Name: "aa"}) |
|
||||
|
|
||||
cache.Move(util.FullPath("/a/b"), util.FullPath("/z/x")) |
|
||||
|
|
||||
d := cache.GetFsNode(util.FullPath("/z/x/d")) |
|
||||
if d == nil { |
|
||||
t.Errorf("unexpected nil node!") |
|
||||
} |
|
||||
if d.(*File).Name != "dd" { |
|
||||
t.Errorf("unexpected non dd node!") |
|
||||
} |
|
||||
|
|
||||
} |
|
Write
Preview
Loading…
Cancel
Save
Reference in new issue