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.

108 lines
3.2 KiB

  1. package shell
  2. import (
  3. "context"
  4. "flag"
  5. "fmt"
  6. "github.com/chrislusf/seaweedfs/weed/pb/master_pb"
  7. "github.com/chrislusf/seaweedfs/weed/storage/types"
  8. "io"
  9. "time"
  10. "github.com/chrislusf/seaweedfs/weed/storage/needle"
  11. )
  12. func init() {
  13. Commands = append(Commands, &commandVolumeTierMove{})
  14. }
  15. type commandVolumeTierMove struct {
  16. }
  17. func (c *commandVolumeTierMove) Name() string {
  18. return "volume.tier.upload"
  19. }
  20. func (c *commandVolumeTierMove) Help() string {
  21. return `change a volume from one disk type to another
  22. volume.tier.move -source=hdd -target=ssd [-collection=""] [-fullPercent=95] [-quietFor=1h]
  23. volume.tier.move -target=hdd [-collection=""] -volumeId=<volume_id>
  24. `
  25. }
  26. func (c *commandVolumeTierMove) Do(args []string, commandEnv *CommandEnv, writer io.Writer) (err error) {
  27. if err = commandEnv.confirmIsLocked(); err != nil {
  28. return
  29. }
  30. tierCommand := flag.NewFlagSet(c.Name(), flag.ContinueOnError)
  31. volumeId := tierCommand.Int("volumeId", 0, "the volume id")
  32. collection := tierCommand.String("collection", "", "the collection name")
  33. fullPercentage := tierCommand.Float64("fullPercent", 95, "the volume reaches the percentage of max volume size")
  34. quietPeriod := tierCommand.Duration("quietFor", 24*time.Hour, "select volumes without no writes for this period")
  35. source := tierCommand.String("fromDiskType", "", "the source disk type")
  36. target := tierCommand.String("toDiskType", "", "the target disk type")
  37. if err = tierCommand.Parse(args); err != nil {
  38. return nil
  39. }
  40. if *source == *target {
  41. return fmt.Errorf("source tier %s is the same as target tier %s", *source, *target)
  42. }
  43. vid := needle.VolumeId(*volumeId)
  44. // volumeId is provided
  45. if vid != 0 {
  46. // return doVolumeTierMove(commandEnv, writer, *collection, vid, *dest, *keepLocalDatFile)
  47. }
  48. // apply to all volumes in the collection
  49. // reusing collectVolumeIdsForEcEncode for now
  50. volumeIds, err := collectVolumeIdsForTierChange(commandEnv, *source, *collection, *fullPercentage, *quietPeriod)
  51. if err != nil {
  52. return err
  53. }
  54. fmt.Printf("tier move volumes: %v\n", volumeIds)
  55. return nil
  56. }
  57. func collectVolumeIdsForTierChange(commandEnv *CommandEnv, sourceTier string, selectedCollection string, fullPercentage float64, quietPeriod time.Duration) (vids []needle.VolumeId, err error) {
  58. var resp *master_pb.VolumeListResponse
  59. err = commandEnv.MasterClient.WithClient(func(client master_pb.SeaweedClient) error {
  60. resp, err = client.VolumeList(context.Background(), &master_pb.VolumeListRequest{})
  61. return err
  62. })
  63. if err != nil {
  64. return
  65. }
  66. quietSeconds := int64(quietPeriod / time.Second)
  67. nowUnixSeconds := time.Now().Unix()
  68. fmt.Printf("collect %s volumes quiet for: %d seconds\n", sourceTier, quietSeconds)
  69. vidMap := make(map[uint32]bool)
  70. eachDataNode(resp.TopologyInfo, func(dc string, rack RackId, dn *master_pb.DataNodeInfo) {
  71. for _, diskInfo := range dn.DiskInfos {
  72. for _, v := range diskInfo.VolumeInfos {
  73. if v.Collection == selectedCollection && v.ModifiedAtSecond+quietSeconds < nowUnixSeconds && types.ToDiskType(v.DiskType) == types.ToDiskType(sourceTier) {
  74. if float64(v.Size) > fullPercentage/100*float64(resp.VolumeSizeLimitMb)*1024*1024 {
  75. vidMap[v.Id] = true
  76. }
  77. }
  78. }
  79. }
  80. })
  81. for vid := range vidMap {
  82. vids = append(vids, needle.VolumeId(vid))
  83. }
  84. return
  85. }