fix:window data race

This commit is contained in:
rulego-team
2025-06-14 21:47:19 +08:00
parent b3ea1fb4fa
commit 040cb6ba87
3 changed files with 32 additions and 6 deletions
+4 -4
View File
@@ -77,12 +77,12 @@ func (cw *CountingWindow) Start() {
if shouldTrigger {
// 在持有锁的情况下立即处理
slot := cw.createSlot(cw.dataBuffer[:cw.threshold])
for i := range cw.dataBuffer[:cw.threshold] {
// 由于Row是值类型,这里需要通过指针来修改Slot字段
cw.dataBuffer[i].Slot = slot
}
data := make([]types.Row, cw.threshold)
copy(data, cw.dataBuffer[:cw.threshold])
// 设置Slot字段到复制的数据中,避免修改原始dataBuffer
for i := range data {
data[i].Slot = slot
}
if len(cw.dataBuffer) > cw.threshold {
remaining := len(cw.dataBuffer) - cw.threshold
+27 -2
View File
@@ -51,10 +51,35 @@ func TestCountingWindow(t *testing.T) {
case <-time.After(2 * time.Second):
t.Error("No results received within timeout")
}
assert.Len(t, cw.dataBuffer, 1)
// 验证窗口状态:添加第4个数据后,第一个窗口已触发,剩余1个数据(值为3)
// 继续添加2个数据,应该再次触发
cw.Add(4) // 添加第5个数据
cw.Add(5) // 添加第6个数据,应该再次触发(3,4,5)
// 等待第二次触发
select {
case res := <-resultsChan:
assert.Len(t, res, 3)
assert.Equal(t, 3, res[0].Data, "第二批第一个元素应该是3")
assert.Equal(t, 4, res[1].Data, "第二批第二个元素应该是4")
assert.Equal(t, 5, res[2].Data, "第二批第三个元素应该是5")
case <-time.After(2 * time.Second):
t.Error("No second results received within timeout")
}
// Test case 2: Reset
cw.Reset()
assert.Len(t, cw.dataBuffer, 0)
// Reset后添加数据验证重置是否成功
cw.Add(100)
cw.Add(101)
cw.Add(102)
select {
case res := <-resultsChan:
assert.Len(t, res, 3)
assert.Equal(t, 100, res[0].Data, "重置后第一个元素应该是100")
case <-time.After(2 * time.Second):
t.Error("No results after reset received within timeout")
}
}
func TestCountingWindowBadThreshold(t *testing.T) {
+1
View File
@@ -115,6 +115,7 @@ func (tw *TumblingWindow) Start() {
select {
// 当定时器到期时,触发窗口。
case <-tw.timer.C:
// 在调用Trigger前不需要额外加锁,因为Trigger方法内部已经有锁保护
tw.Trigger()
// 当上下文被取消时,停止定时器并退出循环。
case <-tw.ctx.Done():