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.

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