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

@@ -158,9 +158,10 @@ TEST(IntervalSet, insertWithMergeAtEdge) {
TEST(IntervalSet, insertBoundTooLarge) {
IntervalSet<uint32_t, 10> set;
EXPECT_THROW(
set.insert(0, std::numeric_limits<uint32_t>::max() - 9),
std::invalid_argument);
// This should CHECK-fail since end - start > 10
EXPECT_DEATH(
set.insert(0, std::numeric_limits<uint32_t>::max() - 9), "Check failed");
// This should work fine since end - start == 10
set.insert(0, std::numeric_limits<uint32_t>::max() - 10);
}
@@ -402,3 +403,77 @@ TEST(IntervalSet, equalityComparatorNotEqualDiffIntervals2) {
EXPECT_FALSE(set1 == set2);
EXPECT_TRUE(set1 != set2);
}
TEST(IntervalSet, tryInsertValidInterval) {
IntervalSet<int> set;
auto result = set.tryInsert(1, 5);
EXPECT_TRUE(result.has_value());
EXPECT_EQ(1, set.size());
EXPECT_TRUE(set.contains(1, 5));
}
TEST(IntervalSet, tryInsertValidPoint) {
IntervalSet<int> set;
auto result = set.tryInsert(10);
EXPECT_TRUE(result.has_value());
EXPECT_EQ(1, set.size());
EXPECT_TRUE(set.contains(10, 10));
}
TEST(IntervalSet, tryInsertInvalidInterval) {
IntervalSet<int> set;
// start > end should return error
auto result = set.tryInsert(10, 5);
EXPECT_TRUE(result.hasError());
EXPECT_EQ(IntervalSetError::InvalidInterval, result.error());
EXPECT_EQ(0, set.size());
}
TEST(IntervalSet, tryInsertBoundTooLarge) {
IntervalSet<uint32_t, 10> set;
// This should return error instead of CHECK-failing
auto result = set.tryInsert(0, std::numeric_limits<uint32_t>::max() - 9);
EXPECT_TRUE(result.hasError());
EXPECT_EQ(IntervalSetError::IntervalBoundTooLarge, result.error());
EXPECT_EQ(0, set.size());
// This should succeed
auto result2 = set.tryInsert(0, std::numeric_limits<uint32_t>::max() - 10);
EXPECT_TRUE(result2.has_value());
EXPECT_EQ(1, set.size());
}
TEST(IntervalSet, tryInsertWithMerging) {
IntervalSet<int> set;
auto result1 = set.tryInsert(1, 3);
EXPECT_TRUE(result1.has_value());
auto result2 = set.tryInsert(5, 7);
EXPECT_TRUE(result2.has_value());
// Insert overlapping interval
auto result3 = set.tryInsert(2, 6);
EXPECT_TRUE(result3.has_value());
EXPECT_EQ(1, set.size());
EXPECT_TRUE(set.contains(1, 7));
}
TEST(IntervalSet, tryCreateInterval) {
// Test the static tryCreate method
auto result1 = Interval<int>::tryCreate(1, 5);
EXPECT_TRUE(result1.has_value());
EXPECT_EQ(1, result1->start);
EXPECT_EQ(5, result1->end);
// Test invalid interval
auto result2 = Interval<int>::tryCreate(10, 5);
EXPECT_TRUE(result2.hasError());
EXPECT_EQ(IntervalSetError::InvalidInterval, result2.error());
// Test bound too large
auto result3 = Interval<uint32_t, 10>::tryCreate(
0, std::numeric_limits<uint32_t>::max() - 9);
EXPECT_TRUE(result3.hasError());
EXPECT_EQ(IntervalSetError::IntervalBoundTooLarge, result3.error());
}