inode_to_path.go 6.1 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279
  1. package mount
  2. import (
  3. "github.com/hanwen/go-fuse/v2/fuse"
  4. "github.com/seaweedfs/seaweedfs/weed/glog"
  5. "github.com/seaweedfs/seaweedfs/weed/util"
  6. "sync"
  7. "time"
  8. )
  9. type InodeToPath struct {
  10. sync.RWMutex
  11. nextInodeId uint64
  12. inode2path map[uint64]*InodeEntry
  13. path2inode map[util.FullPath]uint64
  14. }
  15. type InodeEntry struct {
  16. paths []util.FullPath
  17. nlookup uint64
  18. isDirectory bool
  19. isChildrenCached bool
  20. }
  21. func (ie *InodeEntry) removeOnePath(p util.FullPath) bool {
  22. if len(ie.paths) == 0 {
  23. return false
  24. }
  25. idx := -1
  26. for i, x := range ie.paths {
  27. if x == p {
  28. idx = i
  29. break
  30. }
  31. }
  32. if idx < 0 {
  33. return false
  34. }
  35. for x := idx; x < len(ie.paths)-1; x++ {
  36. ie.paths[x] = ie.paths[x+1]
  37. }
  38. ie.paths = ie.paths[0 : len(ie.paths)-1]
  39. ie.nlookup--
  40. return true
  41. }
  42. func NewInodeToPath(root util.FullPath) *InodeToPath {
  43. t := &InodeToPath{
  44. inode2path: make(map[uint64]*InodeEntry),
  45. path2inode: make(map[util.FullPath]uint64),
  46. }
  47. t.inode2path[1] = &InodeEntry{[]util.FullPath{root}, 1, true, false}
  48. t.path2inode[root] = 1
  49. return t
  50. }
  51. // EnsurePath make sure the full path is tracked, used by symlink.
  52. func (i *InodeToPath) EnsurePath(path util.FullPath, isDirectory bool) bool {
  53. for {
  54. dir, _ := path.DirAndName()
  55. if dir == "/" {
  56. return true
  57. }
  58. if i.EnsurePath(util.FullPath(dir), true) {
  59. i.Lookup(path, time.Now().Unix(), isDirectory, false, 0, false)
  60. return true
  61. }
  62. }
  63. return false
  64. }
  65. func (i *InodeToPath) Lookup(path util.FullPath, unixTime int64, isDirectory bool, isHardlink bool, possibleInode uint64, isLookup bool) uint64 {
  66. i.Lock()
  67. defer i.Unlock()
  68. inode, found := i.path2inode[path]
  69. if !found {
  70. if possibleInode == 0 {
  71. inode = path.AsInode(unixTime)
  72. } else {
  73. inode = possibleInode
  74. }
  75. if !isHardlink {
  76. for _, found := i.inode2path[inode]; found; inode++ {
  77. _, found = i.inode2path[inode+1]
  78. }
  79. }
  80. }
  81. i.path2inode[path] = inode
  82. if _, found := i.inode2path[inode]; found {
  83. if isLookup {
  84. i.inode2path[inode].nlookup++
  85. }
  86. } else {
  87. if !isLookup {
  88. i.inode2path[inode] = &InodeEntry{[]util.FullPath{path}, 0, isDirectory, false}
  89. } else {
  90. i.inode2path[inode] = &InodeEntry{[]util.FullPath{path}, 1, isDirectory, false}
  91. }
  92. }
  93. return inode
  94. }
  95. func (i *InodeToPath) AllocateInode(path util.FullPath, unixTime int64) uint64 {
  96. if path == "/" {
  97. return 1
  98. }
  99. i.Lock()
  100. defer i.Unlock()
  101. inode := path.AsInode(unixTime)
  102. for _, found := i.inode2path[inode]; found; inode++ {
  103. _, found = i.inode2path[inode]
  104. }
  105. return inode
  106. }
  107. func (i *InodeToPath) GetInode(path util.FullPath) uint64 {
  108. if path == "/" {
  109. return 1
  110. }
  111. i.Lock()
  112. defer i.Unlock()
  113. inode, found := i.path2inode[path]
  114. if !found {
  115. // glog.Fatalf("GetInode unknown inode for %s", path)
  116. // this could be the parent for mount point
  117. }
  118. return inode
  119. }
  120. func (i *InodeToPath) GetPath(inode uint64) (util.FullPath, fuse.Status) {
  121. i.RLock()
  122. defer i.RUnlock()
  123. path, found := i.inode2path[inode]
  124. if !found || len(path.paths) == 0 {
  125. return "", fuse.ENOENT
  126. }
  127. return path.paths[0], fuse.OK
  128. }
  129. func (i *InodeToPath) HasPath(path util.FullPath) bool {
  130. i.RLock()
  131. defer i.RUnlock()
  132. _, found := i.path2inode[path]
  133. return found
  134. }
  135. func (i *InodeToPath) MarkChildrenCached(fullpath util.FullPath) {
  136. i.RLock()
  137. defer i.RUnlock()
  138. inode, found := i.path2inode[fullpath]
  139. if !found {
  140. glog.Fatalf("MarkChildrenCached not found inode %v", fullpath)
  141. }
  142. path, found := i.inode2path[inode]
  143. path.isChildrenCached = true
  144. }
  145. func (i *InodeToPath) IsChildrenCached(fullpath util.FullPath) bool {
  146. i.RLock()
  147. defer i.RUnlock()
  148. inode, found := i.path2inode[fullpath]
  149. if !found {
  150. return false
  151. }
  152. path, found := i.inode2path[inode]
  153. if found {
  154. return path.isChildrenCached
  155. }
  156. return false
  157. }
  158. func (i *InodeToPath) HasInode(inode uint64) bool {
  159. if inode == 1 {
  160. return true
  161. }
  162. i.RLock()
  163. defer i.RUnlock()
  164. _, found := i.inode2path[inode]
  165. return found
  166. }
  167. func (i *InodeToPath) AddPath(inode uint64, path util.FullPath) {
  168. i.Lock()
  169. defer i.Unlock()
  170. i.path2inode[path] = inode
  171. ie, found := i.inode2path[inode]
  172. if found {
  173. ie.paths = append(ie.paths, path)
  174. ie.nlookup++
  175. } else {
  176. i.inode2path[inode] = &InodeEntry{
  177. paths: []util.FullPath{path},
  178. nlookup: 1,
  179. isDirectory: false,
  180. isChildrenCached: false,
  181. }
  182. }
  183. }
  184. func (i *InodeToPath) RemovePath(path util.FullPath) {
  185. i.Lock()
  186. defer i.Unlock()
  187. inode, found := i.path2inode[path]
  188. if found {
  189. delete(i.path2inode, path)
  190. i.removePathFromInode2Path(inode, path)
  191. }
  192. }
  193. func (i *InodeToPath) removePathFromInode2Path(inode uint64, path util.FullPath) {
  194. ie, found := i.inode2path[inode]
  195. if !found {
  196. return
  197. }
  198. if !ie.removeOnePath(path) {
  199. return
  200. }
  201. if len(ie.paths) == 0 {
  202. delete(i.inode2path, inode)
  203. }
  204. }
  205. func (i *InodeToPath) MovePath(sourcePath, targetPath util.FullPath) (sourceInode, targetInode uint64) {
  206. i.Lock()
  207. defer i.Unlock()
  208. sourceInode, sourceFound := i.path2inode[sourcePath]
  209. targetInode, targetFound := i.path2inode[targetPath]
  210. if targetFound {
  211. i.removePathFromInode2Path(targetInode, targetPath)
  212. delete(i.path2inode, targetPath)
  213. }
  214. if sourceFound {
  215. delete(i.path2inode, sourcePath)
  216. i.path2inode[targetPath] = sourceInode
  217. } else {
  218. // it is possible some source folder items has not been visited before
  219. // so no need to worry about their source inodes
  220. return
  221. }
  222. if entry, entryFound := i.inode2path[sourceInode]; entryFound {
  223. for i, p := range entry.paths {
  224. if p == sourcePath {
  225. entry.paths[i] = targetPath
  226. }
  227. }
  228. entry.isChildrenCached = false
  229. if !targetFound {
  230. entry.nlookup++
  231. }
  232. } else {
  233. glog.Errorf("MovePath %s to %s: sourceInode %d not found", sourcePath, targetPath, sourceInode)
  234. }
  235. return
  236. }
  237. func (i *InodeToPath) Forget(inode, nlookup uint64, onForgetDir func(dir util.FullPath)) {
  238. i.Lock()
  239. path, found := i.inode2path[inode]
  240. if found {
  241. path.nlookup -= nlookup
  242. if path.nlookup <= 0 {
  243. for _, p := range path.paths {
  244. delete(i.path2inode, p)
  245. }
  246. delete(i.inode2path, inode)
  247. }
  248. }
  249. i.Unlock()
  250. if found {
  251. if path.isDirectory && path.nlookup <= 0 && onForgetDir != nil {
  252. path.isChildrenCached = false
  253. for _, p := range path.paths {
  254. onForgetDir(p)
  255. }
  256. }
  257. }
  258. }