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.

204 lines
6.3 KiB

6 years ago
6 years ago
  1. package shell
  2. import (
  3. "context"
  4. "fmt"
  5. "github.com/chrislusf/seaweedfs/weed/operation"
  6. "github.com/chrislusf/seaweedfs/weed/pb/master_pb"
  7. "github.com/chrislusf/seaweedfs/weed/pb/volume_server_pb"
  8. "github.com/chrislusf/seaweedfs/weed/storage"
  9. "io"
  10. "math/rand"
  11. "sort"
  12. )
  13. func init() {
  14. commands = append(commands, &commandVolumeFixReplication{})
  15. }
  16. type commandVolumeFixReplication struct {
  17. }
  18. func (c *commandVolumeFixReplication) Name() string {
  19. return "volume.fix.replication"
  20. }
  21. func (c *commandVolumeFixReplication) Help() string {
  22. return `add replicas to volumes that are missing replicas
  23. This command file all under-replicated volumes, and find volume servers with free slots.
  24. If the free slots satisfy the replication requirement, the volume content is copied over and mounted.
  25. volume.fix.replication -n # do not take action
  26. volume.fix.replication # actually copying the volume files and mount the volume
  27. Note:
  28. * each time this will only add back one replica for one volume id. If there are multiple replicas
  29. are missing, e.g. multiple volume servers are new, you may need to run this multiple times.
  30. * do not run this too quick within seconds, since the new volume replica may take a few seconds
  31. to register itself to the master.
  32. `
  33. }
  34. func (c *commandVolumeFixReplication) Do(args []string, commandEnv *commandEnv, writer io.Writer) (err error) {
  35. takeAction := true
  36. if len(args) > 0 && args[0] == "-n" {
  37. takeAction = false
  38. }
  39. var resp *master_pb.VolumeListResponse
  40. ctx := context.Background()
  41. err = commandEnv.masterClient.WithClient(ctx, func(client master_pb.SeaweedClient) error {
  42. resp, err = client.VolumeList(ctx, &master_pb.VolumeListRequest{})
  43. return err
  44. })
  45. if err != nil {
  46. return err
  47. }
  48. // find all volumes that needs replication
  49. // collect all data nodes
  50. replicatedVolumeLocations := make(map[uint32][]location)
  51. replicatedVolumeInfo := make(map[uint32]*master_pb.VolumeInformationMessage)
  52. var allLocations []location
  53. for _, dc := range resp.TopologyInfo.DataCenterInfos {
  54. for _, rack := range dc.RackInfos {
  55. for _, dn := range rack.DataNodeInfos {
  56. loc := newLocation(dc.Id, rack.Id, dn)
  57. for _, v := range dn.VolumeInfos {
  58. if v.ReplicaPlacement > 0 {
  59. replicatedVolumeLocations[v.Id] = append(replicatedVolumeLocations[v.Id], loc)
  60. replicatedVolumeInfo[v.Id] = v
  61. }
  62. }
  63. allLocations = append(allLocations, loc)
  64. }
  65. }
  66. }
  67. // find all under replicated volumes
  68. underReplicatedVolumeLocations := make(map[uint32][]location)
  69. for vid, locations := range replicatedVolumeLocations {
  70. volumeInfo := replicatedVolumeInfo[vid]
  71. replicaPlacement, _ := storage.NewReplicaPlacementFromByte(byte(volumeInfo.ReplicaPlacement))
  72. if replicaPlacement.GetCopyCount() > len(locations) {
  73. underReplicatedVolumeLocations[vid] = locations
  74. }
  75. }
  76. if len(underReplicatedVolumeLocations) == 0 {
  77. return fmt.Errorf("no under replicated volumes")
  78. }
  79. if len(allLocations) == 0 {
  80. return fmt.Errorf("no data nodes at all")
  81. }
  82. // find the most under populated data nodes
  83. keepDataNodesSorted(allLocations)
  84. for vid, locations := range underReplicatedVolumeLocations {
  85. volumeInfo := replicatedVolumeInfo[vid]
  86. replicaPlacement, _ := storage.NewReplicaPlacementFromByte(byte(volumeInfo.ReplicaPlacement))
  87. foundNewLocation := false
  88. for _, dst := range allLocations {
  89. // check whether data nodes satisfy the constraints
  90. if dst.dataNode.FreeVolumeCount > 0 && satisfyReplicaPlacement(replicaPlacement, locations, dst) {
  91. // ask the volume server to replicate the volume
  92. sourceNodes := underReplicatedVolumeLocations[vid]
  93. sourceNode := sourceNodes[rand.Intn(len(sourceNodes))]
  94. foundNewLocation = true
  95. fmt.Fprintf(writer, "replicating volume %d %s from %s to dataNode %s ...\n", volumeInfo.Id, replicaPlacement, sourceNode.dataNode.Id, dst.dataNode.Id)
  96. if !takeAction {
  97. break
  98. }
  99. err := operation.WithVolumeServerClient(dst.dataNode.Id, commandEnv.option.GrpcDialOption, func(volumeServerClient volume_server_pb.VolumeServerClient) error {
  100. _, replicateErr := volumeServerClient.VolumeCopy(ctx, &volume_server_pb.VolumeCopyRequest{
  101. VolumeId: volumeInfo.Id,
  102. SourceDataNode: sourceNode.dataNode.Id,
  103. })
  104. return replicateErr
  105. })
  106. if err != nil {
  107. return err
  108. }
  109. // adjust free volume count
  110. dst.dataNode.FreeVolumeCount--
  111. keepDataNodesSorted(allLocations)
  112. break
  113. }
  114. }
  115. if !foundNewLocation {
  116. fmt.Fprintf(writer, "failed to place volume %d replica as %s, existing:%+v\n", volumeInfo.Id, replicaPlacement, locations)
  117. }
  118. }
  119. return nil
  120. }
  121. func keepDataNodesSorted(dataNodes []location) {
  122. sort.Slice(dataNodes, func(i, j int) bool {
  123. return dataNodes[i].dataNode.FreeVolumeCount > dataNodes[j].dataNode.FreeVolumeCount
  124. })
  125. }
  126. func satisfyReplicaPlacement(replicaPlacement *storage.ReplicaPlacement, existingLocations []location, possibleLocation location) bool {
  127. existingDataCenters := make(map[string]bool)
  128. existingRacks := make(map[string]bool)
  129. existingDataNodes := make(map[string]bool)
  130. for _, loc := range existingLocations {
  131. existingDataCenters[loc.DataCenter()] = true
  132. existingRacks[loc.Rack()] = true
  133. existingDataNodes[loc.String()] = true
  134. }
  135. if replicaPlacement.DiffDataCenterCount >= len(existingDataCenters) {
  136. // check dc, good if different from any existing data centers
  137. _, found := existingDataCenters[possibleLocation.DataCenter()]
  138. return !found
  139. } else if replicaPlacement.DiffRackCount >= len(existingRacks) {
  140. // check rack, good if different from any existing racks
  141. _, found := existingRacks[possibleLocation.Rack()]
  142. return !found
  143. } else if replicaPlacement.SameRackCount >= len(existingDataNodes) {
  144. // check data node, good if different from any existing data nodes
  145. _, found := existingDataNodes[possibleLocation.String()]
  146. return !found
  147. }
  148. return false
  149. }
  150. type location struct {
  151. dc string
  152. rack string
  153. dataNode *master_pb.DataNodeInfo
  154. }
  155. func newLocation(dc, rack string, dataNode *master_pb.DataNodeInfo) location {
  156. return location{
  157. dc: dc,
  158. rack: rack,
  159. dataNode: dataNode,
  160. }
  161. }
  162. func (l location) String() string {
  163. return fmt.Sprintf("%s %s %s", l.dc, l.rack, l.dataNode.Id)
  164. }
  165. func (l location) Rack() string {
  166. return fmt.Sprintf("%s %s", l.dc, l.rack)
  167. }
  168. func (l location) DataCenter() string {
  169. return l.dc
  170. }