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.

133 lines
4.2 KiB

  1. package shell
  2. import (
  3. "fmt"
  4. "testing"
  5. "github.com/seaweedfs/seaweedfs/weed/pb/master_pb"
  6. "github.com/seaweedfs/seaweedfs/weed/storage/erasure_coding"
  7. "github.com/seaweedfs/seaweedfs/weed/storage/needle"
  8. "github.com/seaweedfs/seaweedfs/weed/storage/super_block"
  9. )
  10. var (
  11. topology1 = parseOutput(topoData)
  12. topology2 = parseOutput(topoData2)
  13. topologyEc = parseOutput(topoDataEc)
  14. )
  15. func TestEcDistribution(t *testing.T) {
  16. // find out all volume servers with one slot left.
  17. ecNodes, totalFreeEcSlots := collectEcVolumeServersByDc(topology1, "")
  18. sortEcNodesByFreeslotsDescending(ecNodes)
  19. if totalFreeEcSlots < erasure_coding.TotalShardsCount {
  20. t.Errorf("not enough free ec shard slots: %d", totalFreeEcSlots)
  21. }
  22. allocatedDataNodes := ecNodes
  23. if len(allocatedDataNodes) > erasure_coding.TotalShardsCount {
  24. allocatedDataNodes = allocatedDataNodes[:erasure_coding.TotalShardsCount]
  25. }
  26. for _, dn := range allocatedDataNodes {
  27. // fmt.Printf("info %+v %+v\n", dn.info, dn)
  28. fmt.Printf("=> %+v %+v\n", dn.info.Id, dn.freeEcSlot)
  29. }
  30. }
  31. func TestVolumeIdToReplicaPlacement(t *testing.T) {
  32. testCases := []struct {
  33. topology *master_pb.TopologyInfo
  34. vid string
  35. want string
  36. wantErr string
  37. }{
  38. {topology1, "", "", "failed to resolve replica placement for volume ID 0"},
  39. {topology1, "0", "", "failed to resolve replica placement for volume ID 0"},
  40. {topology1, "1", "100", ""},
  41. {topology1, "296", "100", ""},
  42. {topology2, "", "", "failed to resolve replica placement for volume ID 0"},
  43. {topology2, "19012", "", "failed to resolve replica placement for volume ID 19012"},
  44. {topology2, "6271", "002", ""},
  45. {topology2, "17932", "002", ""},
  46. }
  47. for _, tc := range testCases {
  48. vid, _ := needle.NewVolumeId(tc.vid)
  49. ecNodes, _ := collectEcVolumeServersByDc(tc.topology, "")
  50. got, gotErr := volumeIdToReplicaPlacement(vid, ecNodes)
  51. if tc.wantErr == "" && gotErr != nil {
  52. t.Errorf("expected no error for volume %q, got %q", tc.vid, gotErr.Error())
  53. continue
  54. }
  55. if tc.wantErr != "" {
  56. if gotErr == nil {
  57. t.Errorf("got no error for volume %q, expected %q", tc.vid, tc.wantErr)
  58. continue
  59. }
  60. if gotErr.Error() != tc.wantErr {
  61. t.Errorf("expected error %q for volume %q, got %q", tc.wantErr, tc.vid, gotErr.Error())
  62. continue
  63. }
  64. }
  65. if got == nil {
  66. if tc.want != "" {
  67. t.Errorf("expected replica placement %q for volume %q, got nil", tc.want, tc.vid)
  68. }
  69. continue
  70. }
  71. want, _ := super_block.NewReplicaPlacementFromString(tc.want)
  72. if !got.Equals(want) {
  73. t.Errorf("got replica placement %q for volune %q, want %q", got.String(), tc.vid, want.String())
  74. }
  75. }
  76. }
  77. func TestPickRackToBalanceShardsInto(t *testing.T) {
  78. testCases := []struct {
  79. topology *master_pb.TopologyInfo
  80. vid string
  81. wantOneOf []string
  82. }{
  83. // Non-EC volumes. We don't care about these, but the function should return all racks as a safeguard.
  84. {topologyEc, "", []string{"rack1", "rack2", "rack3", "rack4", "rack5", "rack6"}},
  85. {topologyEc, "6225", []string{"rack1", "rack2", "rack3", "rack4", "rack5", "rack6"}},
  86. {topologyEc, "6226", []string{"rack1", "rack2", "rack3", "rack4", "rack5", "rack6"}},
  87. {topologyEc, "6241", []string{"rack1", "rack2", "rack3", "rack4", "rack5", "rack6"}},
  88. {topologyEc, "6242", []string{"rack1", "rack2", "rack3", "rack4", "rack5", "rack6"}},
  89. // EC volumes.
  90. {topologyEc, "9577", []string{"rack1", "rack2", "rack3"}},
  91. {topologyEc, "10457", []string{"rack1"}},
  92. {topologyEc, "12737", []string{"rack2"}},
  93. {topologyEc, "14322", []string{"rack3"}},
  94. }
  95. for _, tc := range testCases {
  96. vid, _ := needle.NewVolumeId(tc.vid)
  97. ecNodes, _ := collectEcVolumeServersByDc(tc.topology, "")
  98. racks := collectRacks(ecNodes)
  99. locations := ecNodes
  100. rackToShardCount := countShardsByRack(vid, locations)
  101. averageShardsPerEcRack := ceilDivide(erasure_coding.TotalShardsCount, len(racks))
  102. got := pickRackToBalanceShardsInto(racks, rackToShardCount, nil, averageShardsPerEcRack)
  103. if string(got) == "" && len(tc.wantOneOf) == 0 {
  104. continue
  105. }
  106. found := false
  107. for _, want := range tc.wantOneOf {
  108. if got := string(got); got == want {
  109. found = true
  110. break
  111. }
  112. }
  113. if !(found) {
  114. t.Errorf("expected one of %v for volume %q, got %q", tc.wantOneOf, tc.vid, got)
  115. }
  116. }
  117. }