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

Add stream prioritization

Summary: Adds a top level API to set stream priorities, mirroring what is currently proposed in httpbis.  For now, default all streams to the highest urgency, round-robin, which mirrors the current behavior in mvfst.

Reviewed By: mjoras

Differential Revision: D20318260

fbshipit-source-id: eec625e2ab641f7fa6266517776a2ca9798e8f89
This commit is contained in:
Yang Chi
2020-11-10 20:06:48 -08:00
committed by Facebook GitHub Bot
parent e2269b49f6
commit 000a0e23ca
17 changed files with 642 additions and 141 deletions

View File

@@ -1068,7 +1068,7 @@ TEST_F(QuicPacketSchedulerTest, StreamFrameSchedulerAllFit) {
folly::IOBuf::copyBuffer("some data"),
false);
scheduler.writeStreams(builder);
EXPECT_EQ(conn.schedulingState.nextScheduledStream, 0);
EXPECT_EQ(conn.streamManager->writableStreams().getNextScheduledStream(), 0);
}
TEST_F(QuicPacketSchedulerTest, StreamFrameSchedulerRoundRobin) {
@@ -1112,9 +1112,8 @@ TEST_F(QuicPacketSchedulerTest, StreamFrameSchedulerRoundRobin) {
folly::IOBuf::copyBuffer("some data"),
false);
// Force the wraparound initially.
conn.schedulingState.nextScheduledStream = stream3 + 8;
scheduler.writeStreams(builder);
EXPECT_EQ(conn.schedulingState.nextScheduledStream, 4);
EXPECT_EQ(conn.streamManager->writableStreams().getNextScheduledStream(), 4);
// Should write frames for stream2, stream3, followed by stream1 again.
NiceMock<MockQuicPacketBuilder> builder2;
@@ -1176,10 +1175,10 @@ TEST_F(QuicPacketSchedulerTest, StreamFrameSchedulerRoundRobinStreamPerPacket) {
*conn.streamManager->findStream(stream3),
folly::IOBuf::copyBuffer("some data"),
false);
// Force the wraparound initially.
conn.schedulingState.nextScheduledStream = stream3 + 8;
// The default is to wraparound initially.
scheduler.writeStreams(builder1);
EXPECT_EQ(conn.schedulingState.nextScheduledStream, 4);
EXPECT_EQ(
conn.streamManager->writableStreams().getNextScheduledStream(), stream2);
// Should write frames for stream2, stream3, followed by stream1 again.
NiceMock<MockQuicPacketBuilder> builder2;
@@ -1205,6 +1204,75 @@ TEST_F(QuicPacketSchedulerTest, StreamFrameSchedulerRoundRobinStreamPerPacket) {
EXPECT_EQ(*frames[2].asWriteStreamFrame(), f3);
}
TEST_F(QuicPacketSchedulerTest, StreamFrameSchedulerSequential) {
QuicClientConnectionState conn(
FizzClientQuicHandshakeContext::Builder().build());
conn.streamManager->setMaxLocalBidirectionalStreams(10);
conn.flowControlState.peerAdvertisedMaxOffset = 100000;
conn.flowControlState.peerAdvertisedInitialMaxStreamOffsetBidiRemote = 100000;
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.value_or(0));
auto stream1 =
conn.streamManager->createNextBidirectionalStream().value()->id;
auto stream2 =
conn.streamManager->createNextBidirectionalStream().value()->id;
auto stream3 =
conn.streamManager->createNextBidirectionalStream().value()->id;
conn.streamManager->findStream(stream1)->priority = Priority(0, false);
conn.streamManager->findStream(stream2)->priority = Priority(0, false);
conn.streamManager->findStream(stream3)->priority = Priority(0, false);
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);
// The default is to wraparound initially.
scheduler.writeStreams(builder1);
EXPECT_EQ(
conn.streamManager->writableStreams().getNextScheduledStream(
Priority(0, false)),
stream1);
// Should write frames for stream1, stream2, stream3, in that order.
NiceMock<MockQuicPacketBuilder> builder2;
EXPECT_CALL(builder2, remainingSpaceInPkt()).WillRepeatedly(Return(4096));
EXPECT_CALL(builder2, appendFrame(_)).WillRepeatedly(Invoke([&](auto f) {
builder2.frames_.push_back(f);
}));
scheduler.writeStreams(builder2);
auto& frames = builder2.frames_;
ASSERT_EQ(frames.size(), 3);
WriteStreamFrame f1(stream1, 0, chainLen, false);
WriteStreamFrame f2(stream2, 0, 9, false);
WriteStreamFrame f3(stream3, 0, 9, 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) {
QuicClientConnectionState conn(
FizzClientQuicHandshakeContext::Builder().build());
@@ -1255,10 +1323,10 @@ TEST_F(QuicPacketSchedulerTest, StreamFrameSchedulerRoundRobinControl) {
*conn.streamManager->findStream(stream4),
folly::IOBuf::copyBuffer("some data"),
false);
// Force the wraparound initially.
conn.schedulingState.nextScheduledStream = stream4 + 8;
// The default is to wraparound initially.
scheduler.writeStreams(builder);
EXPECT_EQ(conn.schedulingState.nextScheduledStream, stream3);
EXPECT_EQ(
conn.streamManager->writableStreams().getNextScheduledStream(), stream3);
EXPECT_EQ(conn.schedulingState.nextScheduledControlStream, stream2);
// Should write frames for stream2, stream4, followed by stream 3 then 1.
@@ -1283,7 +1351,8 @@ TEST_F(QuicPacketSchedulerTest, StreamFrameSchedulerRoundRobinControl) {
ASSERT_TRUE(frames[3].asWriteStreamFrame());
EXPECT_EQ(*frames[3].asWriteStreamFrame(), f4);
EXPECT_EQ(conn.schedulingState.nextScheduledStream, stream3);
EXPECT_EQ(
conn.streamManager->writableStreams().getNextScheduledStream(), stream3);
EXPECT_EQ(conn.schedulingState.nextScheduledControlStream, stream2);
}
@@ -1307,7 +1376,7 @@ TEST_F(QuicPacketSchedulerTest, StreamFrameSchedulerOneStream) {
auto stream1 = conn.streamManager->createNextBidirectionalStream().value();
writeDataToQuicStream(*stream1, folly::IOBuf::copyBuffer("some data"), false);
scheduler.writeStreams(builder);
EXPECT_EQ(conn.schedulingState.nextScheduledStream, 0);
EXPECT_EQ(conn.streamManager->writableStreams().getNextScheduledStream(), 0);
}
TEST_F(QuicPacketSchedulerTest, StreamFrameSchedulerRemoveOne) {
@@ -1344,8 +1413,8 @@ TEST_F(QuicPacketSchedulerTest, StreamFrameSchedulerRemoveOne) {
// Manually remove a stream and set the next scheduled to that stream.
builder.frames_.clear();
conn.streamManager->writableStreams().setNextScheduledStream(stream2);
conn.streamManager->removeWritable(*conn.streamManager->findStream(stream2));
conn.schedulingState.nextScheduledStream = stream2;
scheduler.writeStreams(builder);
ASSERT_EQ(builder.frames_.size(), 1);
ASSERT_TRUE(builder.frames_[0].asWriteStreamFrame());