@@ -38,10 +38,11 @@ type Stream struct {
38
38
// the write will fail.
39
39
outgate gate
40
40
out pipe // buffered data to send
41
+ outflushed int64 // offset of last flush call
41
42
outwin int64 // maximum MAX_STREAM_DATA received from the peer
42
43
outmaxsent int64 // maximum data offset we've sent to the peer
43
44
outmaxbuf int64 // maximum amount of data we will buffer
44
- outunsent rangeset [int64 ] // ranges buffered but not yet sent
45
+ outunsent rangeset [int64 ] // ranges buffered but not yet sent (only flushed data)
45
46
outacked rangeset [int64 ] // ranges sent and acknowledged
46
47
outopened sentVal // set if we should open the stream
47
48
outclosed sentVal // set by CloseWrite
@@ -240,8 +241,6 @@ func (s *Stream) Write(b []byte) (n int, err error) {
240
241
// WriteContext writes data to the stream write buffer.
241
242
// Buffered data is only sent when the buffer is sufficiently full.
242
243
// Call the Flush method to ensure buffered data is sent.
243
- //
244
- // TODO: Implement Flush.
245
244
func (s * Stream ) WriteContext (ctx context.Context , b []byte ) (n int , err error ) {
246
245
if s .IsReadOnly () {
247
246
return 0 , errors .New ("write to read-only stream" )
@@ -269,10 +268,6 @@ func (s *Stream) WriteContext(ctx context.Context, b []byte) (n int, err error)
269
268
s .outUnlock ()
270
269
return n , errors .New ("write to closed stream" )
271
270
}
272
- // We set outopened here rather than below,
273
- // so if this is a zero-length write we still
274
- // open the stream despite not writing any data to it.
275
- s .outopened .set ()
276
271
if len (b ) == 0 {
277
272
break
278
273
}
@@ -282,13 +277,26 @@ func (s *Stream) WriteContext(ctx context.Context, b []byte) (n int, err error)
282
277
// Amount to write is min(the full buffer, data up to the write limit).
283
278
// This is a number of bytes.
284
279
nn := min (int64 (len (b )), lim - s .out .end )
285
- // Copy the data into the output buffer and mark it as unsent.
286
- if s .out .end <= s .outwin {
287
- s .outunsent .add (s .out .end , min (s .out .end + nn , s .outwin ))
288
- }
280
+ // Copy the data into the output buffer.
289
281
s .out .writeAt (b [:nn ], s .out .end )
290
282
b = b [nn :]
291
283
n += int (nn )
284
+ // Possibly flush the output buffer.
285
+ // We automatically flush if:
286
+ // - We have enough data to consume the send window.
287
+ // Sending this data may cause the peer to extend the window.
288
+ // - We have buffered as much data as we're willing do.
289
+ // We need to send data to clear out buffer space.
290
+ // - We have enough data to fill a 1-RTT packet using the smallest
291
+ // possible maximum datagram size (1200 bytes, less header byte,
292
+ // connection ID, packet number, and AEAD overhead).
293
+ const autoFlushSize = smallestMaxDatagramSize - 1 - connIDLen - 1 - aeadOverhead
294
+ shouldFlush := s .out .end >= s .outwin || // peer send window is full
295
+ s .out .end >= lim || // local send buffer is full
296
+ (s .out .end - s .outflushed ) >= autoFlushSize // enough data buffered
297
+ if shouldFlush {
298
+ s .flushLocked ()
299
+ }
292
300
if s .out .end > s .outwin {
293
301
// We're blocked by flow control.
294
302
// Send a STREAM_DATA_BLOCKED frame to let the peer know.
@@ -301,6 +309,23 @@ func (s *Stream) WriteContext(ctx context.Context, b []byte) (n int, err error)
301
309
return n , nil
302
310
}
303
311
312
+ // Flush flushes data written to the stream.
313
+ // It does not wait for the peer to acknowledge receipt of the data.
314
+ // Use CloseContext to wait for the peer's acknowledgement.
315
+ func (s * Stream ) Flush () {
316
+ s .outgate .lock ()
317
+ defer s .outUnlock ()
318
+ s .flushLocked ()
319
+ }
320
+
321
+ func (s * Stream ) flushLocked () {
322
+ s .outopened .set ()
323
+ if s .outflushed < s .outwin {
324
+ s .outunsent .add (s .outflushed , min (s .outwin , s .out .end ))
325
+ }
326
+ s .outflushed = s .out .end
327
+ }
328
+
304
329
// Close closes the stream.
305
330
// See CloseContext for more details.
306
331
func (s * Stream ) Close () error {
@@ -363,6 +388,7 @@ func (s *Stream) CloseWrite() {
363
388
s .outgate .lock ()
364
389
defer s .outUnlock ()
365
390
s .outclosed .set ()
391
+ s .flushLocked ()
366
392
}
367
393
368
394
// Reset aborts writes on the stream and notifies the peer
@@ -612,8 +638,8 @@ func (s *Stream) handleMaxStreamData(maxStreamData int64) error {
612
638
if maxStreamData <= s .outwin {
613
639
return nil
614
640
}
615
- if s .out . end > s .outwin {
616
- s .outunsent .add (s .outwin , min (maxStreamData , s .out . end ))
641
+ if s .outflushed > s .outwin {
642
+ s .outunsent .add (s .outwin , min (maxStreamData , s .outflushed ))
617
643
}
618
644
s .outwin = maxStreamData
619
645
if s .out .end > s .outwin {
@@ -741,10 +767,11 @@ func (s *Stream) appendOutFramesLocked(w *packetWriter, pnum packetNumber, pto b
741
767
}
742
768
for {
743
769
// STREAM
744
- off , size := dataToSend (min (s .out .start , s .outwin ), min (s .out . end , s .outwin ), s .outunsent , s .outacked , pto )
770
+ off , size := dataToSend (min (s .out .start , s .outwin ), min (s .outflushed , s .outwin ), s .outunsent , s .outacked , pto )
745
771
if end := off + size ; end > s .outmaxsent {
746
772
// This will require connection-level flow control to send.
747
773
end = min (end , s .outmaxsent + s .conn .streams .outflow .avail ())
774
+ end = max (end , off )
748
775
size = end - off
749
776
}
750
777
fin := s .outclosed .isSet () && off + size == s .out .end
0 commit comments