fix(db): 修复 NextID 与写锁重入死锁
- NextID 改用独立 seqMu,不再依赖数据写锁,杜绝 Lock 内调用 NextID 的死锁 - CaptureAppVolumeForHour 先取 ID 再 Lock - 新增写锁看门狗:长时间占用时转储 goroutine 栈 - 新增 TestNextIDWhileWriteLocked 回归测试
This commit is contained in:
1 parent
f1fc7b4a9a
commit
2e97c04f84
3 files changed
+73
-3
No files matched your search
@@ -0,0 +1,35 @@
|
||||
package repository
|
||||
|
||||
import (
|
||||
"testing"
|
||||
"time"
|
||||
)
|
||||
|
||||
// TestNextIDWhileWriteLocked 回归测试:调用方持有写锁时 NextID 不能死锁。
|
||||
//
|
||||
// 历史问题:NextID 内部用 d.mu 加锁,而 CaptureAppVolumeForHour 先 db.Lock()
|
||||
// 再 db.NextID(),Go 的 sync.RWMutex 不可重入,导致该 goroutine 永久持有写锁,
|
||||
// 所有读库接口(登录、列表)全部挂起,而 /health 仍然正常。
|
||||
func TestNextIDWhileWriteLocked(t *testing.T) {
|
||||
db := &JsonDB{sequences: map[string]uint{}}
|
||||
db.Lock()
|
||||
|
||||
done := make(chan uint, 1)
|
||||
go func() { done <- db.NextID("test") }()
|
||||
|
||||
select {
|
||||
case id := <-done:
|
||||
db.Unlock()
|
||||
if id != 1 {
|
||||
t.Fatalf("first id = %d, want 1", id)
|
||||
}
|
||||
case <-time.After(2 * time.Second):
|
||||
db.Unlock()
|
||||
t.Fatal("NextID deadlocked while write lock is held")
|
||||
}
|
||||
|
||||
// 解锁后继续分配应递增
|
||||
if id := db.NextID("test"); id != 2 {
|
||||
t.Fatalf("second id = %d, want 2", id)
|
||||
}
|
||||
}
|
||||
Reference in new issue
Block a user