mirror of
https://github.com/refraction-networking/uquic.git
synced 2025-04-03 20:27:35 +03:00
Merge pull request #2538 from lucas-clemente/bundle-small-writes
bundle small writes on streams
This commit is contained in:
commit
1cd1c3f54d
2 changed files with 41 additions and 8 deletions
|
@ -117,13 +117,19 @@ func (s *sendStream) Write(p []byte) (int, error) {
|
|||
// When the user now calls Close(), this is much more likely to happen before we popped that last STREAM frame,
|
||||
// allowing us to set the FIN bit on that frame (instead of sending an empty STREAM frame with FIN).
|
||||
if s.canBufferStreamFrame() && len(s.dataForWriting) > 0 {
|
||||
f := wire.GetStreamFrame()
|
||||
f.Offset = s.writeOffset
|
||||
f.StreamID = s.streamID
|
||||
f.DataLenPresent = true
|
||||
f.Data = f.Data[:len(s.dataForWriting)]
|
||||
copy(f.Data, s.dataForWriting)
|
||||
s.nextFrame = f
|
||||
if s.nextFrame == nil {
|
||||
f := wire.GetStreamFrame()
|
||||
f.Offset = s.writeOffset
|
||||
f.StreamID = s.streamID
|
||||
f.DataLenPresent = true
|
||||
f.Data = f.Data[:len(s.dataForWriting)]
|
||||
copy(f.Data, s.dataForWriting)
|
||||
s.nextFrame = f
|
||||
} else {
|
||||
l := len(s.nextFrame.Data)
|
||||
s.nextFrame.Data = s.nextFrame.Data[:l+len(s.dataForWriting)]
|
||||
copy(s.nextFrame.Data[l:], s.dataForWriting)
|
||||
}
|
||||
s.dataForWriting = nil
|
||||
bytesWritten = len(p)
|
||||
copied = true
|
||||
|
@ -176,7 +182,11 @@ func (s *sendStream) Write(p []byte) (int, error) {
|
|||
}
|
||||
|
||||
func (s *sendStream) canBufferStreamFrame() bool {
|
||||
return s.nextFrame == nil && protocol.ByteCount(len(s.dataForWriting)) <= protocol.MaxReceivePacketSize
|
||||
var l protocol.ByteCount
|
||||
if s.nextFrame != nil {
|
||||
l = s.nextFrame.DataLen()
|
||||
}
|
||||
return l+protocol.ByteCount(len(s.dataForWriting)) <= protocol.MaxReceivePacketSize
|
||||
}
|
||||
|
||||
// popStreamFrame returns the next STREAM frame that is supposed to be sent on this stream
|
||||
|
|
|
@ -125,6 +125,29 @@ var _ = Describe("Send Stream", func() {
|
|||
Eventually(done).Should(BeClosed())
|
||||
})
|
||||
|
||||
It("bundles small writes", func() {
|
||||
done := make(chan struct{})
|
||||
go func() {
|
||||
defer GinkgoRecover()
|
||||
mockSender.EXPECT().onHasStreamData(streamID).Times(2)
|
||||
n, err := strWithTimeout.Write([]byte("foo"))
|
||||
Expect(err).ToNot(HaveOccurred())
|
||||
Expect(n).To(Equal(3))
|
||||
n, err = strWithTimeout.Write([]byte("bar"))
|
||||
Expect(err).ToNot(HaveOccurred())
|
||||
Expect(n).To(Equal(3))
|
||||
close(done)
|
||||
}()
|
||||
Eventually(done).Should(BeClosed()) // both Write calls returned without any data having been dequeued yet
|
||||
mockFC.EXPECT().SendWindowSize().Return(protocol.MaxByteCount)
|
||||
mockFC.EXPECT().AddBytesSent(protocol.ByteCount(6))
|
||||
frame, _ := str.popStreamFrame(protocol.MaxByteCount)
|
||||
f := frame.Frame.(*wire.StreamFrame)
|
||||
Expect(f.Offset).To(BeZero())
|
||||
Expect(f.FinBit).To(BeFalse())
|
||||
Expect(f.Data).To(Equal([]byte("foobar")))
|
||||
})
|
||||
|
||||
It("writes and gets data in multiple turns, for large writes", func() {
|
||||
mockFC.EXPECT().SendWindowSize().Return(protocol.MaxByteCount).Times(5)
|
||||
var totalBytesSent protocol.ByteCount
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue