1
0
mirror of https://github.com/facebookincubator/mvfst.git synced 2025-08-08 09:42:06 +03:00

Optionally write one stream frame per packet.

Summary: It may be desirable for some applications to limit the number of streams written to a single packet, for example if they are treating streams like individual messages.

Reviewed By: yangchi

Differential Revision: D21067175

fbshipit-source-id: 75edcb1051bf7f1eb2c9b730806350f9857eabec
This commit is contained in:
Matt Joras
2020-04-16 13:13:59 -07:00
committed by Facebook GitHub Bot
parent 08f3316678
commit 93844d05fa
4 changed files with 83 additions and 4 deletions

View File

@@ -239,7 +239,8 @@ StreamId StreamFrameScheduler::writeStreamsHelper(
PacketBuilderInterface& builder, PacketBuilderInterface& builder,
const std::set<StreamId>& writableStreams, const std::set<StreamId>& writableStreams,
StreamId nextScheduledStream, StreamId nextScheduledStream,
uint64_t& connWritableBytes) { uint64_t& connWritableBytes,
bool streamPerPacket) {
MiddleStartingIterationWrapper wrapper(writableStreams, nextScheduledStream); MiddleStartingIterationWrapper wrapper(writableStreams, nextScheduledStream);
auto writableStreamItr = wrapper.cbegin(); auto writableStreamItr = wrapper.cbegin();
// This will write the stream frames in a round robin fashion ordered by // This will write the stream frames in a round robin fashion ordered by
@@ -250,6 +251,9 @@ StreamId StreamFrameScheduler::writeStreamsHelper(
while (writableStreamItr != wrapper.cend() && connWritableBytes > 0) { while (writableStreamItr != wrapper.cend() && connWritableBytes > 0) {
if (writeNextStreamFrame(builder, *writableStreamItr, connWritableBytes)) { if (writeNextStreamFrame(builder, *writableStreamItr, connWritableBytes)) {
writableStreamItr++; writableStreamItr++;
if (streamPerPacket) {
break;
}
} else { } else {
break; break;
} }
@@ -271,7 +275,8 @@ void StreamFrameScheduler::writeStreams(PacketBuilderInterface& builder) {
builder, builder,
writableControlStreams, writableControlStreams,
conn_.schedulingState.nextScheduledControlStream, conn_.schedulingState.nextScheduledControlStream,
connWritableBytes); connWritableBytes,
conn_.transportSettings.streamFramePerPacket);
} }
if (connWritableBytes == 0) { if (connWritableBytes == 0) {
return; return;
@@ -282,7 +287,8 @@ void StreamFrameScheduler::writeStreams(PacketBuilderInterface& builder) {
builder, builder,
writableStreams, writableStreams,
conn_.schedulingState.nextScheduledStream, conn_.schedulingState.nextScheduledStream,
connWritableBytes); connWritableBytes,
conn_.transportSettings.streamFramePerPacket);
} }
} // namespace quic } // namespace quic

View File

@@ -170,7 +170,8 @@ class StreamFrameScheduler {
PacketBuilderInterface& builder, PacketBuilderInterface& builder,
const std::set<StreamId>& writableStreams, const std::set<StreamId>& writableStreams,
StreamId nextScheduledStream, StreamId nextScheduledStream,
uint64_t& connWritableBytes); uint64_t& connWritableBytes,
bool streamPerPacket);
using WritableStreamItr = using WritableStreamItr =
MiddleStartingIterationWrapper::MiddleStartingIterator; MiddleStartingIterationWrapper::MiddleStartingIterator;

View File

@@ -776,6 +776,75 @@ TEST_F(QuicPacketSchedulerTest, StreamFrameSchedulerRoundRobin) {
EXPECT_EQ(*frames[2].asWriteStreamFrame(), f3); EXPECT_EQ(*frames[2].asWriteStreamFrame(), f3);
} }
TEST_F(QuicPacketSchedulerTest, StreamFrameSchedulerRoundRobinStreamPerPacket) {
QuicClientConnectionState conn(
FizzClientQuicHandshakeContext::Builder().build());
conn.streamManager->setMaxLocalBidirectionalStreams(10);
conn.flowControlState.peerAdvertisedMaxOffset = 100000;
conn.flowControlState.peerAdvertisedInitialMaxStreamOffsetBidiRemote = 100000;
conn.transportSettings.streamFramePerPacket = true;
auto connId = getTestConnectionId();
StreamFrameScheduler scheduler(conn);
ShortHeader shortHeader1(
ProtectionType::KeyPhaseZero,
connId,
getNextPacketNum(conn, PacketNumberSpace::AppData));
RegularQuicPacketBuilder builder1(
conn.udpSendPacketLen,
std::move(shortHeader1),
conn.ackStates.appDataAckState.largestAckedByPeer);
auto stream1 =
conn.streamManager->createNextBidirectionalStream().value()->id;
auto stream2 =
conn.streamManager->createNextBidirectionalStream().value()->id;
auto stream3 =
conn.streamManager->createNextBidirectionalStream().value()->id;
auto largeBuf = folly::IOBuf::createChain(conn.udpSendPacketLen * 2, 4096);
auto curBuf = largeBuf.get();
do {
curBuf->append(curBuf->capacity());
curBuf = curBuf->next();
} while (curBuf != largeBuf.get());
auto chainLen = largeBuf->computeChainDataLength();
writeDataToQuicStream(
*conn.streamManager->findStream(stream1), std::move(largeBuf), false);
writeDataToQuicStream(
*conn.streamManager->findStream(stream2),
folly::IOBuf::copyBuffer("some data"),
false);
writeDataToQuicStream(
*conn.streamManager->findStream(stream3),
folly::IOBuf::copyBuffer("some data"),
false);
// Force the wraparound initially.
conn.schedulingState.nextScheduledStream = stream3 + 8;
scheduler.writeStreams(builder1);
EXPECT_EQ(conn.schedulingState.nextScheduledStream, 4);
// Should write frames for stream2, stream3, followed by stream1 again.
NiceMock<MockQuicPacketBuilder> builder2;
EXPECT_CALL(builder2, remainingSpaceInPkt()).WillRepeatedly(Return(4096));
EXPECT_CALL(builder2, appendFrame(_)).WillRepeatedly(Invoke([&](auto f) {
builder2.frames_.push_back(f);
}));
auto& frames = builder2.frames_;
scheduler.writeStreams(builder2);
ASSERT_EQ(frames.size(), 1);
scheduler.writeStreams(builder2);
ASSERT_EQ(frames.size(), 2);
scheduler.writeStreams(builder2);
ASSERT_EQ(frames.size(), 3);
WriteStreamFrame f1(stream2, 0, 9, false);
WriteStreamFrame f2(stream3, 0, 9, false);
WriteStreamFrame f3(stream1, 0, chainLen, false);
ASSERT_TRUE(frames[0].asWriteStreamFrame());
EXPECT_EQ(*frames[0].asWriteStreamFrame(), f1);
ASSERT_TRUE(frames[1].asWriteStreamFrame());
EXPECT_EQ(*frames[1].asWriteStreamFrame(), f2);
ASSERT_TRUE(frames[2].asWriteStreamFrame());
EXPECT_EQ(*frames[2].asWriteStreamFrame(), f3);
}
TEST_F(QuicPacketSchedulerTest, StreamFrameSchedulerRoundRobinControl) { TEST_F(QuicPacketSchedulerTest, StreamFrameSchedulerRoundRobinControl) {
QuicClientConnectionState conn( QuicClientConnectionState conn(
FizzClientQuicHandshakeContext::Builder().build()); FizzClientQuicHandshakeContext::Builder().build());

View File

@@ -168,6 +168,9 @@ struct TransportSettings {
// A temporary type to control DataPath write style. Will be gone after we // A temporary type to control DataPath write style. Will be gone after we
// are done with experiment. // are done with experiment.
DataPathType dataPathType{DataPathType::ChainedMemory}; DataPathType dataPathType{DataPathType::ChainedMemory};
// Whether or not we should stop writing a packet after writing a single
// stream frame to it.
bool streamFramePerPacket{false};
}; };
} // namespace quic } // namespace quic