You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

278 lines
6.1 KiB

3 years ago
3 years ago
3 years ago
3 years ago
3 years ago
3 years ago
  1. package mount
  2. import (
  3. "github.com/chrislusf/seaweedfs/weed/glog"
  4. "github.com/chrislusf/seaweedfs/weed/util"
  5. "github.com/hanwen/go-fuse/v2/fuse"
  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. }
  61. }
  62. return false
  63. }
  64. func (i *InodeToPath) Lookup(path util.FullPath, unixTime int64, isDirectory bool, isHardlink bool, possibleInode uint64, isLookup bool) uint64 {
  65. i.Lock()
  66. defer i.Unlock()
  67. inode, found := i.path2inode[path]
  68. if !found {
  69. if possibleInode == 0 {
  70. inode = path.AsInode(unixTime)
  71. } else {
  72. inode = possibleInode
  73. }
  74. if !isHardlink {
  75. for _, found := i.inode2path[inode]; found; inode++ {
  76. _, found = i.inode2path[inode]
  77. }
  78. }
  79. }
  80. i.path2inode[path] = inode
  81. if _, found := i.inode2path[inode]; found {
  82. if isLookup {
  83. i.inode2path[inode].nlookup++
  84. }
  85. } else {
  86. if !isLookup {
  87. i.inode2path[inode] = &InodeEntry{[]util.FullPath{path}, 0, isDirectory, false}
  88. } else {
  89. i.inode2path[inode] = &InodeEntry{[]util.FullPath{path}, 1, isDirectory, false}
  90. }
  91. }
  92. return inode
  93. }
  94. func (i *InodeToPath) AllocateInode(path util.FullPath, unixTime int64) uint64 {
  95. if path == "/" {
  96. return 1
  97. }
  98. i.Lock()
  99. defer i.Unlock()
  100. inode := path.AsInode(unixTime)
  101. for _, found := i.inode2path[inode]; found; inode++ {
  102. _, found = i.inode2path[inode]
  103. }
  104. return inode
  105. }
  106. func (i *InodeToPath) GetInode(path util.FullPath) uint64 {
  107. if path == "/" {
  108. return 1
  109. }
  110. i.Lock()
  111. defer i.Unlock()
  112. inode, found := i.path2inode[path]
  113. if !found {
  114. // glog.Fatalf("GetInode unknown inode for %s", path)
  115. // this could be the parent for mount point
  116. }
  117. return inode
  118. }
  119. func (i *InodeToPath) GetPath(inode uint64) (util.FullPath, fuse.Status) {
  120. i.RLock()
  121. defer i.RUnlock()
  122. path, found := i.inode2path[inode]
  123. if !found || len(path.paths) == 0 {
  124. return "", fuse.ENOENT
  125. }
  126. return path.paths[0], fuse.OK
  127. }
  128. func (i *InodeToPath) HasPath(path util.FullPath) bool {
  129. i.RLock()
  130. defer i.RUnlock()
  131. _, found := i.path2inode[path]
  132. return found
  133. }
  134. func (i *InodeToPath) MarkChildrenCached(fullpath util.FullPath) {
  135. i.RLock()
  136. defer i.RUnlock()
  137. inode, found := i.path2inode[fullpath]
  138. if !found {
  139. glog.Fatalf("MarkChildrenCached not found inode %v", fullpath)
  140. }
  141. path, found := i.inode2path[inode]
  142. path.isChildrenCached = true
  143. }
  144. func (i *InodeToPath) IsChildrenCached(fullpath util.FullPath) bool {
  145. i.RLock()
  146. defer i.RUnlock()
  147. inode, found := i.path2inode[fullpath]
  148. if !found {
  149. return false
  150. }
  151. path, found := i.inode2path[inode]
  152. if found {
  153. return path.isChildrenCached
  154. }
  155. return false
  156. }
  157. func (i *InodeToPath) HasInode(inode uint64) bool {
  158. if inode == 1 {
  159. return true
  160. }
  161. i.RLock()
  162. defer i.RUnlock()
  163. _, found := i.inode2path[inode]
  164. return found
  165. }
  166. func (i *InodeToPath) AddPath(inode uint64, path util.FullPath) {
  167. i.Lock()
  168. defer i.Unlock()
  169. i.path2inode[path] = inode
  170. ie, found := i.inode2path[inode]
  171. if found {
  172. ie.paths = append(ie.paths, path)
  173. ie.nlookup++
  174. } else {
  175. i.inode2path[inode] = &InodeEntry{
  176. paths: []util.FullPath{path},
  177. nlookup: 1,
  178. isDirectory: false,
  179. isChildrenCached: false,
  180. }
  181. }
  182. }
  183. func (i *InodeToPath) RemovePath(path util.FullPath) {
  184. i.Lock()
  185. defer i.Unlock()
  186. inode, found := i.path2inode[path]
  187. if found {
  188. delete(i.path2inode, path)
  189. i.removePathFromInode2Path(inode, path)
  190. }
  191. }
  192. func (i *InodeToPath) removePathFromInode2Path(inode uint64, path util.FullPath) {
  193. ie, found := i.inode2path[inode]
  194. if !found {
  195. return
  196. }
  197. if !ie.removeOnePath(path) {
  198. return
  199. }
  200. if len(ie.paths) == 0 {
  201. delete(i.inode2path, inode)
  202. }
  203. }
  204. func (i *InodeToPath) MovePath(sourcePath, targetPath util.FullPath) (sourceInode, targetInode uint64) {
  205. i.Lock()
  206. defer i.Unlock()
  207. sourceInode, sourceFound := i.path2inode[sourcePath]
  208. targetInode, targetFound := i.path2inode[targetPath]
  209. if targetFound {
  210. i.removePathFromInode2Path(targetInode, targetPath)
  211. delete(i.path2inode, targetPath)
  212. }
  213. if sourceFound {
  214. delete(i.path2inode, sourcePath)
  215. i.path2inode[targetPath] = sourceInode
  216. } else {
  217. // it is possible some source folder items has not been visited before
  218. // so no need to worry about their source inodes
  219. return
  220. }
  221. if entry, entryFound := i.inode2path[sourceInode]; entryFound {
  222. for i, p := range entry.paths {
  223. if p == sourcePath {
  224. entry.paths[i] = targetPath
  225. }
  226. }
  227. entry.isChildrenCached = false
  228. if !targetFound {
  229. entry.nlookup++
  230. }
  231. } else {
  232. glog.Errorf("MovePath %s to %s: sourceInode %d not found", sourcePath, targetPath, sourceInode)
  233. }
  234. return
  235. }
  236. func (i *InodeToPath) Forget(inode, nlookup uint64, onForgetDir func(dir util.FullPath)) {
  237. i.Lock()
  238. path, found := i.inode2path[inode]
  239. if found {
  240. path.nlookup -= nlookup
  241. if path.nlookup <= 0 {
  242. for _, p := range path.paths {
  243. delete(i.path2inode, p)
  244. }
  245. delete(i.inode2path, inode)
  246. }
  247. }
  248. i.Unlock()
  249. if found {
  250. if path.isDirectory && path.nlookup <= 0 && onForgetDir != nil {
  251. path.isChildrenCached = false
  252. for _, p := range path.paths {
  253. onForgetDir(p)
  254. }
  255. }
  256. }
  257. }