fix(notify): 根治低带宽控制面阻塞与传输写入卡死

- 为控制消息增加优先级、公平调度、队列字节预算和自适应批处理
- 支持可取消的写门等待,收紧 shared/dedicated bulk、stream 和 Reply 写入边界
- 修复 bulk reset/close、连接 handoff 和安全 profile 切换时序
- 保留旧取消与超时错误契约,新增阶段化 TransportSendError
- 增加 ReplyCtx、ReplyObjCtx、写超时配置及黑洞连接和竞态回归测试
This commit is contained in:
2026-08-14 10:16:37 +08:00
parent 98ef9e7fcc
commit 0826e17063
45 changed files with 4231 additions and 293 deletions
+199 -1
View File
@@ -6,6 +6,7 @@ import (
"io"
"net"
"strings"
"sync"
"testing"
"time"
)
@@ -818,6 +819,61 @@ func TestBulkWritePrefersResetErrorOverContextCanceled(t *testing.T) {
}
}
func TestBulkResetWakesLocalStateBeforeRemoteNotificationCompletes(t *testing.T) {
wantErr := errors.New("local reset must win")
resetStarted := make(chan struct{})
resetUnblock := make(chan struct{})
var unblockOnce sync.Once
unblock := func() { unblockOnce.Do(func() { close(resetUnblock) }) }
defer unblock()
bulk := newBulkHandle(context.Background(), nil, "test", BulkOpenRequest{
BulkID: "bulk-reset-local-first",
DataID: 1,
Range: BulkRange{
Length: 1,
},
}, 0, nil, nil, 0, nil, func(context.Context, *bulkHandle, string) error {
close(resetStarted)
<-resetUnblock
return nil
}, nil, nil, nil)
readDone := make(chan error, 1)
go func() {
_, err := bulk.Read(make([]byte, 1))
readDone <- err
}()
resetDone := make(chan error, 1)
go func() {
resetDone <- bulk.Reset(wantErr)
}()
select {
case <-resetStarted:
case <-time.After(time.Second):
t.Fatal("remote reset notification did not start")
}
select {
case <-bulk.Context().Done():
case <-time.After(100 * time.Millisecond):
t.Fatal("bulk context stayed live while remote reset notification was blocked")
}
select {
case err := <-readDone:
if !errors.Is(err, wantErr) {
t.Fatalf("bulk Read error=%v, want %v", err, wantErr)
}
case <-time.After(100 * time.Millisecond):
t.Fatal("bulk Read stayed blocked while remote reset notification was blocked")
}
unblock()
if err := <-resetDone; err != nil {
t.Fatalf("Reset returned error: %v", err)
}
}
func TestDedicatedBulkWaitReadyPrefersClosedPipeOverContextCanceled(t *testing.T) {
bulk := newBulkHandle(context.Background(), nil, "test", BulkOpenRequest{
BulkID: "bulk-dedicated-ready-close",
@@ -892,6 +948,111 @@ func TestBulkReadWaitingLocalClosePrefersClosedPipeOverContextCanceled(t *testin
}
}
func TestBulkDefaultWriteContextDoesNotAddTimer(t *testing.T) {
parent := context.Background()
ctx, cancel, err := bulkWriteContext(parent, 0)
if err != nil {
t.Fatalf("bulkWriteContext returned error: %v", err)
}
defer cancel()
if ctx != parent {
t.Fatal("zero WriteTimeout wrapped the parent context")
}
if _, ok := ctx.Deadline(); ok {
t.Fatal("zero WriteTimeout added a per-write deadline")
}
}
func TestBulkDefaultCloseContextIsBounded(t *testing.T) {
ctx, cancel := bulkCloseContext(context.Background(), 0)
defer cancel()
deadline, ok := ctx.Deadline()
if !ok {
t.Fatal("default bulk close context has no deadline")
}
remaining := time.Until(deadline)
if remaining < defaultBulkDataWriteTimeout-time.Second || remaining > defaultBulkDataWriteTimeout+time.Second {
t.Fatalf("default bulk close deadline remaining=%v, want about %v", remaining, defaultBulkDataWriteTimeout)
}
}
func TestBulkCloseWriteHonorsBulkContextCancellation(t *testing.T) {
parent, cancelParent := context.WithCancel(context.Background())
defer cancelParent()
closeStarted := make(chan struct{})
bulk := newBulkHandle(
parent,
nil,
clientFileScope(),
BulkOpenRequest{BulkID: "close-write-context-bound", DataID: 1},
0,
nil,
nil,
0,
func(ctx context.Context, _ *bulkHandle, _ bool) error {
close(closeStarted)
<-ctx.Done()
return ctx.Err()
},
nil,
nil,
nil,
nil,
)
done := make(chan error, 1)
go func() { done <- bulk.CloseWrite() }()
select {
case <-closeStarted:
case <-time.After(time.Second):
t.Fatal("bulk close notification did not start")
}
cancelParent()
select {
case err := <-done:
if !errors.Is(err, context.Canceled) {
t.Fatalf("Bulk.CloseWrite error=%v, want context canceled", err)
}
case <-time.After(time.Second):
t.Fatal("Bulk.CloseWrite ignored the canceled bulk context")
}
}
func TestBulkCloseAfterPeerEOFUsesBoundedCleanupContext(t *testing.T) {
closeCalled := false
bulk := newBulkHandle(
context.Background(),
nil,
clientFileScope(),
BulkOpenRequest{BulkID: "close-after-peer-eof", DataID: 1},
0,
nil,
nil,
0,
func(ctx context.Context, _ *bulkHandle, full bool) error {
if !full {
return errors.New("expected full close after peer EOF")
}
if err := ctx.Err(); err != nil {
return err
}
closeCalled = true
return nil
},
nil,
nil,
nil,
nil,
)
bulk.markPeerClosed()
if err := bulk.Close(); err != nil {
t.Fatalf("Bulk.Close after peer EOF failed: %v", err)
}
if !closeCalled {
t.Fatal("Bulk.Close skipped the final peer notification after EOF")
}
}
func TestBulkReleaseControlRoundTripTransport(t *testing.T) {
server := NewServer().(*ServerCommon)
if err := UseModernPSKServer(server, integrationSharedSecret, integrationModernPSKOptions()); err != nil {
@@ -951,7 +1112,7 @@ func TestBulkReleaseControlRoundTripTransport(t *testing.T) {
clientHandle.outboundInFlight = 1
clientHandle.mu.Unlock()
if err := sendBulkReleaseServerTransport(server, accepted.TransportConn, BulkReleaseRequest{
if err := sendBulkReleaseServerTransport(context.Background(), server, accepted.TransportConn, BulkReleaseRequest{
BulkID: serverHandle.ID(),
DataID: serverHandle.dataIDSnapshot(),
Bytes: chunkSize,
@@ -1549,6 +1710,43 @@ func TestBulkDedicatedClientFullCloseAfterCloseWriteDoesNotResetTCP(t *testing.T
}
}
func TestBulkCloseWriteUsesWriteTimeoutForControlNotification(t *testing.T) {
const timeout = 40 * time.Millisecond
bulk := newBulkHandle(
context.Background(),
nil,
clientFileScope(),
BulkOpenRequest{
BulkID: "close-write-timeout",
WriteTimeout: timeout,
Range: BulkRange{Length: 1},
},
0,
nil,
nil,
0,
func(ctx context.Context, _ *bulkHandle, _ bool) error {
<-ctx.Done()
return ctx.Err()
},
nil,
nil,
nil,
nil,
)
done := make(chan error, 1)
go func() { done <- bulk.CloseWrite() }()
select {
case err := <-done:
if !errors.Is(err, context.DeadlineExceeded) {
t.Fatalf("Bulk.CloseWrite error=%v, want deadline exceeded", err)
}
case <-time.After(time.Second):
t.Fatal("Bulk.CloseWrite remained blocked past WriteTimeout")
}
}
func TestBulkSharedConcurrentWritersWithSlowReceiver(t *testing.T) {
server := NewServer().(*ServerCommon)
if err := UseModernPSKServer(server, integrationSharedSecret, integrationModernPSKOptions()); err != nil {