locker_test.go 2.6 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161
  1. package locker
  2. import (
  3. "math/rand"
  4. "strconv"
  5. "sync"
  6. "testing"
  7. "time"
  8. )
  9. func TestLockCounter(t *testing.T) {
  10. l := &lockCtr{}
  11. l.inc()
  12. if l.waiters != 1 {
  13. t.Fatal("counter inc failed")
  14. }
  15. l.dec()
  16. if l.waiters != 0 {
  17. t.Fatal("counter dec failed")
  18. }
  19. }
  20. func TestLockerLock(t *testing.T) {
  21. l := New()
  22. l.Lock("test")
  23. ctr := l.locks["test"]
  24. if ctr.count() != 0 {
  25. t.Fatalf("expected waiters to be 0, got :%d", ctr.waiters)
  26. }
  27. chDone := make(chan struct{})
  28. go func() {
  29. l.Lock("test")
  30. close(chDone)
  31. }()
  32. chWaiting := make(chan struct{})
  33. go func() {
  34. for range time.Tick(1 * time.Millisecond) {
  35. if ctr.count() == 1 {
  36. close(chWaiting)
  37. break
  38. }
  39. }
  40. }()
  41. select {
  42. case <-chWaiting:
  43. case <-time.After(3 * time.Second):
  44. t.Fatal("timed out waiting for lock waiters to be incremented")
  45. }
  46. select {
  47. case <-chDone:
  48. t.Fatal("lock should not have returned while it was still held")
  49. default:
  50. }
  51. if err := l.Unlock("test"); err != nil {
  52. t.Fatal(err)
  53. }
  54. select {
  55. case <-chDone:
  56. case <-time.After(3 * time.Second):
  57. t.Fatalf("lock should have completed")
  58. }
  59. if ctr.count() != 0 {
  60. t.Fatalf("expected waiters to be 0, got: %d", ctr.count())
  61. }
  62. }
  63. func TestLockerUnlock(t *testing.T) {
  64. l := New()
  65. l.Lock("test")
  66. l.Unlock("test")
  67. chDone := make(chan struct{})
  68. go func() {
  69. l.Lock("test")
  70. close(chDone)
  71. }()
  72. select {
  73. case <-chDone:
  74. case <-time.After(3 * time.Second):
  75. t.Fatalf("lock should not be blocked")
  76. }
  77. }
  78. func TestLockerConcurrency(t *testing.T) {
  79. l := New()
  80. var wg sync.WaitGroup
  81. for i := 0; i <= 10000; i++ {
  82. wg.Add(1)
  83. go func() {
  84. l.Lock("test")
  85. // if there is a concurrency issue, will very likely panic here
  86. l.Unlock("test")
  87. wg.Done()
  88. }()
  89. }
  90. chDone := make(chan struct{})
  91. go func() {
  92. wg.Wait()
  93. close(chDone)
  94. }()
  95. select {
  96. case <-chDone:
  97. case <-time.After(10 * time.Second):
  98. t.Fatal("timeout waiting for locks to complete")
  99. }
  100. // Since everything has unlocked this should not exist anymore
  101. if ctr, exists := l.locks["test"]; exists {
  102. t.Fatalf("lock should not exist: %v", ctr)
  103. }
  104. }
  105. func BenchmarkLocker(b *testing.B) {
  106. l := New()
  107. for i := 0; i < b.N; i++ {
  108. l.Lock("test")
  109. l.Unlock("test")
  110. }
  111. }
  112. func BenchmarkLockerParallel(b *testing.B) {
  113. l := New()
  114. b.SetParallelism(128)
  115. b.RunParallel(func(pb *testing.PB) {
  116. for pb.Next() {
  117. l.Lock("test")
  118. l.Unlock("test")
  119. }
  120. })
  121. }
  122. func BenchmarkLockerMoreKeys(b *testing.B) {
  123. l := New()
  124. var keys []string
  125. for i := 0; i < 64; i++ {
  126. keys = append(keys, strconv.Itoa(i))
  127. }
  128. b.SetParallelism(128)
  129. b.RunParallel(func(pb *testing.PB) {
  130. for pb.Next() {
  131. k := keys[rand.Intn(len(keys))]
  132. l.Lock(k)
  133. l.Unlock(k)
  134. }
  135. })
  136. }