2020-08-10 04:56:09 +00:00
|
|
|
package filesys
|
|
|
|
|
|
|
|
import (
|
|
|
|
"sync"
|
|
|
|
|
|
|
|
"github.com/seaweedfs/fuse/fs"
|
2020-08-16 00:01:42 +00:00
|
|
|
|
|
|
|
"github.com/chrislusf/seaweedfs/weed/util"
|
2020-08-10 04:56:09 +00:00
|
|
|
)
|
|
|
|
|
|
|
|
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
|
|
|
|
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
|
2021-03-10 07:08:38 +00:00
|
|
|
entry := f.getEntry()
|
|
|
|
if entry != nil {
|
2021-03-12 08:36:29 +00:00
|
|
|
entry.FullPath = newPath
|
2020-08-10 04:56:09 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
parent.disconnectChild(target)
|
|
|
|
|
|
|
|
target.deleteSelf()
|
|
|
|
|
2020-08-16 00:01:42 +00:00
|
|
|
src.name = target.name
|
2020-08-10 04:56:09 +00:00
|
|
|
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 {
|
2020-08-16 00:01:42 +00:00
|
|
|
if parent.node != nil {
|
|
|
|
dir.parent = parent.node.(*Dir)
|
|
|
|
}
|
2020-08-10 04:56:09 +00:00
|
|
|
}
|
|
|
|
if f, ok := n.node.(*File); ok {
|
2020-08-16 00:01:42 +00:00
|
|
|
if parent.node != nil {
|
|
|
|
f.dir = parent.node.(*Dir)
|
|
|
|
}
|
2020-08-10 04:56:09 +00:00
|
|
|
}
|
|
|
|
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
|
|
|
|
|
|
|
|
}
|