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.

205 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. Collection: volumeInfo.Collection,
  103. SourceDataNode: sourceNode.dataNode.Id,
  104. })
  105. return replicateErr
  106. })
  107. if err != nil {
  108. return err
  109. }
  110. // adjust free volume count
  111. dst.dataNode.FreeVolumeCount--
  112. keepDataNodesSorted(allLocations)
  113. break
  114. }
  115. }
  116. if !foundNewLocation {
  117. fmt.Fprintf(writer, "failed to place volume %d replica as %s, existing:%+v\n", volumeInfo.Id, replicaPlacement, locations)
  118. }
  119. }
  120. return nil
  121. }
  122. func keepDataNodesSorted(dataNodes []location) {
  123. sort.Slice(dataNodes, func(i, j int) bool {
  124. return dataNodes[i].dataNode.FreeVolumeCount > dataNodes[j].dataNode.FreeVolumeCount
  125. })
  126. }
  127. func satisfyReplicaPlacement(replicaPlacement *storage.ReplicaPlacement, existingLocations []location, possibleLocation location) bool {
  128. existingDataCenters := make(map[string]bool)
  129. existingRacks := make(map[string]bool)
  130. existingDataNodes := make(map[string]bool)
  131. for _, loc := range existingLocations {
  132. existingDataCenters[loc.DataCenter()] = true
  133. existingRacks[loc.Rack()] = true
  134. existingDataNodes[loc.String()] = true
  135. }
  136. if replicaPlacement.DiffDataCenterCount >= len(existingDataCenters) {
  137. // check dc, good if different from any existing data centers
  138. _, found := existingDataCenters[possibleLocation.DataCenter()]
  139. return !found
  140. } else if replicaPlacement.DiffRackCount >= len(existingRacks) {
  141. // check rack, good if different from any existing racks
  142. _, found := existingRacks[possibleLocation.Rack()]
  143. return !found
  144. } else if replicaPlacement.SameRackCount >= len(existingDataNodes) {
  145. // check data node, good if different from any existing data nodes
  146. _, found := existingDataNodes[possibleLocation.String()]
  147. return !found
  148. }
  149. return false
  150. }
  151. type location struct {
  152. dc string
  153. rack string
  154. dataNode *master_pb.DataNodeInfo
  155. }
  156. func newLocation(dc, rack string, dataNode *master_pb.DataNodeInfo) location {
  157. return location{
  158. dc: dc,
  159. rack: rack,
  160. dataNode: dataNode,
  161. }
  162. }
  163. func (l location) String() string {
  164. return fmt.Sprintf("%s %s %s", l.dc, l.rack, l.dataNode.Id)
  165. }
  166. func (l location) Rack() string {
  167. return fmt.Sprintf("%s %s", l.dc, l.rack)
  168. }
  169. func (l location) DataCenter() string {
  170. return l.dc
  171. }