fix: close stream adaptive gaps and switch notify to stario v0.1.1

- make stream fast path honor adaptive soft payload limits end-to-end
  - split oversized fast-stream payloads into sequential frames before batching
  - use adaptive soft cap when encoding stream batch payloads
  - move timeout-like error detection into production code for adaptive tx
  - tune notify FrameReader read size explicitly to avoid throughput regression
  - drop local stario replace and depend on released b612.me/stario v0.1.1
This commit is contained in:
2026-04-18 16:05:57 +08:00
parent 4f760f2807
commit f038a89771
76 changed files with 12656 additions and 906 deletions
+172
View File
@@ -37,6 +37,45 @@ func TestGetClientRuntimeSnapshotDefaults(t *testing.T) {
if snapshot.ConnectSource != "" || snapshot.ConnectNetwork != "" || snapshot.ConnectAddress != "" || snapshot.CanReconnect {
t.Fatalf("unexpected default connect source snapshot: %+v", snapshot)
}
if got, want := snapshot.BulkNetworkProfile, "default"; got != want {
t.Fatalf("BulkNetworkProfile mismatch: got %q want %q", got, want)
}
if got, want := snapshot.BulkDefaultMode, "shared"; got != want {
t.Fatalf("BulkDefaultMode mismatch: got %q want %q", got, want)
}
if got, want := snapshot.BulkChunkSize, defaultBulkChunkSize; got != want {
t.Fatalf("BulkChunkSize mismatch: got %d want %d", got, want)
}
if got, want := snapshot.BulkWindowBytes, defaultBulkOpenWindowBytes; got != want {
t.Fatalf("BulkWindowBytes mismatch: got %d want %d", got, want)
}
if got, want := snapshot.BulkMaxInFlight, defaultBulkOpenMaxInFlight; got != want {
t.Fatalf("BulkMaxInFlight mismatch: got %d want %d", got, want)
}
if got, want := snapshot.BulkAttachLimit, defaultBulkDedicatedAttachLimit; got != want {
t.Fatalf("BulkAttachLimit mismatch: got %d want %d", got, want)
}
if got, want := snapshot.BulkActiveLimit, defaultBulkDedicatedActiveLimit; got != want {
t.Fatalf("BulkActiveLimit mismatch: got %d want %d", got, want)
}
if got, want := snapshot.BulkLaneLimit, defaultBulkDedicatedLaneLimit; got != want {
t.Fatalf("BulkLaneLimit mismatch: got %d want %d", got, want)
}
if snapshot.BulkAttachAttempts != 0 || snapshot.BulkAttachRetries != 0 || snapshot.BulkAttachSuccess != 0 || snapshot.BulkAutoFallbacks != 0 {
t.Fatalf("unexpected default bulk attach counters: %+v", snapshot)
}
if snapshot.TransportBulkAdaptiveSoftPayloadBytes != 0 {
t.Fatalf("TransportBulkAdaptiveSoftPayloadBytes mismatch: got %d want 0", snapshot.TransportBulkAdaptiveSoftPayloadBytes)
}
if snapshot.TransportStreamAdaptiveSoftPayloadBytes != 0 {
t.Fatalf("TransportStreamAdaptiveSoftPayloadBytes mismatch: got %d want 0", snapshot.TransportStreamAdaptiveSoftPayloadBytes)
}
if snapshot.TransportStreamAdaptiveWaitThresholdBytes != 0 {
t.Fatalf("TransportStreamAdaptiveWaitThresholdBytes mismatch: got %d want 0", snapshot.TransportStreamAdaptiveWaitThresholdBytes)
}
if snapshot.TransportStreamAdaptiveFlushDelay != 0 {
t.Fatalf("TransportStreamAdaptiveFlushDelay mismatch: got %s want 0", snapshot.TransportStreamAdaptiveFlushDelay)
}
if snapshot.Retry != (ConnectionRetrySnapshot{}) {
t.Fatalf("Retry snapshot mismatch: %+v", snapshot.Retry)
}
@@ -78,11 +117,144 @@ func TestGetServerRuntimeSnapshotDefaults(t *testing.T) {
if !snapshot.HasRuntimeStopCtx {
t.Fatalf("HasRuntimeStopCtx mismatch: got %v want true", snapshot.HasRuntimeStopCtx)
}
if got, want := snapshot.BulkChunkSize, defaultBulkChunkSize; got != want {
t.Fatalf("BulkChunkSize mismatch: got %d want %d", got, want)
}
if got, want := snapshot.BulkWindowBytes, defaultBulkOpenWindowBytes; got != want {
t.Fatalf("BulkWindowBytes mismatch: got %d want %d", got, want)
}
if got, want := snapshot.BulkMaxInFlight, defaultBulkOpenMaxInFlight; got != want {
t.Fatalf("BulkMaxInFlight mismatch: got %d want %d", got, want)
}
if snapshot.Retry != (ConnectionRetrySnapshot{}) {
t.Fatalf("Retry snapshot mismatch: %+v", snapshot.Retry)
}
}
func TestGetClientRuntimeSnapshotIncludesBulkAttachStats(t *testing.T) {
client := NewClient().(*ClientCommon)
client.SetBulkNetworkProfile(BulkNetworkProfileWAN)
client.SetBulkDefaultOpenMode(BulkOpenModeAuto)
client.bulkAttachAttemptCount.Store(11)
client.bulkAttachRetryCount.Store(5)
client.bulkAttachSuccessCount.Store(6)
client.bulkAttachFallbackCount.Store(3)
snapshot, err := GetClientRuntimeSnapshot(client)
if err != nil {
t.Fatalf("GetClientRuntimeSnapshot failed: %v", err)
}
if got, want := snapshot.BulkNetworkProfile, "wan"; got != want {
t.Fatalf("BulkNetworkProfile mismatch: got %q want %q", got, want)
}
if got, want := snapshot.BulkDefaultMode, "auto"; got != want {
t.Fatalf("BulkDefaultMode mismatch: got %q want %q", got, want)
}
if got, want := snapshot.BulkChunkSize, 512*1024; got != want {
t.Fatalf("BulkChunkSize mismatch: got %d want %d", got, want)
}
if got, want := snapshot.BulkWindowBytes, 8*1024*1024; got != want {
t.Fatalf("BulkWindowBytes mismatch: got %d want %d", got, want)
}
if got, want := snapshot.BulkMaxInFlight, 16; got != want {
t.Fatalf("BulkMaxInFlight mismatch: got %d want %d", got, want)
}
if got, want := snapshot.BulkAttachLimit, 2; got != want {
t.Fatalf("BulkAttachLimit mismatch: got %d want %d", got, want)
}
if got, want := snapshot.BulkActiveLimit, 4096; got != want {
t.Fatalf("BulkActiveLimit mismatch: got %d want %d", got, want)
}
if got, want := snapshot.BulkLaneLimit, 2; got != want {
t.Fatalf("BulkLaneLimit mismatch: got %d want %d", got, want)
}
if got, want := snapshot.BulkAttachAttempts, int64(11); got != want {
t.Fatalf("BulkAttachAttempts mismatch: got %d want %d", got, want)
}
if got, want := snapshot.BulkAttachRetries, int64(5); got != want {
t.Fatalf("BulkAttachRetries mismatch: got %d want %d", got, want)
}
if got, want := snapshot.BulkAttachSuccess, int64(6); got != want {
t.Fatalf("BulkAttachSuccess mismatch: got %d want %d", got, want)
}
if got, want := snapshot.BulkAutoFallbacks, int64(3); got != want {
t.Fatalf("BulkAutoFallbacks mismatch: got %d want %d", got, want)
}
}
func TestGetClientRuntimeSnapshotIncludesAdaptiveBulkSoftPayload(t *testing.T) {
client := NewClient().(*ClientCommon)
stopCtx, stopFn := context.WithCancel(context.Background())
defer stopFn()
queue := stario.NewQueueCtx(stopCtx, 4, math.MaxUint32)
left, right := net.Pipe()
defer left.Close()
defer right.Close()
binding := newTransportBinding(left, queue)
binding.observeBulkAdaptivePayloadWrite(8*1024*1024, 640*time.Millisecond, 0, nil)
client.setClientSessionRuntime(&clientSessionRuntime{
transport: binding,
stopCtx: stopCtx,
stopFn: stopFn,
queue: queue,
epoch: 1,
})
client.markSessionStarted()
snapshot, err := GetClientRuntimeSnapshot(client)
if err != nil {
t.Fatalf("GetClientRuntimeSnapshot failed: %v", err)
}
if got, want := snapshot.TransportBulkAdaptiveSoftPayloadBytes, bulkAdaptiveSoftPayloadMinBytes; got != want {
t.Fatalf("TransportBulkAdaptiveSoftPayloadBytes mismatch: got %d want %d", got, want)
}
if got, want := snapshot.TransportStreamAdaptiveSoftPayloadBytes, streamAdaptiveSoftPayloadStartBytes; got != want {
t.Fatalf("TransportStreamAdaptiveSoftPayloadBytes mismatch: got %d want %d", got, want)
}
if got, want := snapshot.TransportStreamAdaptiveWaitThresholdBytes, streamBatchWaitThreshold; got != want {
t.Fatalf("TransportStreamAdaptiveWaitThresholdBytes mismatch: got %d want %d", got, want)
}
if got, want := snapshot.TransportStreamAdaptiveFlushDelay, streamBatchMaxFlushDelay; got != want {
t.Fatalf("TransportStreamAdaptiveFlushDelay mismatch: got %s want %s", got, want)
}
}
func TestGetClientRuntimeSnapshotIncludesAdaptiveStreamTuning(t *testing.T) {
client := NewClient().(*ClientCommon)
stopCtx, stopFn := context.WithCancel(context.Background())
defer stopFn()
queue := stario.NewQueueCtx(stopCtx, 4, math.MaxUint32)
left, right := net.Pipe()
defer left.Close()
defer right.Close()
binding := newTransportBinding(left, queue)
binding.observeStreamAdaptivePayloadWrite(2*1024*1024, 640*time.Millisecond, 0, nil)
client.setClientSessionRuntime(&clientSessionRuntime{
transport: binding,
stopCtx: stopCtx,
stopFn: stopFn,
queue: queue,
epoch: 1,
})
client.markSessionStarted()
snapshot, err := GetClientRuntimeSnapshot(client)
if err != nil {
t.Fatalf("GetClientRuntimeSnapshot failed: %v", err)
}
if got, want := snapshot.TransportStreamAdaptiveSoftPayloadBytes, streamAdaptiveSoftPayloadMinBytes; got != want {
t.Fatalf("TransportStreamAdaptiveSoftPayloadBytes mismatch: got %d want %d", got, want)
}
if got, want := snapshot.TransportStreamAdaptiveWaitThresholdBytes, streamAdaptiveWaitThresholdMinBytes; got != want {
t.Fatalf("TransportStreamAdaptiveWaitThresholdBytes mismatch: got %d want %d", got, want)
}
if got := snapshot.TransportStreamAdaptiveFlushDelay; got != 0 {
t.Fatalf("TransportStreamAdaptiveFlushDelay mismatch: got %s want 0", got)
}
}
func TestGetRuntimeSnapshotRejectsNil(t *testing.T) {
if _, err := GetClientRuntimeSnapshot(nil); !errors.Is(err, errClientRuntimeSnapshotNil) {
t.Fatalf("GetClientRuntimeSnapshot nil error = %v, want %v", err, errClientRuntimeSnapshotNil)