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.

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