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:
+105
-11
@@ -62,18 +62,72 @@ func TestWriteFullToConnSerializesConcurrentWriters(t *testing.T) {
|
||||
}
|
||||
}
|
||||
|
||||
func newTestBulkBatchSender(binding *transportBinding) *bulkBatchSender {
|
||||
return newTestBulkBatchSenderWithWriteTimeout(binding, nil)
|
||||
}
|
||||
|
||||
func newTestBulkBatchSenderWithWriteTimeout(binding *transportBinding, writeTimeout func() time.Duration) *bulkBatchSender {
|
||||
return newBulkBatchSender(binding, bulkBatchCodec{
|
||||
encodeSingle: func(frame bulkFastFrame) ([]byte, func(), error) {
|
||||
return append([]byte(nil), frame.Payload...), nil, nil
|
||||
},
|
||||
encodeBatch: func(frames []bulkFastFrame) ([]byte, func(), error) {
|
||||
payload, err := encodeBulkFastBatchPlain(frames)
|
||||
return payload, nil, err
|
||||
},
|
||||
}, writeTimeout)
|
||||
}
|
||||
|
||||
func newTestStreamBatchSender(binding *transportBinding, writeTimeout func() time.Duration) *streamBatchSender {
|
||||
return newStreamBatchSender(binding, streamBatchCodec{
|
||||
encodeSingle: func(frame streamFastDataFrame) ([]byte, error) {
|
||||
return encodeStreamFastFramePayload(frame)
|
||||
},
|
||||
encodeBatch: func(frames []streamFastDataFrame) ([]byte, error) {
|
||||
return encodeStreamFastBatchPlain(frames)
|
||||
},
|
||||
}, writeTimeout)
|
||||
}
|
||||
|
||||
func TestBulkBatchSenderRespectsWriteDeadlineWhenReceiverStalls(t *testing.T) {
|
||||
left, right := net.Pipe()
|
||||
defer left.Close()
|
||||
defer right.Close()
|
||||
|
||||
sender := newBulkBatchSender(newTransportBinding(left, stario.NewQueue()))
|
||||
ctx, cancel := context.WithTimeout(context.Background(), 50*time.Millisecond)
|
||||
defer cancel()
|
||||
sender := newTestBulkBatchSenderWithWriteTimeout(newTransportBinding(left, stario.NewQueue()), func() time.Duration {
|
||||
return 50 * time.Millisecond
|
||||
})
|
||||
|
||||
errCh := make(chan error, 1)
|
||||
go func() {
|
||||
errCh <- sender.submit(ctx, []byte("payload"))
|
||||
errCh <- sender.submitData(context.Background(), 1, 1, bulkFastPathVersionV1, []byte("payload"))
|
||||
}()
|
||||
|
||||
select {
|
||||
case err := <-errCh:
|
||||
if err == nil {
|
||||
t.Fatal("sender.submit should fail when receiver stalls")
|
||||
}
|
||||
if !isTimeoutLikeError(err) {
|
||||
t.Fatalf("sender.submit error = %v, want timeout-like error", err)
|
||||
}
|
||||
case <-time.After(time.Second):
|
||||
t.Fatal("sender.submit should not hang when receiver stalls")
|
||||
}
|
||||
}
|
||||
|
||||
func TestStreamBatchSenderRespectsBindingWriteDeadlineWhenReceiverStalls(t *testing.T) {
|
||||
left, right := net.Pipe()
|
||||
defer left.Close()
|
||||
defer right.Close()
|
||||
|
||||
sender := newTestStreamBatchSender(newTransportBinding(left, stario.NewQueue()), func() time.Duration {
|
||||
return 50 * time.Millisecond
|
||||
})
|
||||
|
||||
errCh := make(chan error, 1)
|
||||
go func() {
|
||||
errCh <- sender.submitData(context.Background(), 1, 1, streamFastPathVersionV2, []byte("payload"))
|
||||
}()
|
||||
|
||||
select {
|
||||
@@ -258,12 +312,12 @@ func TestWriteNetBuffersFullUnlockedUsesUnwrappedVectoredConn(t *testing.T) {
|
||||
func TestBulkBatchSenderSkipsQueuedCanceledRequest(t *testing.T) {
|
||||
conn := newBlockingPacketWriteConn()
|
||||
binding := newTransportBinding(conn, stario.NewQueue())
|
||||
sender := newBulkBatchSender(binding)
|
||||
sender := newTestBulkBatchSender(binding)
|
||||
defer sender.stop()
|
||||
|
||||
firstErrCh := make(chan error, 1)
|
||||
go func() {
|
||||
firstErrCh <- sender.submit(context.Background(), []byte("first"))
|
||||
firstErrCh <- sender.submitData(context.Background(), 1, 1, bulkFastPathVersionV1, []byte("first"))
|
||||
}()
|
||||
|
||||
select {
|
||||
@@ -275,7 +329,7 @@ func TestBulkBatchSenderSkipsQueuedCanceledRequest(t *testing.T) {
|
||||
ctx, cancel := context.WithCancel(context.Background())
|
||||
secondErrCh := make(chan error, 1)
|
||||
go func() {
|
||||
secondErrCh <- sender.submit(ctx, []byte("second"))
|
||||
secondErrCh <- sender.submitData(ctx, 1, 2, bulkFastPathVersionV1, []byte("second"))
|
||||
}()
|
||||
time.Sleep(20 * time.Millisecond)
|
||||
cancel()
|
||||
@@ -306,16 +360,48 @@ func TestBulkBatchSenderSkipsQueuedCanceledRequest(t *testing.T) {
|
||||
}
|
||||
}
|
||||
|
||||
func TestBulkBatchSenderDoesNotDirectSubmitShareableV2Data(t *testing.T) {
|
||||
sender := &bulkBatchSender{}
|
||||
req := bulkBatchRequest{
|
||||
frames: []bulkFastFrame{{
|
||||
Type: bulkFastPayloadTypeData,
|
||||
DataID: 1,
|
||||
Seq: 1,
|
||||
Payload: make([]byte, 256*1024),
|
||||
}},
|
||||
fastPathVersion: bulkFastPathVersionV2,
|
||||
}
|
||||
if sender.shouldDirectSubmit(req) {
|
||||
t.Fatal("shareable v2 shared bulk data should queue for super-batch instead of direct submit")
|
||||
}
|
||||
}
|
||||
|
||||
func TestBulkBatchSenderDirectSubmitsUnbatchableRequest(t *testing.T) {
|
||||
sender := &bulkBatchSender{}
|
||||
req := bulkBatchRequest{
|
||||
frames: []bulkFastFrame{{
|
||||
Type: bulkFastPayloadTypeRelease,
|
||||
DataID: 1,
|
||||
Seq: 0,
|
||||
Payload: []byte("rel"),
|
||||
}},
|
||||
fastPathVersion: bulkFastPathVersionV2,
|
||||
}
|
||||
if !sender.shouldDirectSubmit(req) {
|
||||
t.Fatal("unbatchable shared bulk control request should still direct submit")
|
||||
}
|
||||
}
|
||||
|
||||
func TestBulkBatchSenderReturnsFlushResultAfterStartedContextCancel(t *testing.T) {
|
||||
conn := newBlockingPacketWriteConn()
|
||||
binding := newTransportBinding(conn, stario.NewQueue())
|
||||
sender := newBulkBatchSender(binding)
|
||||
sender := newTestBulkBatchSender(binding)
|
||||
defer sender.stop()
|
||||
|
||||
ctx, cancel := context.WithCancel(context.Background())
|
||||
errCh := make(chan error, 1)
|
||||
go func() {
|
||||
errCh <- sender.submit(ctx, []byte("payload"))
|
||||
errCh <- sender.submitData(ctx, 1, 1, bulkFastPathVersionV1, []byte("payload"))
|
||||
}()
|
||||
|
||||
select {
|
||||
@@ -346,10 +432,18 @@ func TestBulkBatchSenderReturnsFlushResultAfterStartedContextCancel(t *testing.T
|
||||
|
||||
func TestTransportBindingStopBackgroundWorkersStopsSharedSender(t *testing.T) {
|
||||
binding := newTransportBinding(newBlockingPacketWriteConn(), stario.NewQueue())
|
||||
sender := binding.bulkBatchSenderSnapshot()
|
||||
sender := binding.bulkBatchSenderSnapshotWithCodec(bulkBatchCodec{
|
||||
encodeSingle: func(frame bulkFastFrame) ([]byte, func(), error) {
|
||||
return append([]byte(nil), frame.Payload...), nil, nil
|
||||
},
|
||||
encodeBatch: func(frames []bulkFastFrame) ([]byte, func(), error) {
|
||||
payload, err := encodeBulkFastBatchPlain(frames)
|
||||
return payload, nil, err
|
||||
},
|
||||
}, nil)
|
||||
binding.stopBackgroundWorkers()
|
||||
|
||||
err := sender.submit(context.Background(), []byte("payload"))
|
||||
err := sender.submitData(context.Background(), 1, 1, bulkFastPathVersionV1, []byte("payload"))
|
||||
if !errors.Is(err, errTransportDetached) {
|
||||
t.Fatalf("sender.submit after stop = %v, want %v", err, errTransportDetached)
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user