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.

176 lines
5.3 KiB

3 years ago
3 years ago
3 years ago
3 years ago
3 years ago
3 years ago
3 years ago
3 years ago
3 years ago
3 years ago
3 years ago
3 years ago
3 years ago
3 years ago
3 years ago
3 years ago
3 years ago
3 years ago
3 years ago
3 years ago
3 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. "context"
  4. "fmt"
  5. "github.com/chrislusf/seaweedfs/weed/filer"
  6. "github.com/chrislusf/seaweedfs/weed/mount/meta_cache"
  7. "github.com/chrislusf/seaweedfs/weed/pb"
  8. "github.com/chrislusf/seaweedfs/weed/pb/filer_pb"
  9. "github.com/chrislusf/seaweedfs/weed/storage/types"
  10. "github.com/chrislusf/seaweedfs/weed/util"
  11. "github.com/chrislusf/seaweedfs/weed/util/chunk_cache"
  12. "github.com/chrislusf/seaweedfs/weed/util/grace"
  13. "github.com/chrislusf/seaweedfs/weed/wdclient"
  14. "github.com/hanwen/go-fuse/v2/fuse"
  15. "google.golang.org/grpc"
  16. "math/rand"
  17. "os"
  18. "path"
  19. "time"
  20. "github.com/hanwen/go-fuse/v2/fs"
  21. )
  22. type Option struct {
  23. MountDirectory string
  24. FilerAddresses []pb.ServerAddress
  25. filerIndex int
  26. GrpcDialOption grpc.DialOption
  27. FilerMountRootPath string
  28. Collection string
  29. Replication string
  30. TtlSec int32
  31. DiskType types.DiskType
  32. ChunkSizeLimit int64
  33. ConcurrentWriters int
  34. CacheDir string
  35. CacheSizeMB int64
  36. DataCenter string
  37. Umask os.FileMode
  38. MountUid uint32
  39. MountGid uint32
  40. MountMode os.FileMode
  41. MountCtime time.Time
  42. MountMtime time.Time
  43. MountParentInode uint64
  44. VolumeServerAccess string // how to access volume servers
  45. Cipher bool // whether encrypt data on volume server
  46. UidGidMapper *meta_cache.UidGidMapper
  47. uniqueCacheDir string
  48. }
  49. type WFS struct {
  50. // follow https://github.com/hanwen/go-fuse/blob/master/fuse/api.go
  51. fuse.RawFileSystem
  52. fs.Inode
  53. option *Option
  54. metaCache *meta_cache.MetaCache
  55. stats statsCache
  56. chunkCache *chunk_cache.TieredChunkCache
  57. signature int32
  58. concurrentWriters *util.LimitedConcurrentExecutor
  59. inodeToPath *InodeToPath
  60. fhmap *FileHandleToInode
  61. dhmap *DirectoryHandleToInode
  62. }
  63. func NewSeaweedFileSystem(option *Option) *WFS {
  64. wfs := &WFS{
  65. RawFileSystem: fuse.NewDefaultRawFileSystem(),
  66. option: option,
  67. signature: util.RandomInt32(),
  68. inodeToPath: NewInodeToPath(),
  69. fhmap: NewFileHandleToInode(),
  70. dhmap: NewDirectoryHandleToInode(),
  71. }
  72. wfs.option.filerIndex = rand.Intn(len(option.FilerAddresses))
  73. wfs.option.setupUniqueCacheDirectory()
  74. if option.CacheSizeMB > 0 {
  75. wfs.chunkCache = chunk_cache.NewTieredChunkCache(256, option.getUniqueCacheDir(), option.CacheSizeMB, 1024*1024)
  76. }
  77. wfs.metaCache = meta_cache.NewMetaCache(path.Join(option.getUniqueCacheDir(), "meta"), option.UidGidMapper, func(path util.FullPath) {
  78. wfs.inodeToPath.MarkChildrenCached(path)
  79. }, func(path util.FullPath) bool {
  80. return wfs.inodeToPath.IsChildrenCached(path)
  81. }, func(filePath util.FullPath, entry *filer_pb.Entry) {
  82. })
  83. grace.OnInterrupt(func() {
  84. wfs.metaCache.Shutdown()
  85. os.RemoveAll(option.getUniqueCacheDir())
  86. })
  87. if wfs.option.ConcurrentWriters > 0 {
  88. wfs.concurrentWriters = util.NewLimitedConcurrentExecutor(wfs.option.ConcurrentWriters)
  89. }
  90. return wfs
  91. }
  92. func (wfs *WFS) StartBackgroundTasks() {
  93. startTime := time.Now()
  94. go meta_cache.SubscribeMetaEvents(wfs.metaCache, wfs.signature, wfs, wfs.option.FilerMountRootPath, startTime.UnixNano())
  95. }
  96. func (wfs *WFS) String() string {
  97. return "seaweedfs"
  98. }
  99. func (wfs *WFS) maybeReadEntry(inode uint64) (path util.FullPath, fh *FileHandle, entry *filer_pb.Entry, status fuse.Status) {
  100. path, status = wfs.inodeToPath.GetPath(inode)
  101. if status != fuse.OK {
  102. return
  103. }
  104. var found bool
  105. if fh, found = wfs.fhmap.FindFileHandle(inode); found {
  106. return path, fh, fh.entry, fuse.OK
  107. }
  108. entry, status = wfs.maybeLoadEntry(path)
  109. return
  110. }
  111. func (wfs *WFS) maybeLoadEntry(fullpath util.FullPath) (*filer_pb.Entry, fuse.Status) {
  112. // glog.V(3).Infof("read entry cache miss %s", fullpath)
  113. dir, name := fullpath.DirAndName()
  114. // return a valid entry for the mount root
  115. if string(fullpath) == wfs.option.FilerMountRootPath {
  116. return &filer_pb.Entry{
  117. Name: name,
  118. IsDirectory: true,
  119. Attributes: &filer_pb.FuseAttributes{
  120. Mtime: wfs.option.MountMtime.Unix(),
  121. FileMode: uint32(wfs.option.MountMode),
  122. Uid: wfs.option.MountUid,
  123. Gid: wfs.option.MountGid,
  124. Crtime: wfs.option.MountCtime.Unix(),
  125. },
  126. }, fuse.OK
  127. }
  128. // read from async meta cache
  129. meta_cache.EnsureVisited(wfs.metaCache, wfs, util.FullPath(dir), nil)
  130. cachedEntry, cacheErr := wfs.metaCache.FindEntry(context.Background(), fullpath)
  131. if cacheErr == filer_pb.ErrNotFound {
  132. return nil, fuse.ENOENT
  133. }
  134. return cachedEntry.ToProtoEntry(), fuse.OK
  135. }
  136. func (wfs *WFS) LookupFn() wdclient.LookupFileIdFunctionType {
  137. if wfs.option.VolumeServerAccess == "filerProxy" {
  138. return func(fileId string) (targetUrls []string, err error) {
  139. return []string{"http://" + wfs.getCurrentFiler().ToHttpAddress() + "/?proxyChunkId=" + fileId}, nil
  140. }
  141. }
  142. return filer.LookupFn(wfs)
  143. }
  144. func (wfs *WFS) getCurrentFiler() pb.ServerAddress {
  145. return wfs.option.FilerAddresses[wfs.option.filerIndex]
  146. }
  147. func (option *Option) setupUniqueCacheDirectory() {
  148. cacheUniqueId := util.Md5String([]byte(option.MountDirectory + string(option.FilerAddresses[0]) + option.FilerMountRootPath + util.Version()))[0:8]
  149. option.uniqueCacheDir = path.Join(option.CacheDir, cacheUniqueId)
  150. os.MkdirAll(option.uniqueCacheDir, os.FileMode(0777)&^option.Umask)
  151. }
  152. func (option *Option) getUniqueCacheDir() string {
  153. return option.uniqueCacheDir
  154. }