1
0
mirror of https://github.com/facebookincubator/mvfst.git synced 2025-11-24 04:01:07 +03:00

Convert IntervalSet from throwing exceptions to using CHECKs with Expected error handling

Summary:
This commit converts IntervalSet to use CHECKs instead of throwing exceptions and provides safe tryInsert methods that return quic::Expected for error handling.

**Core Problem Solved:**
IntervalSet was throwing `std::invalid_argument` exceptions in two scenarios:
1. When constructing an Interval with `start > end`
2. When interval bounds exceed the maximum allowed value

This change eliminates exceptions in favor of CHECKs (for internal validation) and Expected-based error handling (for caller validation).

**Implementation Details:**

**1. IntervalSet Core Changes:**
- Replaced `throw std::invalid_argument` with `CHECK_LE` in Interval constructor
- Replaced `throw std::invalid_argument` with `CHECK_LE` in `insert(start, end)`
- Added `IntervalSetError` enum for error classification
- Added `folly::Expected` include

**2. Safe API Layer:**
- Added `tryInsert(interval)` method returning `Expected<Unit, IntervalSetError>`
- Added `tryInsert(start, end)` method with pre-validation
- Added `tryInsert(point)` method
- Added static `Interval::tryCreate()` method for safe interval construction

**3. Updated  Code:**
- **QuicWriteCodec.cpp**: Updated `fillFrameWithPacketReceiveTimestamps` to use `tryInsert`
  - Returns `QuicError` if interval validation fails
  - Maintains existing error handling patterns
- **QuicTransportFunctions.cpp**: Updated `implicitAckCryptoStream` to use `tryInsert`
  - Logs errors and continues processing other packets
  - Robust error handling for crypto stream implicit acks

Reviewed By: kvtsoy

Differential Revision: D76792362

fbshipit-source-id: 5bd7c22e69a91d60cc41c603a1f2380893f4c8a0
This commit is contained in:
Matt Joras
2025-08-19 10:47:24 -07:00
committed by Facebook GitHub Bot
parent 8f8be8d5d0
commit d3e8fe246a
19 changed files with 262 additions and 51 deletions

View File

@@ -73,12 +73,14 @@ TEST_P(AddPacketToAckStateTest, FirstPacketNotOutOfOrder) {
/**
* We skip setting the getAckState(conn,
* GetParam()).largestReceivedUdpPacketNum to simulate that we haven't
* received any packets yet. `addPacketToAckState()` should return false for
* the first packet received.
* received any packets yet. `addPacketToAckState()` should return distance 0
* for the first packet received.
*/
PacketNum firstPacket = folly::Random::rand32(1, 100);
EXPECT_FALSE(addPacketToAckState(
conn, getAckState(conn, GetParam()), firstPacket, buildPacketMinimal()));
auto result = addPacketToAckState(
conn, getAckState(conn, GetParam()), firstPacket, buildPacketMinimal());
ASSERT_TRUE(result.has_value());
EXPECT_EQ(result.value(), 0);
}
TEST_P(AddPacketToAckStateTest, ReceiveNew) {
@@ -90,7 +92,8 @@ TEST_P(AddPacketToAckStateTest, ReceiveNew) {
PacketNum newReceived = currentLargestReceived + 1;
auto distance = addPacketToAckState(
conn, getAckState(conn, GetParam()), newReceived, buildPacketMinimal());
EXPECT_EQ(distance, 0);
ASSERT_TRUE(distance.has_value());
EXPECT_EQ(distance.value(), 0);
EXPECT_GT(
*getAckState(conn, GetParam()).largestRecvdPacketNum,
currentLargestReceived);
@@ -105,7 +108,8 @@ TEST_P(AddPacketToAckStateTest, ReceiveNewWithGap) {
PacketNum newReceived = currentLargestReceived + 3;
auto distance = addPacketToAckState(
conn, getAckState(conn, GetParam()), newReceived, buildPacketMinimal());
EXPECT_EQ(distance, 2); // newReceived is 2 after the expected pkt num
ASSERT_TRUE(distance.has_value());
EXPECT_EQ(distance.value(), 2); // newReceived is 2 after the expected pkt num
EXPECT_GT(
*getAckState(conn, GetParam()).largestRecvdPacketNum,
currentLargestReceived);
@@ -120,7 +124,9 @@ TEST_P(AddPacketToAckStateTest, ReceiveOld) {
PacketNum newReceived = currentLargestReceived - 1;
auto distance = addPacketToAckState(
conn, getAckState(conn, GetParam()), newReceived, buildPacketMinimal());
EXPECT_EQ(distance, 2); // newReceived is 2 before the expected pkt num
ASSERT_TRUE(distance.has_value());
EXPECT_EQ(
distance.value(), 2); // newReceived is 2 before the expected pkt num
EXPECT_EQ(
*getAckState(conn, GetParam()).largestRecvdPacketNum,
currentLargestReceived);
@@ -135,7 +141,9 @@ TEST_P(AddPacketToAckStateTest, ReceiveOldWithGap) {
PacketNum newReceived = currentLargestReceived - 5;
auto distance = addPacketToAckState(
conn, getAckState(conn, GetParam()), newReceived, buildPacketMinimal());
EXPECT_EQ(distance, 6); // newReceived is 6 before the expected pkt num
ASSERT_TRUE(distance.has_value());
EXPECT_EQ(
distance.value(), 6); // newReceived is 6 before the expected pkt num
EXPECT_EQ(
*getAckState(conn, GetParam()).largestRecvdPacketNum,
currentLargestReceived);
@@ -159,7 +167,8 @@ TEST_P(AddPacketToAckStateTest, ReceiveWithECN) {
packet.tosValue = kEcnECT0;
auto distance = addPacketToAckState(
conn, getAckState(conn, GetParam()), ++nextPacketNum, packet);
EXPECT_EQ(distance, 0);
ASSERT_TRUE(distance.has_value());
EXPECT_EQ(distance.value(), 0);
// Seen 1 ECT0, 0 ECT1, 0 CE.
EXPECT_EQ(getAckState(conn, GetParam()).ecnCECountReceived, 0);
@@ -172,7 +181,8 @@ TEST_P(AddPacketToAckStateTest, ReceiveWithECN) {
packet.tosValue = kEcnECT1;
auto distance = addPacketToAckState(
conn, getAckState(conn, GetParam()), ++nextPacketNum, packet);
EXPECT_EQ(distance, 0);
ASSERT_TRUE(distance.has_value());
EXPECT_EQ(distance.value(), 0);
// Seen 1 ECT0, 1 ECT1, 0 CE.
EXPECT_EQ(getAckState(conn, GetParam()).ecnCECountReceived, 0);
@@ -185,7 +195,8 @@ TEST_P(AddPacketToAckStateTest, ReceiveWithECN) {
packet.tosValue = kEcnCE;
auto distance = addPacketToAckState(
conn, getAckState(conn, GetParam()), ++nextPacketNum, packet);
EXPECT_EQ(distance, 0);
ASSERT_TRUE(distance.has_value());
EXPECT_EQ(distance.value(), 0);
// Seen 1 ECT0, 1 ECT1, 1 CE.
EXPECT_EQ(getAckState(conn, GetParam()).ecnCECountReceived, 1);
@@ -198,7 +209,8 @@ TEST_P(AddPacketToAckStateTest, ReceiveWithECN) {
packet.tosValue = kEcnCE;
auto distance = addPacketToAckState(
conn, getAckState(conn, GetParam()), ++nextPacketNum, packet);
EXPECT_EQ(distance, 0);
ASSERT_TRUE(distance.has_value());
EXPECT_EQ(distance.value(), 0);
// Seen 1 ECT0, 1 ECT1, 2 CE.
EXPECT_EQ(getAckState(conn, GetParam()).ecnCECountReceived, 2);