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.

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