mirror of
https://github.com/facebookincubator/mvfst.git
synced 2025-08-06 22:22:38 +03:00
Count cumulative # of egress packets for a stream
Summary: There are situations where application needs to know how many packets were transmitted for a stream on certain byte range. This diff provides *some* level of that information, by adding the `cumulativeTxedPackets` field in `StreamLike`, which stores the number of egress packets that contain new STREAM frame(s) for a stream. ~~To prevent double-counting, I added a fast set of stream ids.~~ Application could rely on other callbacks (e.g. ByteEventCallback or DeliveryCallback) to get notified, and use `getStreamTransportInfo` to get `packetsTxed` for a stream. Reviewed By: bschlinker, mjoras Differential Revision: D23361789 fbshipit-source-id: 6624ddcbe9cf62c628f936eda2a39d0fc2781636
This commit is contained in:
committed by
Facebook GitHub Bot
parent
820f102401
commit
3fac7d21f4
@@ -3141,5 +3141,144 @@ TEST_F(QuicTransportTest, SaneCwndSettings) {
|
||||
conn.congestionController->getCongestionWindow());
|
||||
}
|
||||
|
||||
TEST_F(QuicTransportTest, GetStreamPackestTxedSingleByte) {
|
||||
StrictMock<MockByteEventCallback> firstByteTxCb;
|
||||
auto stream = transport_->createBidirectionalStream().value();
|
||||
|
||||
auto buf = buildRandomInputData(1);
|
||||
transport_->writeChain(
|
||||
stream, buf->clone(), false /* eof */, false /* cork */);
|
||||
transport_->registerTxCallback(stream, 0, &firstByteTxCb);
|
||||
|
||||
// when first byte TX callback gets invoked, numPacketsTxWithNewData should be
|
||||
// one
|
||||
EXPECT_CALL(firstByteTxCb, onByteEvent(getTxMatcher(stream, 0)))
|
||||
.Times(1)
|
||||
.WillOnce(Invoke([&](QuicSocket::ByteEvent /* event */) {
|
||||
auto info = *transport_->getStreamTransportInfo(stream);
|
||||
EXPECT_EQ(info.numPacketsTxWithNewData, 1);
|
||||
}));
|
||||
loopForWrites();
|
||||
Mock::VerifyAndClearExpectations(&firstByteTxCb);
|
||||
}
|
||||
|
||||
TEST_F(QuicTransportTest, GetStreamPacketsTxedMultipleBytes) {
|
||||
const uint64_t streamBytes = 10;
|
||||
const uint64_t lastByte = streamBytes - 1;
|
||||
|
||||
StrictMock<MockByteEventCallback> firstByteTxCb;
|
||||
StrictMock<MockByteEventCallback> lastByteTxCb;
|
||||
auto stream = transport_->createBidirectionalStream().value();
|
||||
|
||||
auto buf = buildRandomInputData(streamBytes);
|
||||
CHECK_EQ(streamBytes, buf->length());
|
||||
transport_->writeChain(
|
||||
stream, buf->clone(), false /* eof */, false /* cork */);
|
||||
transport_->registerTxCallback(stream, 0, &firstByteTxCb);
|
||||
transport_->registerTxCallback(stream, lastByte, &lastByteTxCb);
|
||||
|
||||
// when first and last byte TX callbacsk fired, numPacketsTxWithNewData should
|
||||
// be 1
|
||||
EXPECT_CALL(firstByteTxCb, onByteEvent(getTxMatcher(stream, 0)))
|
||||
.Times(1)
|
||||
.WillOnce(Invoke([&](QuicSocket::ByteEvent /* event */) {
|
||||
auto info = *transport_->getStreamTransportInfo(stream);
|
||||
EXPECT_EQ(info.numPacketsTxWithNewData, 1);
|
||||
}));
|
||||
EXPECT_CALL(lastByteTxCb, onByteEvent(getTxMatcher(stream, lastByte)))
|
||||
.Times(1)
|
||||
.WillOnce(Invoke([&](QuicSocket::ByteEvent /* event */) {
|
||||
auto info = *transport_->getStreamTransportInfo(stream);
|
||||
EXPECT_EQ(info.numPacketsTxWithNewData, 1);
|
||||
}));
|
||||
loopForWrites();
|
||||
Mock::VerifyAndClearExpectations(&firstByteTxCb);
|
||||
Mock::VerifyAndClearExpectations(&lastByteTxCb);
|
||||
}
|
||||
|
||||
TEST_F(QuicTransportTest, GetStreamPacketsTxedMultiplePackets) {
|
||||
auto& conn = transport_->getConnectionState();
|
||||
conn.transportSettings.writeConnectionDataPacketsLimit = 1;
|
||||
|
||||
const uint64_t streamBytes = kDefaultUDPSendPacketLen * 4;
|
||||
const uint64_t lastByte = streamBytes - 1;
|
||||
|
||||
// 20 bytes overhead per packet should be more than enough
|
||||
const uint64_t firstPacketNearTailByte = kDefaultUDPSendPacketLen - 20;
|
||||
const uint64_t secondPacketNearHeadByte = kDefaultUDPSendPacketLen;
|
||||
const uint64_t secondPacketNearTailByte = kDefaultUDPSendPacketLen * 2 - 40;
|
||||
|
||||
StrictMock<MockByteEventCallback> firstByteTxCb;
|
||||
StrictMock<MockByteEventCallback> firstPacketNearTailByteTxCb;
|
||||
StrictMock<MockByteEventCallback> secondPacketNearHeadByteTxCb;
|
||||
StrictMock<MockByteEventCallback> secondPacketNearTailByteTxCb;
|
||||
StrictMock<MockByteEventCallback> lastByteTxCb;
|
||||
auto stream = transport_->createBidirectionalStream().value();
|
||||
auto buf = buildRandomInputData(streamBytes);
|
||||
CHECK_EQ(streamBytes, buf->length());
|
||||
transport_->writeChain(
|
||||
stream, buf->clone(), false /* eof */, false /* cork */);
|
||||
transport_->registerTxCallback(stream, 0, &firstByteTxCb);
|
||||
transport_->registerTxCallback(
|
||||
stream, firstPacketNearTailByte, &firstPacketNearTailByteTxCb);
|
||||
transport_->registerTxCallback(
|
||||
stream, secondPacketNearHeadByte, &secondPacketNearHeadByteTxCb);
|
||||
transport_->registerTxCallback(
|
||||
stream, secondPacketNearTailByte, &secondPacketNearTailByteTxCb);
|
||||
transport_->registerTxCallback(stream, lastByte, &lastByteTxCb);
|
||||
|
||||
// first byte and first packet last bytes get Txed on first loopForWrites
|
||||
EXPECT_CALL(firstByteTxCb, onByteEvent(getTxMatcher(stream, 0)))
|
||||
.Times(1)
|
||||
.WillOnce(Invoke([&](QuicSocket::ByteEvent /* event */) {
|
||||
auto info = *transport_->getStreamTransportInfo(stream);
|
||||
EXPECT_EQ(info.numPacketsTxWithNewData, 1);
|
||||
}));
|
||||
EXPECT_CALL(
|
||||
firstPacketNearTailByteTxCb,
|
||||
onByteEvent(getTxMatcher(stream, firstPacketNearTailByte)))
|
||||
.Times(1)
|
||||
.WillOnce(Invoke([&](QuicSocket::ByteEvent /* even */) {
|
||||
auto info = *transport_->getStreamTransportInfo(stream);
|
||||
EXPECT_EQ(info.numPacketsTxWithNewData, 1);
|
||||
}));
|
||||
loopForWrites();
|
||||
Mock::VerifyAndClearExpectations(&firstByteTxCb);
|
||||
Mock::VerifyAndClearExpectations(&firstPacketNearTailByteTxCb);
|
||||
|
||||
// second packet should be send on the second loopForWrites
|
||||
EXPECT_CALL(
|
||||
secondPacketNearHeadByteTxCb,
|
||||
onByteEvent(getTxMatcher(stream, secondPacketNearHeadByte)))
|
||||
.Times(1)
|
||||
.WillOnce(Invoke([&](QuicSocket::ByteEvent /* even */) {
|
||||
auto info = *transport_->getStreamTransportInfo(stream);
|
||||
EXPECT_EQ(info.numPacketsTxWithNewData, 2);
|
||||
}));
|
||||
EXPECT_CALL(
|
||||
secondPacketNearTailByteTxCb,
|
||||
onByteEvent(getTxMatcher(stream, secondPacketNearTailByte)))
|
||||
.Times(1)
|
||||
.WillOnce(Invoke([&](QuicSocket::ByteEvent /* even */) {
|
||||
auto info = *transport_->getStreamTransportInfo(stream);
|
||||
EXPECT_EQ(info.numPacketsTxWithNewData, 2);
|
||||
}));
|
||||
loopForWrites();
|
||||
Mock::VerifyAndClearExpectations(&secondPacketNearHeadByteTxCb);
|
||||
Mock::VerifyAndClearExpectations(&secondPacketNearTailByteTxCb);
|
||||
|
||||
// last byte will be sent on the fifth loopForWrites
|
||||
EXPECT_CALL(lastByteTxCb, onByteEvent(getTxMatcher(stream, lastByte)))
|
||||
.Times(1)
|
||||
.WillOnce(Invoke([&](QuicSocket::ByteEvent /* event */) {
|
||||
auto info = *transport_->getStreamTransportInfo(stream);
|
||||
EXPECT_EQ(info.numPacketsTxWithNewData, 5);
|
||||
}));
|
||||
loopForWrites();
|
||||
loopForWrites();
|
||||
loopForWrites();
|
||||
Mock::VerifyAndClearExpectations(&lastByteTxCb);
|
||||
}
|
||||
|
||||
} // namespace test
|
||||
} // namespace quic
|
||||
|
Reference in New Issue
Block a user