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.

142 lines
3.5 KiB

  1. package shell
  2. import (
  3. "context"
  4. "fmt"
  5. "github.com/chrislusf/seaweedfs/weed/filer2"
  6. "github.com/chrislusf/seaweedfs/weed/pb/filer_pb"
  7. "github.com/chrislusf/seaweedfs/weed/util"
  8. "google.golang.org/grpc"
  9. "io"
  10. "net/url"
  11. "strconv"
  12. "strings"
  13. )
  14. func init() {
  15. commands = append(commands, &commandFsDu{})
  16. }
  17. type commandFsDu struct {
  18. }
  19. func (c *commandFsDu) Name() string {
  20. return "fs.du"
  21. }
  22. func (c *commandFsDu) Help() string {
  23. return `show disk usage
  24. fs.du http://<filer_server>:<port>/dir
  25. fs.du http://<filer_server>:<port>/dir/file_name
  26. fs.du http://<filer_server>:<port>/dir/file_prefix
  27. `
  28. }
  29. func (c *commandFsDu) Do(args []string, commandEnv *commandEnv, writer io.Writer) (err error) {
  30. filerServer, filerPort, path, err := parseFilerUrl(args[0])
  31. if err != nil {
  32. return err
  33. }
  34. dir, name := filer2.FullPath(path).DirAndName()
  35. if strings.HasSuffix(path, "/") {
  36. if path == "/" {
  37. dir, name = "/", ""
  38. } else {
  39. dir, name = path[0:len(path)-1], ""
  40. }
  41. }
  42. ctx := context.Background()
  43. return commandEnv.withFilerClient(ctx, filerServer, filerPort, func(client filer_pb.SeaweedFilerClient) error {
  44. _, _, err = paginateDirectory(ctx, writer, client, dir, name, 1000)
  45. return err
  46. })
  47. }
  48. func paginateDirectory(ctx context.Context, writer io.Writer, client filer_pb.SeaweedFilerClient, dir, name string, paginateSize int) (blockCount uint64, byteCount uint64, err error) {
  49. paginatedCount := -1
  50. startFromFileName := ""
  51. for paginatedCount == -1 || paginatedCount == paginateSize {
  52. resp, listErr := client.ListEntries(ctx, &filer_pb.ListEntriesRequest{
  53. Directory: dir,
  54. Prefix: name,
  55. StartFromFileName: startFromFileName,
  56. InclusiveStartFrom: false,
  57. Limit: uint32(paginateSize),
  58. })
  59. if listErr != nil {
  60. err = listErr
  61. return
  62. }
  63. paginatedCount = len(resp.Entries)
  64. for _, entry := range resp.Entries {
  65. if entry.IsDirectory {
  66. subDir := fmt.Sprintf("%s/%s", dir, entry.Name)
  67. if dir == "/" {
  68. subDir = "/" + entry.Name
  69. }
  70. numBlock, numByte, err := paginateDirectory(ctx, writer, client, subDir, "", paginateSize)
  71. if err == nil {
  72. blockCount += numBlock
  73. byteCount += numByte
  74. }
  75. } else {
  76. blockCount += uint64(len(entry.Chunks))
  77. byteCount += filer2.TotalSize(entry.Chunks)
  78. }
  79. startFromFileName = entry.Name
  80. if name != "" && !entry.IsDirectory {
  81. fmt.Fprintf(writer, "block:%4d\tbyte:%10d\t%s/%s\n", blockCount, byteCount, dir, name)
  82. }
  83. }
  84. }
  85. if name == "" {
  86. fmt.Fprintf(writer, "block:%4d\tbyte:%10d\t%s\n", blockCount, byteCount, dir)
  87. }
  88. return
  89. }
  90. func parseFilerUrl(entryPath string) (filerServer string, filerPort int64, path string, err error) {
  91. if strings.HasPrefix(entryPath, "http") {
  92. var u *url.URL
  93. u, err = url.Parse(entryPath)
  94. if err != nil {
  95. return
  96. }
  97. filerServer = u.Hostname()
  98. portString := u.Port()
  99. if portString != "" {
  100. filerPort, err = strconv.ParseInt(portString, 10, 32)
  101. }
  102. path = u.Path
  103. } else {
  104. err = fmt.Errorf("path should have full url http://<filer_server>:<port>/path/to/dirOrFile : %s", entryPath)
  105. }
  106. return
  107. }
  108. func (env *commandEnv) withFilerClient(ctx context.Context, filerServer string, filerPort int64, fn func(filer_pb.SeaweedFilerClient) error) error {
  109. filerGrpcAddress := fmt.Sprintf("%s:%d", filerServer, filerPort+10000)
  110. return util.WithCachedGrpcClient(ctx, func(grpcConnection *grpc.ClientConn) error {
  111. client := filer_pb.NewSeaweedFilerClient(grpcConnection)
  112. return fn(client)
  113. }, filerGrpcAddress, env.option.GrpcDialOption)
  114. }