access_lock_test.go 4.2 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188
  1. package core
  2. import (
  3. "sync"
  4. "sync/atomic"
  5. "testing"
  6. "time"
  7. )
  8. // TestAccessLock_ReadReadParallel 验证多个读者真正并行 (不互相阻塞)。
  9. // 原理: 10 个 goroutine 同时 RLock, 每个 sleep 200ms, 总耗时应 ~200ms 而非 ~2000ms。
  10. func TestAccessLock_ReadReadParallel(t *testing.T) {
  11. var l accessLock
  12. const readers = 10
  13. const hold = 200 * time.Millisecond
  14. start := time.Now()
  15. var wg sync.WaitGroup
  16. wg.Add(readers)
  17. for i := 0; i < readers; i++ {
  18. go func() {
  19. defer wg.Done()
  20. l.RLock()
  21. time.Sleep(hold)
  22. l.RUnlock()
  23. }()
  24. }
  25. wg.Wait()
  26. elapsed := time.Since(start)
  27. if elapsed >= hold*2 { // 给 2x 余量, 超过说明有串行化
  28. t.Errorf("读读应该并行, 但耗时 %v (期望 < %v)", elapsed, hold*2)
  29. }
  30. t.Logf("10 个读者并行耗时: %v", elapsed)
  31. }
  32. // TestAccessLock_WriteBlocksRead 验证写锁阻塞读。
  33. func TestAccessLock_WriteBlocksRead(t *testing.T) {
  34. var l accessLock
  35. const hold = 200 * time.Millisecond
  36. const waitTolerance = hold / 2
  37. // goroutine A: 拿写锁, sleep 200ms
  38. doneA := make(chan struct{})
  39. go func() {
  40. l.Lock()
  41. time.Sleep(hold)
  42. l.Unlock()
  43. close(doneA)
  44. }()
  45. // 等 goroutine A 真正拿到锁
  46. time.Sleep(20 * time.Millisecond)
  47. // goroutine B: 尝试 RLock, 应该被阻塞, 直到 A 释放
  48. startB := time.Now()
  49. l.RLock()
  50. elapsedB := time.Since(startB)
  51. l.RUnlock()
  52. if elapsedB < hold-waitTolerance {
  53. t.Errorf("写锁应该阻塞读, 但 B 只等了 %v (期望 >= %v)", elapsedB, hold-waitTolerance)
  54. }
  55. t.Logf("读等写释放耗时: %v", elapsedB)
  56. <-doneA
  57. }
  58. // TestAccessLock_ReentrantWrite 验证同 goroutine 写锁重入不卡死。
  59. func TestAccessLock_ReentrantWrite(t *testing.T) {
  60. var l accessLock
  61. const depth = 10
  62. // 同 goroutine 连续 Lock 10 次, 再 Unlock 10 次
  63. for i := 0; i < depth; i++ {
  64. l.Lock()
  65. }
  66. for i := 0; i < depth; i++ {
  67. l.Unlock()
  68. }
  69. t.Logf("写锁 %d 层重入正常", depth)
  70. }
  71. // TestAccessLock_ReentrantRLockUnderWrite 验证同 goroutine 持有写锁时再 RLock 不卡死。
  72. // 这是 TsDB2 特有的关键路径: BeginTransaction (Lock) → InsertRow → scanWithPKID (RLock)
  73. func TestAccessLock_ReentrantRLockUnderWrite(t *testing.T) {
  74. var l accessLock
  75. l.Lock()
  76. l.RLock() // 同 goroutine, 已持写锁, 应该跳过
  77. l.RUnlock()
  78. l.Unlock()
  79. t.Logf("同 goroutine 写锁下 RLock 正常")
  80. }
  81. // TestAccessLock_WriteWaitsForReaders 验证写锁等待现有读者离开。
  82. func TestAccessLock_WriteWaitsForReaders(t *testing.T) {
  83. var l accessLock
  84. const hold = 200 * time.Millisecond
  85. const tolerance = hold / 2
  86. // goroutine A: RLock, sleep 200ms
  87. doneA := make(chan struct{})
  88. go func() {
  89. l.RLock()
  90. time.Sleep(hold)
  91. l.RUnlock()
  92. close(doneA)
  93. }()
  94. // 等 A 拿到 RLock
  95. time.Sleep(20 * time.Millisecond)
  96. // goroutine B: 尝试 Lock, 应该等 A 的 RUnlock
  97. startB := time.Now()
  98. l.Lock()
  99. elapsedB := time.Since(startB)
  100. l.Unlock()
  101. if elapsedB < hold-tolerance {
  102. t.Errorf("写锁应该等待读者, 但 B 只等了 %v (期望 >= %v)", elapsedB, hold-tolerance)
  103. }
  104. t.Logf("写锁等待读者耗时: %v", elapsedB)
  105. <-doneA
  106. }
  107. // TestAccessLock_DeadlockStress 长时间压力测试, 确保没有死锁。
  108. // 10 个读者 goroutine + 2 个写者 goroutine, 混合跑 3 秒。
  109. func TestAccessLock_DeadlockStress(t *testing.T) {
  110. var l accessLock
  111. var reads, writes int64
  112. stop := make(chan struct{})
  113. var wg sync.WaitGroup
  114. // 读者: RLock → 少量工作 → RUnlock
  115. for i := 0; i < 10; i++ {
  116. wg.Add(1)
  117. go func() {
  118. defer wg.Done()
  119. for {
  120. select {
  121. case <-stop:
  122. return
  123. default:
  124. l.RLock()
  125. atomic.AddInt64(&reads, 1)
  126. l.RUnlock()
  127. }
  128. }
  129. }()
  130. }
  131. // 写者: Lock → 少量工作 → Unlock
  132. for i := 0; i < 2; i++ {
  133. wg.Add(1)
  134. go func() {
  135. defer wg.Done()
  136. for {
  137. select {
  138. case <-stop:
  139. return
  140. default:
  141. l.Lock()
  142. atomic.AddInt64(&writes, 1)
  143. l.Unlock()
  144. }
  145. }
  146. }()
  147. }
  148. // 跑 3 秒后停止
  149. time.Sleep(3 * time.Second)
  150. close(stop)
  151. done := make(chan struct{})
  152. go func() { wg.Wait(); close(done) }()
  153. select {
  154. case <-done:
  155. r := atomic.LoadInt64(&reads)
  156. w := atomic.LoadInt64(&writes)
  157. t.Logf("3 秒压力测试通过, reads=%d writes=%d", r, w)
  158. case <-time.After(2 * time.Second):
  159. t.Fatal("压力测试超时 —— 疑似死锁!")
  160. }
  161. }