fix: 修复 dedicated bulk attach 竞态并优化 short write 补写路径

- 客户端 dedicated attach 回复改为精确读取单帧,避免 attach reply 与后续 NBR1 数据粘连后被误解析
  - 服务端 accepted attach 改为先 detach transport,再直接回 attach reply,随后立即切入 dedicated bulk read loop
  - transport 读循环在 stop 或 transport ownership 失效后不再继续上推已读数据,避免 handoff 后首包被旧 reader 吃掉
  - dedicated bulk record 写路径改为 full-write,消除 short write 导致的 invalid bulk fast payload
  - 优化 vectored write 补写策略:先尝试一次 writev,未写完时直接顺序补完剩余 buffers,减少重复 WriteTo 开销
  - 放宽 vectored write 能力识别,支持通过 UnwrapConn/WriteBuffers 命中 fast path
  - 修复 dedicated batch 排队路径 payload 复用问题,改为深拷贝 queued items
  - 补齐 dedicated attach、short write、payload clone、transport stop/handoff 等回归测试
This commit is contained in:
2026-04-16 17:27:48 +08:00
parent 7ed3dd5b37
commit 4f760f2807
9 changed files with 690 additions and 47 deletions
+33
View File
@@ -1,6 +1,7 @@
package notify
import (
"bytes"
"context"
"errors"
"net"
@@ -8,6 +9,38 @@ import (
"time"
)
func TestCloneBulkDedicatedSendRequestsDeepCopiesPayload(t *testing.T) {
src := []bulkDedicatedSendRequest{
{
Type: bulkFastPayloadTypeData,
Seq: 1,
Payload: []byte("payload-a"),
},
{
Type: bulkFastPayloadTypeReset,
Seq: 2,
Payload: []byte("payload-b"),
},
}
cloned := cloneBulkDedicatedSendRequests(src)
if len(cloned) != len(src) {
t.Fatalf("clone length = %d, want %d", len(cloned), len(src))
}
if &cloned[0] == &src[0] {
t.Fatal("request clone should not alias source slice elements")
}
if len(cloned[0].Payload) == 0 || len(src[0].Payload) == 0 {
t.Fatal("payload should not be empty")
}
if &cloned[0].Payload[0] == &src[0].Payload[0] {
t.Fatal("payload clone should not alias source bytes")
}
src[0].Payload[0] = 'X'
if bytes.Equal(cloned[0].Payload, src[0].Payload) {
t.Fatal("mutating source payload should not affect cloned payload")
}
}
func TestBulkDedicatedBatchPlainRoundTrip(t *testing.T) {
releasePayload, err := encodeBulkDedicatedReleasePayload(4096, 2)
if err != nil {