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.

243 lines
5.3 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 := len(ie.paths) - 2; x > idx; x-- {
  35. ie.paths[x-1] = ie.paths[x]
  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) RemovePath(path util.FullPath) {
  152. i.Lock()
  153. defer i.Unlock()
  154. inode, found := i.path2inode[path]
  155. if found {
  156. delete(i.path2inode, path)
  157. i.removePathFromInode2Path(inode, path)
  158. }
  159. }
  160. func (i *InodeToPath) removePathFromInode2Path(inode uint64, path util.FullPath) {
  161. ie, found := i.inode2path[inode]
  162. if !found {
  163. return
  164. }
  165. if !ie.removeOnePath(path) {
  166. return
  167. }
  168. if len(ie.paths) == 0 {
  169. delete(i.inode2path, inode)
  170. }
  171. }
  172. func (i *InodeToPath) MovePath(sourcePath, targetPath util.FullPath) (sourceInode, targetInode uint64) {
  173. i.Lock()
  174. defer i.Unlock()
  175. sourceInode, sourceFound := i.path2inode[sourcePath]
  176. targetInode, targetFound := i.path2inode[targetPath]
  177. if targetFound {
  178. i.removePathFromInode2Path(targetInode, targetPath)
  179. delete(i.path2inode, targetPath)
  180. }
  181. if sourceFound {
  182. delete(i.path2inode, sourcePath)
  183. i.path2inode[targetPath] = sourceInode
  184. } else {
  185. // it is possible some source folder items has not been visited before
  186. // so no need to worry about their source inodes
  187. return
  188. }
  189. if entry, entryFound := i.inode2path[sourceInode]; entryFound {
  190. for i, p := range entry.paths {
  191. if p == sourcePath {
  192. entry.paths[i] = targetPath
  193. }
  194. }
  195. entry.isChildrenCached = false
  196. if !targetFound {
  197. entry.nlookup++
  198. }
  199. } else {
  200. glog.Errorf("MovePath %s to %s: sourceInode %d not found", sourcePath, targetPath, sourceInode)
  201. }
  202. return
  203. }
  204. func (i *InodeToPath) Forget(inode, nlookup uint64, onForgetDir func(dir util.FullPath)) {
  205. i.Lock()
  206. path, found := i.inode2path[inode]
  207. if found {
  208. path.nlookup -= nlookup
  209. if path.nlookup <= 0 {
  210. for _, p := range path.paths {
  211. delete(i.path2inode, p)
  212. }
  213. delete(i.inode2path, inode)
  214. }
  215. }
  216. i.Unlock()
  217. if found {
  218. if path.isDirectory && path.nlookup <= 0 && onForgetDir != nil {
  219. path.isChildrenCached = false
  220. for _, p := range path.paths {
  221. onForgetDir(p)
  222. }
  223. }
  224. }
  225. }