|
@@ -0,0 +1,207 @@
|
|
|
+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
|
|
|
+
|
|
|
+}
|