123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279 |
- package mount
- import (
- "github.com/hanwen/go-fuse/v2/fuse"
- "github.com/seaweedfs/seaweedfs/weed/glog"
- "github.com/seaweedfs/seaweedfs/weed/util"
- "sync"
- "time"
- )
- type InodeToPath struct {
- sync.RWMutex
- nextInodeId uint64
- inode2path map[uint64]*InodeEntry
- path2inode map[util.FullPath]uint64
- }
- type InodeEntry struct {
- paths []util.FullPath
- nlookup uint64
- isDirectory bool
- isChildrenCached bool
- }
- func (ie *InodeEntry) removeOnePath(p util.FullPath) bool {
- if len(ie.paths) == 0 {
- return false
- }
- idx := -1
- for i, x := range ie.paths {
- if x == p {
- idx = i
- break
- }
- }
- if idx < 0 {
- return false
- }
- for x := idx; x < len(ie.paths)-1; x++ {
- ie.paths[x] = ie.paths[x+1]
- }
- ie.paths = ie.paths[0 : len(ie.paths)-1]
- ie.nlookup--
- return true
- }
- func NewInodeToPath(root util.FullPath) *InodeToPath {
- t := &InodeToPath{
- inode2path: make(map[uint64]*InodeEntry),
- path2inode: make(map[util.FullPath]uint64),
- }
- t.inode2path[1] = &InodeEntry{[]util.FullPath{root}, 1, true, false}
- t.path2inode[root] = 1
- return t
- }
- // EnsurePath make sure the full path is tracked, used by symlink.
- func (i *InodeToPath) EnsurePath(path util.FullPath, isDirectory bool) bool {
- for {
- dir, _ := path.DirAndName()
- if dir == "/" {
- return true
- }
- if i.EnsurePath(util.FullPath(dir), true) {
- i.Lookup(path, time.Now().Unix(), isDirectory, false, 0, false)
- return true
- }
- }
- return false
- }
- func (i *InodeToPath) Lookup(path util.FullPath, unixTime int64, isDirectory bool, isHardlink bool, possibleInode uint64, isLookup bool) uint64 {
- i.Lock()
- defer i.Unlock()
- inode, found := i.path2inode[path]
- if !found {
- if possibleInode == 0 {
- inode = path.AsInode(unixTime)
- } else {
- inode = possibleInode
- }
- if !isHardlink {
- for _, found := i.inode2path[inode]; found; inode++ {
- _, found = i.inode2path[inode+1]
- }
- }
- }
- i.path2inode[path] = inode
- if _, found := i.inode2path[inode]; found {
- if isLookup {
- i.inode2path[inode].nlookup++
- }
- } else {
- if !isLookup {
- i.inode2path[inode] = &InodeEntry{[]util.FullPath{path}, 0, isDirectory, false}
- } else {
- i.inode2path[inode] = &InodeEntry{[]util.FullPath{path}, 1, isDirectory, false}
- }
- }
- return inode
- }
- func (i *InodeToPath) AllocateInode(path util.FullPath, unixTime int64) uint64 {
- if path == "/" {
- return 1
- }
- i.Lock()
- defer i.Unlock()
- inode := path.AsInode(unixTime)
- for _, found := i.inode2path[inode]; found; inode++ {
- _, found = i.inode2path[inode]
- }
- return inode
- }
- func (i *InodeToPath) GetInode(path util.FullPath) uint64 {
- if path == "/" {
- return 1
- }
- i.Lock()
- defer i.Unlock()
- inode, found := i.path2inode[path]
- if !found {
- // glog.Fatalf("GetInode unknown inode for %s", path)
- // this could be the parent for mount point
- }
- return inode
- }
- func (i *InodeToPath) GetPath(inode uint64) (util.FullPath, fuse.Status) {
- i.RLock()
- defer i.RUnlock()
- path, found := i.inode2path[inode]
- if !found || len(path.paths) == 0 {
- return "", fuse.ENOENT
- }
- return path.paths[0], fuse.OK
- }
- func (i *InodeToPath) HasPath(path util.FullPath) bool {
- i.RLock()
- defer i.RUnlock()
- _, found := i.path2inode[path]
- return found
- }
- func (i *InodeToPath) MarkChildrenCached(fullpath util.FullPath) {
- i.RLock()
- defer i.RUnlock()
- inode, found := i.path2inode[fullpath]
- if !found {
- glog.Fatalf("MarkChildrenCached not found inode %v", fullpath)
- }
- path, found := i.inode2path[inode]
- path.isChildrenCached = true
- }
- func (i *InodeToPath) IsChildrenCached(fullpath util.FullPath) bool {
- i.RLock()
- defer i.RUnlock()
- inode, found := i.path2inode[fullpath]
- if !found {
- return false
- }
- path, found := i.inode2path[inode]
- if found {
- return path.isChildrenCached
- }
- return false
- }
- func (i *InodeToPath) HasInode(inode uint64) bool {
- if inode == 1 {
- return true
- }
- i.RLock()
- defer i.RUnlock()
- _, found := i.inode2path[inode]
- return found
- }
- func (i *InodeToPath) AddPath(inode uint64, path util.FullPath) {
- i.Lock()
- defer i.Unlock()
- i.path2inode[path] = inode
- ie, found := i.inode2path[inode]
- if found {
- ie.paths = append(ie.paths, path)
- ie.nlookup++
- } else {
- i.inode2path[inode] = &InodeEntry{
- paths: []util.FullPath{path},
- nlookup: 1,
- isDirectory: false,
- isChildrenCached: false,
- }
- }
- }
- func (i *InodeToPath) RemovePath(path util.FullPath) {
- i.Lock()
- defer i.Unlock()
- inode, found := i.path2inode[path]
- if found {
- delete(i.path2inode, path)
- i.removePathFromInode2Path(inode, path)
- }
- }
- func (i *InodeToPath) removePathFromInode2Path(inode uint64, path util.FullPath) {
- ie, found := i.inode2path[inode]
- if !found {
- return
- }
- if !ie.removeOnePath(path) {
- return
- }
- if len(ie.paths) == 0 {
- delete(i.inode2path, inode)
- }
- }
- func (i *InodeToPath) MovePath(sourcePath, targetPath util.FullPath) (sourceInode, targetInode uint64) {
- i.Lock()
- defer i.Unlock()
- sourceInode, sourceFound := i.path2inode[sourcePath]
- targetInode, targetFound := i.path2inode[targetPath]
- if targetFound {
- i.removePathFromInode2Path(targetInode, targetPath)
- delete(i.path2inode, targetPath)
- }
- if sourceFound {
- delete(i.path2inode, sourcePath)
- i.path2inode[targetPath] = sourceInode
- } else {
- // it is possible some source folder items has not been visited before
- // so no need to worry about their source inodes
- return
- }
- if entry, entryFound := i.inode2path[sourceInode]; entryFound {
- for i, p := range entry.paths {
- if p == sourcePath {
- entry.paths[i] = targetPath
- }
- }
- entry.isChildrenCached = false
- if !targetFound {
- entry.nlookup++
- }
- } else {
- glog.Errorf("MovePath %s to %s: sourceInode %d not found", sourcePath, targetPath, sourceInode)
- }
- return
- }
- func (i *InodeToPath) Forget(inode, nlookup uint64, onForgetDir func(dir util.FullPath)) {
- i.Lock()
- path, found := i.inode2path[inode]
- if found {
- path.nlookup -= nlookup
- if path.nlookup <= 0 {
- for _, p := range path.paths {
- delete(i.path2inode, p)
- }
- delete(i.inode2path, inode)
- }
- }
- i.Unlock()
- if found {
- if path.isDirectory && path.nlookup <= 0 && onForgetDir != nil {
- path.isChildrenCached = false
- for _, p := range path.paths {
- onForgetDir(p)
- }
- }
- }
- }
|