inode_to_path.go 6.2 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282
  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, bool) {
  108. if path == "/" {
  109. return 1, true
  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, found
  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.Lock()
  137. defer i.Unlock()
  138. inode, found := i.path2inode[fullpath]
  139. if !found {
  140. // https://github.com/seaweedfs/seaweedfs/issues/4968
  141. // glog.Fatalf("MarkChildrenCached not found inode %v", fullpath)
  142. glog.Warningf("MarkChildrenCached not found inode %v", fullpath)
  143. return
  144. }
  145. path, found := i.inode2path[inode]
  146. path.isChildrenCached = true
  147. }
  148. func (i *InodeToPath) IsChildrenCached(fullpath util.FullPath) bool {
  149. i.RLock()
  150. defer i.RUnlock()
  151. inode, found := i.path2inode[fullpath]
  152. if !found {
  153. return false
  154. }
  155. path, found := i.inode2path[inode]
  156. if found {
  157. return path.isChildrenCached
  158. }
  159. return false
  160. }
  161. func (i *InodeToPath) HasInode(inode uint64) bool {
  162. if inode == 1 {
  163. return true
  164. }
  165. i.RLock()
  166. defer i.RUnlock()
  167. _, found := i.inode2path[inode]
  168. return found
  169. }
  170. func (i *InodeToPath) AddPath(inode uint64, path util.FullPath) {
  171. i.Lock()
  172. defer i.Unlock()
  173. i.path2inode[path] = inode
  174. ie, found := i.inode2path[inode]
  175. if found {
  176. ie.paths = append(ie.paths, path)
  177. ie.nlookup++
  178. } else {
  179. i.inode2path[inode] = &InodeEntry{
  180. paths: []util.FullPath{path},
  181. nlookup: 1,
  182. isDirectory: false,
  183. isChildrenCached: false,
  184. }
  185. }
  186. }
  187. func (i *InodeToPath) RemovePath(path util.FullPath) {
  188. i.Lock()
  189. defer i.Unlock()
  190. inode, found := i.path2inode[path]
  191. if found {
  192. delete(i.path2inode, path)
  193. i.removePathFromInode2Path(inode, path)
  194. }
  195. }
  196. func (i *InodeToPath) removePathFromInode2Path(inode uint64, path util.FullPath) {
  197. ie, found := i.inode2path[inode]
  198. if !found {
  199. return
  200. }
  201. if !ie.removeOnePath(path) {
  202. return
  203. }
  204. if len(ie.paths) == 0 {
  205. delete(i.inode2path, inode)
  206. }
  207. }
  208. func (i *InodeToPath) MovePath(sourcePath, targetPath util.FullPath) (sourceInode, targetInode uint64) {
  209. i.Lock()
  210. defer i.Unlock()
  211. sourceInode, sourceFound := i.path2inode[sourcePath]
  212. targetInode, targetFound := i.path2inode[targetPath]
  213. if targetFound {
  214. i.removePathFromInode2Path(targetInode, targetPath)
  215. delete(i.path2inode, targetPath)
  216. }
  217. if sourceFound {
  218. delete(i.path2inode, sourcePath)
  219. i.path2inode[targetPath] = sourceInode
  220. } else {
  221. // it is possible some source folder items has not been visited before
  222. // so no need to worry about their source inodes
  223. return
  224. }
  225. if entry, entryFound := i.inode2path[sourceInode]; entryFound {
  226. for i, p := range entry.paths {
  227. if p == sourcePath {
  228. entry.paths[i] = targetPath
  229. }
  230. }
  231. entry.isChildrenCached = false
  232. if !targetFound {
  233. entry.nlookup++
  234. }
  235. } else {
  236. glog.Errorf("MovePath %s to %s: sourceInode %d not found", sourcePath, targetPath, sourceInode)
  237. }
  238. return
  239. }
  240. func (i *InodeToPath) Forget(inode, nlookup uint64, onForgetDir func(dir util.FullPath)) {
  241. i.Lock()
  242. path, found := i.inode2path[inode]
  243. if found {
  244. path.nlookup -= nlookup
  245. if path.nlookup <= 0 {
  246. for _, p := range path.paths {
  247. delete(i.path2inode, p)
  248. }
  249. delete(i.inode2path, inode)
  250. }
  251. }
  252. i.Unlock()
  253. if found {
  254. if path.isDirectory && path.nlookup <= 0 && onForgetDir != nil {
  255. path.isChildrenCached = false
  256. for _, p := range path.paths {
  257. onForgetDir(p)
  258. }
  259. }
  260. }
  261. }