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.

292 lines
6.6 KiB

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