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.

151 lines
4.1 KiB

3 years ago
  1. package shell
  2. import (
  3. "flag"
  4. "fmt"
  5. "github.com/chrislusf/seaweedfs/weed/filer"
  6. "github.com/chrislusf/seaweedfs/weed/pb/filer_pb"
  7. "github.com/chrislusf/seaweedfs/weed/util"
  8. "io"
  9. "strings"
  10. )
  11. func init() {
  12. Commands = append(Commands, &commandRemoteCache{})
  13. }
  14. type commandRemoteCache struct {
  15. }
  16. func (c *commandRemoteCache) Name() string {
  17. return "remote.cache"
  18. }
  19. func (c *commandRemoteCache) Help() string {
  20. return `cache the file content for mounted directories or files
  21. # assume a remote storage is configured to name "cloud1"
  22. remote.configure -name=cloud1 -type=s3 -access_key=xxx -secret_key=yyy
  23. # mount and pull one bucket
  24. remote.mount -dir=xxx -remote=cloud1/bucket
  25. # after mount, run one of these command to cache the content of the files
  26. remote.cache -dir=xxx
  27. remote.cache -dir=xxx/some/sub/dir
  28. `
  29. }
  30. func (c *commandRemoteCache) Do(args []string, commandEnv *CommandEnv, writer io.Writer) (err error) {
  31. remoteMountCommand := flag.NewFlagSet(c.Name(), flag.ContinueOnError)
  32. dir := remoteMountCommand.String("dir", "", "a directory in filer")
  33. if err = remoteMountCommand.Parse(args); err != nil {
  34. return nil
  35. }
  36. mappings, listErr := filer.ReadMountMappings(commandEnv.option.GrpcDialOption, commandEnv.option.FilerAddress)
  37. if listErr != nil {
  38. return listErr
  39. }
  40. if *dir == "" {
  41. jsonPrintln(writer, mappings)
  42. fmt.Fprintln(writer, "need to specify '-dir' option")
  43. return nil
  44. }
  45. var localMountedDir string
  46. var remoteStorageMountedLocation *filer_pb.RemoteStorageLocation
  47. for k, loc := range mappings.Mappings {
  48. if strings.HasPrefix(*dir, k) {
  49. localMountedDir, remoteStorageMountedLocation = k, loc
  50. }
  51. }
  52. if localMountedDir == "" {
  53. jsonPrintln(writer, mappings)
  54. fmt.Fprintf(writer, "%s is not mounted\n", *dir)
  55. return nil
  56. }
  57. // find remote storage configuration
  58. remoteStorageConf, err := filer.ReadRemoteStorageConf(commandEnv.option.GrpcDialOption, commandEnv.option.FilerAddress, remoteStorageMountedLocation.Name)
  59. if err != nil {
  60. return err
  61. }
  62. // pull content from remote
  63. if err = c.cacheContentData(commandEnv, writer, util.FullPath(localMountedDir), remoteStorageMountedLocation, util.FullPath(*dir), remoteStorageConf); err != nil {
  64. return fmt.Errorf("cache content data: %v", err)
  65. }
  66. return nil
  67. }
  68. func recursivelyTraverseDirectory(filerClient filer_pb.FilerClient, dirPath util.FullPath, visitEntry func(dir util.FullPath, entry *filer_pb.Entry) bool) (err error) {
  69. err = filer_pb.ReadDirAllEntries(filerClient, dirPath, "", func(entry *filer_pb.Entry, isLast bool) error {
  70. if entry.IsDirectory {
  71. if !visitEntry(dirPath, entry) {
  72. return nil
  73. }
  74. subDir := dirPath.Child(entry.Name)
  75. if err := recursivelyTraverseDirectory(filerClient, subDir, visitEntry); err != nil {
  76. return err
  77. }
  78. } else {
  79. if !visitEntry(dirPath, entry) {
  80. return nil
  81. }
  82. }
  83. return nil
  84. })
  85. return
  86. }
  87. func shouldCacheToLocal(entry *filer_pb.Entry) bool {
  88. if entry.IsDirectory {
  89. return false
  90. }
  91. if entry.RemoteEntry == nil {
  92. return false
  93. }
  94. if entry.RemoteEntry.LocalMtime == 0 && entry.RemoteEntry.RemoteSize > 0 {
  95. return true
  96. }
  97. return false
  98. }
  99. func mayHaveCachedToLocal(entry *filer_pb.Entry) bool {
  100. if entry.IsDirectory {
  101. return false
  102. }
  103. if entry.RemoteEntry == nil {
  104. return false
  105. }
  106. if entry.RemoteEntry.LocalMtime > 0 && len(entry.Chunks) > 0 {
  107. return true
  108. }
  109. return false
  110. }
  111. func (c *commandRemoteCache) cacheContentData(commandEnv *CommandEnv, writer io.Writer, localMountedDir util.FullPath, remoteMountedLocation *filer_pb.RemoteStorageLocation, dirToCache util.FullPath, remoteConf *filer_pb.RemoteConf) error {
  112. return recursivelyTraverseDirectory(commandEnv, dirToCache, func(dir util.FullPath, entry *filer_pb.Entry) bool {
  113. if !shouldCacheToLocal(entry) {
  114. return true // true means recursive traversal should continue
  115. }
  116. println(dir, entry.Name)
  117. remoteLocation := filer.MapFullPathToRemoteStorageLocation(localMountedDir, remoteMountedLocation, dir.Child(entry.Name))
  118. if err := filer.DownloadToLocal(commandEnv, remoteConf, remoteLocation, dir, entry); err != nil {
  119. fmt.Fprintf(writer, "DownloadToLocal %+v: %v\n", remoteLocation, err)
  120. return false
  121. }
  122. return true
  123. })
  124. }