- 客户端 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 等回归测试
67 lines
2.1 KiB
Go
67 lines
2.1 KiB
Go
package notify
|
|
|
|
import (
|
|
"bytes"
|
|
"encoding/binary"
|
|
"io"
|
|
"net"
|
|
"testing"
|
|
"time"
|
|
)
|
|
|
|
type shortWriteBulkRecordConn struct {
|
|
maxPerWrite int
|
|
buf bytes.Buffer
|
|
}
|
|
|
|
func (c *shortWriteBulkRecordConn) Read([]byte) (int, error) { return 0, io.EOF }
|
|
|
|
func (c *shortWriteBulkRecordConn) Write(p []byte) (int, error) {
|
|
if len(p) == 0 {
|
|
return 0, nil
|
|
}
|
|
n := c.maxPerWrite
|
|
if n <= 0 || n > len(p) {
|
|
n = len(p)
|
|
}
|
|
_, _ = c.buf.Write(p[:n])
|
|
return n, nil
|
|
}
|
|
|
|
func (c *shortWriteBulkRecordConn) Close() error { return nil }
|
|
func (c *shortWriteBulkRecordConn) LocalAddr() net.Addr { return shortWriteBulkRecordAddr("local") }
|
|
func (c *shortWriteBulkRecordConn) RemoteAddr() net.Addr { return shortWriteBulkRecordAddr("remote") }
|
|
func (c *shortWriteBulkRecordConn) SetDeadline(time.Time) error { return nil }
|
|
func (c *shortWriteBulkRecordConn) SetReadDeadline(time.Time) error {
|
|
return nil
|
|
}
|
|
func (c *shortWriteBulkRecordConn) SetWriteDeadline(time.Time) error {
|
|
return nil
|
|
}
|
|
|
|
type shortWriteBulkRecordAddr string
|
|
|
|
func (a shortWriteBulkRecordAddr) Network() string { return "tcp" }
|
|
func (a shortWriteBulkRecordAddr) String() string { return string(a) }
|
|
|
|
func TestWriteBulkDedicatedRecordWithDeadlineHandlesShortWrite(t *testing.T) {
|
|
conn := &shortWriteBulkRecordConn{maxPerWrite: 3}
|
|
payload := []byte("abcdefghijklmnopqrstuvwxyz")
|
|
if err := writeBulkDedicatedRecordWithDeadline(conn, payload, time.Time{}); err != nil {
|
|
t.Fatalf("writeBulkDedicatedRecordWithDeadline failed: %v", err)
|
|
}
|
|
raw := conn.buf.Bytes()
|
|
if got, want := len(raw), bulkDedicatedRecordHeaderLen+len(payload); got != want {
|
|
t.Fatalf("record length = %d, want %d", got, want)
|
|
}
|
|
if got := string(raw[:4]); got != bulkDedicatedRecordMagic {
|
|
t.Fatalf("record magic = %q, want %q", got, bulkDedicatedRecordMagic)
|
|
}
|
|
if got, want := int(binary.BigEndian.Uint32(raw[4:8])), len(payload); got != want {
|
|
t.Fatalf("record payload length = %d, want %d", got, want)
|
|
}
|
|
if got := raw[bulkDedicatedRecordHeaderLen:]; !bytes.Equal(got, payload) {
|
|
t.Fatalf("record payload mismatch")
|
|
}
|
|
}
|