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

Store stream state in F14FastMap

Summary: `F14FastMap` is faster than `F14NodeMap` as it requires one fewer allocations. We don't need the reference stability of `F14NodeMap`. We need to make the `QuicStreamLike` movable to use it.

Reviewed By: siyengar

Differential Revision: D18681242

fbshipit-source-id: e155d0bdec905c6a2f42d7169741c130bc9cc86d
This commit is contained in:
Matt Joras
2019-11-26 09:54:44 -08:00
committed by Facebook Github Bot
parent 49ade0aa75
commit cc73527122
5 changed files with 126 additions and 51 deletions

View File

@@ -715,12 +715,24 @@ TEST_F(QuicPacketSchedulerTest, StreamFrameSchedulerAllFit) {
conn.udpSendPacketLen, conn.udpSendPacketLen,
std::move(shortHeader), std::move(shortHeader),
conn.ackStates.appDataAckState.largestAckedByPeer); conn.ackStates.appDataAckState.largestAckedByPeer);
auto stream1 = conn.streamManager->createNextBidirectionalStream().value(); auto stream1 =
auto stream2 = conn.streamManager->createNextBidirectionalStream().value(); conn.streamManager->createNextBidirectionalStream().value()->id;
auto stream3 = conn.streamManager->createNextBidirectionalStream().value(); auto stream2 =
writeDataToQuicStream(*stream1, folly::IOBuf::copyBuffer("some data"), false); conn.streamManager->createNextBidirectionalStream().value()->id;
writeDataToQuicStream(*stream2, folly::IOBuf::copyBuffer("some data"), false); auto stream3 =
writeDataToQuicStream(*stream3, folly::IOBuf::copyBuffer("some data"), false); conn.streamManager->createNextBidirectionalStream().value()->id;
writeDataToQuicStream(
*conn.streamManager->findStream(stream1),
folly::IOBuf::copyBuffer("some data"),
false);
writeDataToQuicStream(
*conn.streamManager->findStream(stream2),
folly::IOBuf::copyBuffer("some data"),
false);
writeDataToQuicStream(
*conn.streamManager->findStream(stream3),
folly::IOBuf::copyBuffer("some data"),
false);
scheduler.writeStreams(builder); scheduler.writeStreams(builder);
EXPECT_EQ(conn.schedulingState.nextScheduledStream, 0); EXPECT_EQ(conn.schedulingState.nextScheduledStream, 0);
} }
@@ -741,9 +753,12 @@ TEST_F(QuicPacketSchedulerTest, StreamFrameSchedulerRoundRobin) {
conn.udpSendPacketLen, conn.udpSendPacketLen,
std::move(shortHeader1), std::move(shortHeader1),
conn.ackStates.appDataAckState.largestAckedByPeer); conn.ackStates.appDataAckState.largestAckedByPeer);
auto stream1 = conn.streamManager->createNextBidirectionalStream().value(); auto stream1 =
auto stream2 = conn.streamManager->createNextBidirectionalStream().value(); conn.streamManager->createNextBidirectionalStream().value()->id;
auto stream3 = conn.streamManager->createNextBidirectionalStream().value(); auto stream2 =
conn.streamManager->createNextBidirectionalStream().value()->id;
auto stream3 =
conn.streamManager->createNextBidirectionalStream().value()->id;
auto largeBuf = folly::IOBuf::createChain(conn.udpSendPacketLen * 2, 4096); auto largeBuf = folly::IOBuf::createChain(conn.udpSendPacketLen * 2, 4096);
auto curBuf = largeBuf.get(); auto curBuf = largeBuf.get();
do { do {
@@ -751,11 +766,18 @@ TEST_F(QuicPacketSchedulerTest, StreamFrameSchedulerRoundRobin) {
curBuf = curBuf->next(); curBuf = curBuf->next();
} while (curBuf != largeBuf.get()); } while (curBuf != largeBuf.get());
auto chainLen = largeBuf->computeChainDataLength(); auto chainLen = largeBuf->computeChainDataLength();
writeDataToQuicStream(*stream1, std::move(largeBuf), false); writeDataToQuicStream(
writeDataToQuicStream(*stream2, folly::IOBuf::copyBuffer("some data"), false); *conn.streamManager->findStream(stream1), std::move(largeBuf), false);
writeDataToQuicStream(*stream3, folly::IOBuf::copyBuffer("some data"), 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. // Force the wraparound initially.
conn.schedulingState.nextScheduledStream = stream3->id + 8; conn.schedulingState.nextScheduledStream = stream3 + 8;
scheduler.writeStreams(builder1); scheduler.writeStreams(builder1);
EXPECT_EQ(conn.schedulingState.nextScheduledStream, 4); EXPECT_EQ(conn.schedulingState.nextScheduledStream, 4);
@@ -768,9 +790,9 @@ TEST_F(QuicPacketSchedulerTest, StreamFrameSchedulerRoundRobin) {
scheduler.writeStreams(builder2); scheduler.writeStreams(builder2);
auto& frames = builder2.frames_; auto& frames = builder2.frames_;
ASSERT_EQ(frames.size(), 3); ASSERT_EQ(frames.size(), 3);
WriteStreamFrame f1(stream2->id, 0, 9, false); WriteStreamFrame f1(stream2, 0, 9, false);
WriteStreamFrame f2(stream3->id, 0, 9, false); WriteStreamFrame f2(stream3, 0, 9, false);
WriteStreamFrame f3(stream1->id, 0, chainLen, false); WriteStreamFrame f3(stream1, 0, chainLen, false);
ASSERT_TRUE(frames[0].asWriteStreamFrame()); ASSERT_TRUE(frames[0].asWriteStreamFrame());
EXPECT_EQ(*frames[0].asWriteStreamFrame(), f1); EXPECT_EQ(*frames[0].asWriteStreamFrame(), f1);
ASSERT_TRUE(frames[1].asWriteStreamFrame()); ASSERT_TRUE(frames[1].asWriteStreamFrame());
@@ -795,12 +817,18 @@ TEST_F(QuicPacketSchedulerTest, StreamFrameSchedulerRoundRobinControl) {
conn.udpSendPacketLen, conn.udpSendPacketLen,
std::move(shortHeader1), std::move(shortHeader1),
conn.ackStates.appDataAckState.largestAckedByPeer); conn.ackStates.appDataAckState.largestAckedByPeer);
auto stream1 = conn.streamManager->createNextBidirectionalStream().value(); auto stream1 =
auto stream2 = conn.streamManager->createNextBidirectionalStream().value(); conn.streamManager->createNextBidirectionalStream().value()->id;
auto stream3 = conn.streamManager->createNextBidirectionalStream().value(); auto stream2 =
auto stream4 = conn.streamManager->createNextBidirectionalStream().value(); conn.streamManager->createNextBidirectionalStream().value()->id;
conn.streamManager->setStreamAsControl(*stream2); auto stream3 =
conn.streamManager->setStreamAsControl(*stream4); conn.streamManager->createNextBidirectionalStream().value()->id;
auto stream4 =
conn.streamManager->createNextBidirectionalStream().value()->id;
conn.streamManager->setStreamAsControl(
*conn.streamManager->findStream(stream2));
conn.streamManager->setStreamAsControl(
*conn.streamManager->findStream(stream4));
auto largeBuf = folly::IOBuf::createChain(conn.udpSendPacketLen * 2, 4096); auto largeBuf = folly::IOBuf::createChain(conn.udpSendPacketLen * 2, 4096);
auto curBuf = largeBuf.get(); auto curBuf = largeBuf.get();
do { do {
@@ -808,15 +836,25 @@ TEST_F(QuicPacketSchedulerTest, StreamFrameSchedulerRoundRobinControl) {
curBuf = curBuf->next(); curBuf = curBuf->next();
} while (curBuf != largeBuf.get()); } while (curBuf != largeBuf.get());
auto chainLen = largeBuf->computeChainDataLength(); auto chainLen = largeBuf->computeChainDataLength();
writeDataToQuicStream(*stream1, std::move(largeBuf), false); writeDataToQuicStream(
writeDataToQuicStream(*stream2, folly::IOBuf::copyBuffer("some data"), false); *conn.streamManager->findStream(stream1), std::move(largeBuf), false);
writeDataToQuicStream(*stream3, folly::IOBuf::copyBuffer("some data"), false); writeDataToQuicStream(
writeDataToQuicStream(*stream4, folly::IOBuf::copyBuffer("some data"), false); *conn.streamManager->findStream(stream2),
folly::IOBuf::copyBuffer("some data"),
false);
writeDataToQuicStream(
*conn.streamManager->findStream(stream3),
folly::IOBuf::copyBuffer("some data"),
false);
writeDataToQuicStream(
*conn.streamManager->findStream(stream4),
folly::IOBuf::copyBuffer("some data"),
false);
// Force the wraparound initially. // Force the wraparound initially.
conn.schedulingState.nextScheduledStream = stream4->id + 8; conn.schedulingState.nextScheduledStream = stream4 + 8;
scheduler.writeStreams(builder1); scheduler.writeStreams(builder1);
EXPECT_EQ(conn.schedulingState.nextScheduledStream, stream3->id); EXPECT_EQ(conn.schedulingState.nextScheduledStream, stream3);
EXPECT_EQ(conn.schedulingState.nextScheduledControlStream, stream2->id); EXPECT_EQ(conn.schedulingState.nextScheduledControlStream, stream2);
// Should write frames for stream2, stream4, followed by stream 3 then 1. // Should write frames for stream2, stream4, followed by stream 3 then 1.
MockQuicPacketBuilder builder2; MockQuicPacketBuilder builder2;
@@ -827,10 +865,10 @@ TEST_F(QuicPacketSchedulerTest, StreamFrameSchedulerRoundRobinControl) {
scheduler.writeStreams(builder2); scheduler.writeStreams(builder2);
auto& frames = builder2.frames_; auto& frames = builder2.frames_;
ASSERT_EQ(frames.size(), 4); ASSERT_EQ(frames.size(), 4);
WriteStreamFrame f1(stream2->id, 0, 9, false); WriteStreamFrame f1(stream2, 0, 9, false);
WriteStreamFrame f2(stream4->id, 0, 9, false); WriteStreamFrame f2(stream4, 0, 9, false);
WriteStreamFrame f3(stream3->id, 0, 9, false); WriteStreamFrame f3(stream3, 0, 9, false);
WriteStreamFrame f4(stream1->id, 0, chainLen, false); WriteStreamFrame f4(stream1, 0, chainLen, false);
ASSERT_TRUE(frames[0].asWriteStreamFrame()); ASSERT_TRUE(frames[0].asWriteStreamFrame());
EXPECT_EQ(*frames[0].asWriteStreamFrame(), f1); EXPECT_EQ(*frames[0].asWriteStreamFrame(), f1);
ASSERT_TRUE(frames[1].asWriteStreamFrame()); ASSERT_TRUE(frames[1].asWriteStreamFrame());
@@ -840,8 +878,8 @@ TEST_F(QuicPacketSchedulerTest, StreamFrameSchedulerRoundRobinControl) {
ASSERT_TRUE(frames[3].asWriteStreamFrame()); ASSERT_TRUE(frames[3].asWriteStreamFrame());
EXPECT_EQ(*frames[3].asWriteStreamFrame(), f4); EXPECT_EQ(*frames[3].asWriteStreamFrame(), f4);
EXPECT_EQ(conn.schedulingState.nextScheduledStream, stream3->id); EXPECT_EQ(conn.schedulingState.nextScheduledStream, stream3);
EXPECT_EQ(conn.schedulingState.nextScheduledControlStream, stream2->id); EXPECT_EQ(conn.schedulingState.nextScheduledControlStream, stream2);
} }
TEST_F(QuicPacketSchedulerTest, StreamFrameSchedulerOneStream) { TEST_F(QuicPacketSchedulerTest, StreamFrameSchedulerOneStream) {
@@ -874,17 +912,25 @@ TEST_F(QuicPacketSchedulerTest, StreamFrameSchedulerRemoveOne) {
conn.flowControlState.peerAdvertisedInitialMaxStreamOffsetBidiRemote = 100000; conn.flowControlState.peerAdvertisedInitialMaxStreamOffsetBidiRemote = 100000;
StreamFrameScheduler scheduler(conn); StreamFrameScheduler scheduler(conn);
MockQuicPacketBuilder builder; MockQuicPacketBuilder builder;
auto stream1 = conn.streamManager->createNextBidirectionalStream().value(); auto stream1 =
auto stream2 = conn.streamManager->createNextBidirectionalStream().value(); conn.streamManager->createNextBidirectionalStream().value()->id;
writeDataToQuicStream(*stream1, folly::IOBuf::copyBuffer("some data"), false); auto stream2 =
writeDataToQuicStream(*stream2, folly::IOBuf::copyBuffer("some data"), false); conn.streamManager->createNextBidirectionalStream().value()->id;
writeDataToQuicStream(
*conn.streamManager->findStream(stream1),
folly::IOBuf::copyBuffer("some data"),
false);
writeDataToQuicStream(
*conn.streamManager->findStream(stream2),
folly::IOBuf::copyBuffer("some data"),
false);
EXPECT_CALL(builder, remainingSpaceInPkt()).WillRepeatedly(Return(4096)); EXPECT_CALL(builder, remainingSpaceInPkt()).WillRepeatedly(Return(4096));
EXPECT_CALL(builder, appendFrame(_)).WillRepeatedly(Invoke([&](auto f) { EXPECT_CALL(builder, appendFrame(_)).WillRepeatedly(Invoke([&](auto f) {
builder.frames_.push_back(f); builder.frames_.push_back(f);
})); }));
scheduler.writeStreams(builder); scheduler.writeStreams(builder);
WriteStreamFrame f1(stream1->id, 0, 9, false); WriteStreamFrame f1(stream1, 0, 9, false);
WriteStreamFrame f2(stream2->id, 0, 9, false); WriteStreamFrame f2(stream2, 0, 9, false);
ASSERT_TRUE(builder.frames_[0].asWriteStreamFrame()); ASSERT_TRUE(builder.frames_[0].asWriteStreamFrame());
EXPECT_EQ(*builder.frames_[0].asWriteStreamFrame(), f1); EXPECT_EQ(*builder.frames_[0].asWriteStreamFrame(), f1);
ASSERT_TRUE(builder.frames_[1].asWriteStreamFrame()); ASSERT_TRUE(builder.frames_[1].asWriteStreamFrame());
@@ -892,8 +938,8 @@ TEST_F(QuicPacketSchedulerTest, StreamFrameSchedulerRemoveOne) {
// Manually remove a stream and set the next scheduled to that stream. // Manually remove a stream and set the next scheduled to that stream.
builder.frames_.clear(); builder.frames_.clear();
conn.streamManager->removeWritable(*stream2); conn.streamManager->removeWritable(*conn.streamManager->findStream(stream2));
conn.schedulingState.nextScheduledStream = stream2->id; conn.schedulingState.nextScheduledStream = stream2;
scheduler.writeStreams(builder); scheduler.writeStreams(builder);
ASSERT_EQ(builder.frames_.size(), 1); ASSERT_EQ(builder.frames_.size(), 1);
ASSERT_TRUE(builder.frames_[0].asWriteStreamFrame()); ASSERT_TRUE(builder.frames_[0].asWriteStreamFrame());

View File

@@ -186,8 +186,12 @@ TEST_F(QuicTransportFunctionsTest, TestUpdateConnection) {
// Builds a fake packet to test with. // Builds a fake packet to test with.
auto packet = buildEmptyPacket(*conn, PacketNumberSpace::Handshake); auto packet = buildEmptyPacket(*conn, PacketNumberSpace::Handshake);
auto stream1 = conn->streamManager->createNextBidirectionalStream().value(); auto stream1Id =
auto stream2 = conn->streamManager->createNextBidirectionalStream().value(); conn->streamManager->createNextBidirectionalStream().value()->id;
auto stream2Id =
conn->streamManager->createNextBidirectionalStream().value()->id;
auto stream1 = conn->streamManager->findStream(stream1Id);
auto stream2 = conn->streamManager->findStream(stream2Id);
auto buf = IOBuf::copyBuffer("hey whats up"); auto buf = IOBuf::copyBuffer("hey whats up");
EXPECT_CALL(*transportInfoCb_, onPacketRetransmission()).Times(2); EXPECT_CALL(*transportInfoCb_, onPacketRetransmission()).Times(2);

View File

@@ -352,8 +352,12 @@ TEST_F(QuicLossFunctionsTest, TestMarkPacketLoss) {
MockAsyncUDPSocket socket(&evb); MockAsyncUDPSocket socket(&evb);
auto conn = createConn(); auto conn = createConn();
EXPECT_CALL(*transportInfoCb_, onNewQuicStream()).Times(2); EXPECT_CALL(*transportInfoCb_, onNewQuicStream()).Times(2);
auto stream1 = conn->streamManager->createNextBidirectionalStream().value(); auto stream1Id =
auto stream2 = conn->streamManager->createNextBidirectionalStream().value(); conn->streamManager->createNextBidirectionalStream().value()->id;
auto stream2Id =
conn->streamManager->createNextBidirectionalStream().value()->id;
auto stream1 = conn->streamManager->findStream(stream1Id);
auto stream2 = conn->streamManager->findStream(stream2Id);
auto buf = buildRandomInputData(20); auto buf = buildRandomInputData(20);
writeDataToQuicStream(*stream1, buf->clone(), true); writeDataToQuicStream(*stream1, buf->clone(), true);
writeDataToQuicStream(*stream2, buf->clone(), true); writeDataToQuicStream(*stream2, buf->clone(), true);
@@ -1248,14 +1252,18 @@ TEST_F(QuicLossFunctionsTest, TestMarkPacketLossProcessedPacket) {
auto conn = createConn(); auto conn = createConn();
ASSERT_TRUE(conn->outstandingPackets.empty()); ASSERT_TRUE(conn->outstandingPackets.empty());
ASSERT_TRUE(conn->outstandingPacketEvents.empty()); ASSERT_TRUE(conn->outstandingPacketEvents.empty());
auto stream1 = conn->streamManager->createNextBidirectionalStream().value(); auto stream1Id =
conn->streamManager->createNextBidirectionalStream().value()->id;
auto buf = folly::IOBuf::copyBuffer("I wrestled by the sea."); auto buf = folly::IOBuf::copyBuffer("I wrestled by the sea.");
auto stream2 = conn->streamManager->createNextBidirectionalStream().value(); auto stream2Id =
conn->streamManager->queueWindowUpdate(stream2->id); conn->streamManager->createNextBidirectionalStream().value()->id;
conn->streamManager->queueWindowUpdate(stream2Id);
conn->pendingEvents.connWindowUpdate = true; conn->pendingEvents.connWindowUpdate = true;
auto nextPacketNum = conn->ackStates.appDataAckState.nextPacketNum; auto nextPacketNum = conn->ackStates.appDataAckState.nextPacketNum;
// writeQuicPacket will call writeQuicDataToSocket which will also take care // writeQuicPacket will call writeQuicDataToSocket which will also take care
// of sending the MaxStreamDataFrame for stream2 // of sending the MaxStreamDataFrame for stream2
auto stream1 = conn->streamManager->findStream(stream1Id);
auto stream2 = conn->streamManager->findStream(stream2Id);
auto packet = writeQuicPacket( auto packet = writeQuicPacket(
*conn, *conn,
*conn->clientConnectionId, *conn->clientConnectionId,

View File

@@ -745,7 +745,7 @@ class QuicStreamManager {
folly::F14FastSet<StreamId> openUnidirectionalLocalStreams_; folly::F14FastSet<StreamId> openUnidirectionalLocalStreams_;
// A map of streams that are active. // A map of streams that are active.
folly::F14NodeMap<StreamId, QuicStreamState> streams_; folly::F14FastMap<StreamId, QuicStreamState> streams_;
// Recently opened peer streams. // Recently opened peer streams.
std::vector<StreamId> newPeerStreams_; std::vector<StreamId> newPeerStreams_;

View File

@@ -26,6 +26,21 @@ struct StreamBuffer {
}; };
struct QuicStreamLike { struct QuicStreamLike {
QuicStreamLike()
: readBuffer{},
writeBuffer{folly::IOBufQueue::cacheChainLength()},
retransmissionBuffer{},
ackedIntervals{},
lossBuffer{},
currentWriteOffset{},
minimumRetransmittableOffset{},
currentReadOffset{},
currentReceiveOffset{},
maxOffsetObserved{},
finalReadOffset{} {}
QuicStreamLike(QuicStreamLike&&) = default;
virtual ~QuicStreamLike() = default; virtual ~QuicStreamLike() = default;
// List of bytes that have been read and buffered. We need to buffer // List of bytes that have been read and buffered. We need to buffer
@@ -127,6 +142,8 @@ struct QuicStreamState : public QuicStreamLike {
QuicStreamState(StreamId id, QuicConnectionStateBase& conn); QuicStreamState(StreamId id, QuicConnectionStateBase& conn);
QuicStreamState(QuicStreamState&&) = default;
// Connection that this stream is associated with. // Connection that this stream is associated with.
QuicConnectionStateBase& conn; QuicConnectionStateBase& conn;