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.

189 lines
4.4 KiB

  1. package wdclient
  2. import (
  3. "context"
  4. "fmt"
  5. "github.com/seaweedfs/seaweedfs/weed/pb"
  6. "google.golang.org/grpc"
  7. "strconv"
  8. "sync"
  9. "testing"
  10. "time"
  11. )
  12. func TestLocationIndex(t *testing.T) {
  13. vm := &vidMap{}
  14. // test must be failed
  15. mustFailed := func(length int) {
  16. _, err := vm.getLocationIndex(length)
  17. if err == nil {
  18. t.Errorf("length %d must be failed", length)
  19. }
  20. if err.Error() != fmt.Sprintf("invalid length: %d", length) {
  21. t.Errorf("length %d must be failed. error: %v", length, err)
  22. }
  23. }
  24. mustFailed(-1)
  25. mustFailed(0)
  26. mustOk := func(length, cursor, expect int) {
  27. if length <= 0 {
  28. t.Fatal("please don't do this")
  29. }
  30. vm.cursor = int32(cursor)
  31. got, err := vm.getLocationIndex(length)
  32. if err != nil {
  33. t.Errorf("length: %d, why? %v\n", length, err)
  34. return
  35. }
  36. if got != expect {
  37. t.Errorf("cursor: %d, length: %d, expect: %d, got: %d\n", cursor, length, expect, got)
  38. return
  39. }
  40. }
  41. for i := -1; i < 100; i++ {
  42. mustOk(7, i, (i+1)%7)
  43. }
  44. // when cursor reaches MaxInt64
  45. mustOk(7, maxCursorIndex, 0)
  46. // test with constructor
  47. vm = newVidMap("")
  48. length := 7
  49. for i := 0; i < 100; i++ {
  50. got, err := vm.getLocationIndex(length)
  51. if err != nil {
  52. t.Errorf("length: %d, why? %v\n", length, err)
  53. return
  54. }
  55. if got != i%length {
  56. t.Errorf("length: %d, i: %d, got: %d\n", length, i, got)
  57. }
  58. }
  59. }
  60. func TestLookupFileId(t *testing.T) {
  61. mc := NewMasterClient(grpc.EmptyDialOption{}, "", "", "", "", "", pb.ServerDiscovery{})
  62. length := 5
  63. //Construct a cache linked list of length 5
  64. for i := 0; i < length; i++ {
  65. mc.addLocation(uint32(i), Location{Url: strconv.FormatInt(int64(i), 10)})
  66. mc.resetVidMap()
  67. }
  68. for i := 0; i < length; i++ {
  69. locations, found := mc.GetLocations(uint32(i))
  70. if !found || len(locations) != 1 || locations[0].Url != strconv.FormatInt(int64(i), 10) {
  71. t.Fatalf("urls of vid=%d is not valid.", i)
  72. }
  73. }
  74. //When continue to add nodes to the linked list, the previous node will be deleted, and the cache of the response will be gone.
  75. for i := length; i < length+5; i++ {
  76. mc.addLocation(uint32(i), Location{Url: strconv.FormatInt(int64(i), 10)})
  77. mc.resetVidMap()
  78. }
  79. for i := 0; i < length; i++ {
  80. locations, found := mc.GetLocations(uint32(i))
  81. if found {
  82. t.Fatalf("urls of vid[%d] should not exists, but found: %v", i, locations)
  83. }
  84. }
  85. //The delete operation will be applied to all cache nodes
  86. _, found := mc.GetLocations(uint32(length))
  87. if !found {
  88. t.Fatalf("urls of vid[%d] not found", length)
  89. }
  90. //If the locations of the current node exist, return directly
  91. newUrl := "abc"
  92. mc.addLocation(uint32(length), Location{Url: newUrl})
  93. locations, found := mc.GetLocations(uint32(length))
  94. if !found || locations[0].Url != newUrl {
  95. t.Fatalf("urls of vid[%d] not found", length)
  96. }
  97. //After delete `abc`, cache nodes are searched
  98. deleteLoc := Location{Url: newUrl}
  99. mc.deleteLocation(uint32(length), deleteLoc)
  100. locations, found = mc.GetLocations(uint32(length))
  101. if found && locations[0].Url != strconv.FormatInt(int64(length), 10) {
  102. t.Fatalf("urls of vid[%d] not expected", length)
  103. }
  104. //lock: concurrent test
  105. var wg sync.WaitGroup
  106. for i := 0; i < 20; i++ {
  107. wg.Add(1)
  108. go func() {
  109. defer wg.Done()
  110. for i := 0; i < 100; i++ {
  111. for i := 0; i < 20; i++ {
  112. _, _ = mc.GetLocations(uint32(i))
  113. }
  114. }
  115. }()
  116. }
  117. for i := 0; i < 100; i++ {
  118. mc.addLocation(uint32(i), Location{})
  119. }
  120. wg.Wait()
  121. }
  122. func TestConcurrentGetLocations(t *testing.T) {
  123. mc := NewMasterClient(grpc.EmptyDialOption{}, "", "", "", "", "", pb.ServerDiscovery{})
  124. location := Location{Url: "TestDataRacing"}
  125. mc.addLocation(1, location)
  126. ctx, cancel := context.WithCancel(context.Background())
  127. wg := sync.WaitGroup{}
  128. for i := 0; i < 50; i++ {
  129. wg.Add(1)
  130. go func() {
  131. defer wg.Done()
  132. for {
  133. select {
  134. case <-ctx.Done():
  135. return
  136. default:
  137. _, found := mc.GetLocations(1)
  138. if !found {
  139. cancel()
  140. t.Error("vid map invalid due to data racing. ")
  141. return
  142. }
  143. }
  144. }
  145. }()
  146. }
  147. //Simulate vidmap reset with cache when leader changes
  148. for i := 0; i < 100; i++ {
  149. mc.resetVidMap()
  150. mc.addLocation(1, location)
  151. time.Sleep(1 * time.Microsecond)
  152. }
  153. cancel()
  154. wg.Wait()
  155. }
  156. func BenchmarkLocationIndex(b *testing.B) {
  157. b.SetParallelism(8)
  158. vm := vidMap{
  159. cursor: maxCursorIndex - 4000,
  160. }
  161. b.ResetTimer()
  162. b.RunParallel(func(pb *testing.PB) {
  163. for pb.Next() {
  164. _, err := vm.getLocationIndex(3)
  165. if err != nil {
  166. b.Error(err)
  167. }
  168. }
  169. })
  170. }