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.

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