When QPACK encoding, allow blocking references on a stream that is already blocked.
After this change, blocked_stream_count() would only be used in tests. This CL
also takes the opportunity to replace it with a more expressive
stream_is_blocked() method.
gfe-relnote: n/a, change to QUIC v99-only code. Protected by existing disabled gfe2_reloadable_flag_quic_enable_version_99.
PiperOrigin-RevId: 270385673
Change-Id: I2b68be71f2db19e2acbc830b3a4579436fe4fa39
diff --git a/quic/core/qpack/qpack_blocking_manager_test.cc b/quic/core/qpack/qpack_blocking_manager_test.cc
index 6f78d87..f21f1e7 100644
--- a/quic/core/qpack/qpack_blocking_manager_test.cc
+++ b/quic/core/qpack/qpack_blocking_manager_test.cc
@@ -8,6 +8,27 @@
namespace quic {
namespace test {
+
+class QpackBlockingManagerPeer {
+ public:
+ static bool stream_is_blocked(const QpackBlockingManager* manager,
+ QuicStreamId stream_id) {
+ for (const auto& header_blocks_for_stream : manager->header_blocks_) {
+ if (header_blocks_for_stream.first != stream_id) {
+ continue;
+ }
+ for (const auto& indices : header_blocks_for_stream.second) {
+ if (QpackBlockingManager::RequiredInsertCount(indices) >
+ manager->known_received_count_) {
+ return true;
+ }
+ }
+ }
+
+ return false;
+ }
+};
+
namespace {
class QpackBlockingManagerTest : public QuicTest {
@@ -15,11 +36,14 @@
QpackBlockingManagerTest() = default;
~QpackBlockingManagerTest() override = default;
+ bool stream_is_blocked(QuicStreamId stream_id) const {
+ return QpackBlockingManagerPeer::stream_is_blocked(&manager_, stream_id);
+ }
+
QpackBlockingManager manager_;
};
TEST_F(QpackBlockingManagerTest, Empty) {
- EXPECT_EQ(0u, manager_.blocked_stream_count());
EXPECT_EQ(0u, manager_.known_received_count());
EXPECT_EQ(std::numeric_limits<uint64_t>::max(),
manager_.smallest_blocking_index());
@@ -34,37 +58,39 @@
// Stream 0 is not blocked, because it only references entries that are
// already acknowledged by an Insert Count Increment instruction.
manager_.OnHeaderBlockSent(0, {1, 0});
- EXPECT_EQ(0u, manager_.blocked_stream_count());
+ EXPECT_FALSE(stream_is_blocked(0));
}
TEST_F(QpackBlockingManagerTest, UnblockedByInsertCountIncrement) {
manager_.OnHeaderBlockSent(0, {1, 0});
- EXPECT_EQ(1u, manager_.blocked_stream_count());
+ EXPECT_TRUE(stream_is_blocked(0));
manager_.OnInsertCountIncrement(2);
- EXPECT_EQ(0u, manager_.blocked_stream_count());
+ EXPECT_FALSE(stream_is_blocked(0));
}
TEST_F(QpackBlockingManagerTest, NotBlockedByHeaderAcknowledgement) {
manager_.OnHeaderBlockSent(0, {2, 1, 1});
- EXPECT_EQ(1u, manager_.blocked_stream_count());
+ EXPECT_TRUE(stream_is_blocked(0));
EXPECT_TRUE(manager_.OnHeaderAcknowledgement(0));
- EXPECT_EQ(0u, manager_.blocked_stream_count());
+ EXPECT_FALSE(stream_is_blocked(0));
// Stream 1 is not blocked, because it only references entries that are
// already acknowledged by a Header Acknowledgement instruction.
manager_.OnHeaderBlockSent(1, {2, 2});
- EXPECT_EQ(0u, manager_.blocked_stream_count());
+ EXPECT_FALSE(stream_is_blocked(1));
}
TEST_F(QpackBlockingManagerTest, UnblockedByHeaderAcknowledgement) {
manager_.OnHeaderBlockSent(0, {2, 1, 1});
manager_.OnHeaderBlockSent(1, {2, 2});
- EXPECT_EQ(2u, manager_.blocked_stream_count());
+ EXPECT_TRUE(stream_is_blocked(0));
+ EXPECT_TRUE(stream_is_blocked(1));
EXPECT_TRUE(manager_.OnHeaderAcknowledgement(0));
- EXPECT_EQ(0u, manager_.blocked_stream_count());
+ EXPECT_FALSE(stream_is_blocked(0));
+ EXPECT_FALSE(stream_is_blocked(1));
}
TEST_F(QpackBlockingManagerTest, KnownReceivedCount) {
@@ -145,38 +171,37 @@
TEST_F(QpackBlockingManagerTest, HeaderAcknowledgementsOnSingleStream) {
EXPECT_EQ(0u, manager_.known_received_count());
- EXPECT_EQ(0u, manager_.blocked_stream_count());
EXPECT_EQ(std::numeric_limits<uint64_t>::max(),
manager_.smallest_blocking_index());
manager_.OnHeaderBlockSent(0, {2, 1, 1});
EXPECT_EQ(0u, manager_.known_received_count());
- EXPECT_EQ(1u, manager_.blocked_stream_count());
+ EXPECT_TRUE(stream_is_blocked(0));
EXPECT_EQ(1u, manager_.smallest_blocking_index());
manager_.OnHeaderBlockSent(0, {1, 0});
EXPECT_EQ(0u, manager_.known_received_count());
- EXPECT_EQ(1u, manager_.blocked_stream_count());
+ EXPECT_TRUE(stream_is_blocked(0));
EXPECT_EQ(0u, manager_.smallest_blocking_index());
EXPECT_TRUE(manager_.OnHeaderAcknowledgement(0));
EXPECT_EQ(3u, manager_.known_received_count());
- EXPECT_EQ(0u, manager_.blocked_stream_count());
+ EXPECT_FALSE(stream_is_blocked(0));
EXPECT_EQ(0u, manager_.smallest_blocking_index());
manager_.OnHeaderBlockSent(0, {3});
EXPECT_EQ(3u, manager_.known_received_count());
- EXPECT_EQ(1u, manager_.blocked_stream_count());
+ EXPECT_TRUE(stream_is_blocked(0));
EXPECT_EQ(0u, manager_.smallest_blocking_index());
EXPECT_TRUE(manager_.OnHeaderAcknowledgement(0));
EXPECT_EQ(3u, manager_.known_received_count());
- EXPECT_EQ(1u, manager_.blocked_stream_count());
+ EXPECT_TRUE(stream_is_blocked(0));
EXPECT_EQ(3u, manager_.smallest_blocking_index());
EXPECT_TRUE(manager_.OnHeaderAcknowledgement(0));
EXPECT_EQ(4u, manager_.known_received_count());
- EXPECT_EQ(0u, manager_.blocked_stream_count());
+ EXPECT_FALSE(stream_is_blocked(0));
EXPECT_EQ(std::numeric_limits<uint64_t>::max(),
manager_.smallest_blocking_index());
@@ -185,23 +210,26 @@
TEST_F(QpackBlockingManagerTest, CancelStream) {
manager_.OnHeaderBlockSent(0, {3});
- EXPECT_EQ(1u, manager_.blocked_stream_count());
+ EXPECT_TRUE(stream_is_blocked(0));
EXPECT_EQ(3u, manager_.smallest_blocking_index());
manager_.OnHeaderBlockSent(0, {2});
- EXPECT_EQ(1u, manager_.blocked_stream_count());
+ EXPECT_TRUE(stream_is_blocked(0));
EXPECT_EQ(2u, manager_.smallest_blocking_index());
manager_.OnHeaderBlockSent(1, {4});
- EXPECT_EQ(2u, manager_.blocked_stream_count());
+ EXPECT_TRUE(stream_is_blocked(0));
+ EXPECT_TRUE(stream_is_blocked(1));
EXPECT_EQ(2u, manager_.smallest_blocking_index());
manager_.OnStreamCancellation(0);
- EXPECT_EQ(1u, manager_.blocked_stream_count());
+ EXPECT_FALSE(stream_is_blocked(0));
+ EXPECT_TRUE(stream_is_blocked(1));
EXPECT_EQ(4u, manager_.smallest_blocking_index());
manager_.OnStreamCancellation(1);
- EXPECT_EQ(0u, manager_.blocked_stream_count());
+ EXPECT_FALSE(stream_is_blocked(0));
+ EXPECT_FALSE(stream_is_blocked(1));
EXPECT_EQ(std::numeric_limits<uint64_t>::max(),
manager_.smallest_blocking_index());
}
@@ -288,6 +316,76 @@
manager_.smallest_blocking_index());
}
+TEST_F(QpackBlockingManagerTest, BlockingAllowedOnStream) {
+ const QuicStreamId kStreamId1 = 1;
+ const QuicStreamId kStreamId2 = 2;
+ const QuicStreamId kStreamId3 = 3;
+
+ // No stream can block if limit is 0.
+ EXPECT_FALSE(manager_.blocking_allowed_on_stream(kStreamId1, 0));
+ EXPECT_FALSE(manager_.blocking_allowed_on_stream(kStreamId2, 0));
+
+ // Either stream can block if limit is larger.
+ EXPECT_TRUE(manager_.blocking_allowed_on_stream(kStreamId1, 1));
+ EXPECT_TRUE(manager_.blocking_allowed_on_stream(kStreamId2, 1));
+
+ // Doubly block first stream.
+ manager_.OnHeaderBlockSent(kStreamId1, {0});
+ manager_.OnHeaderBlockSent(kStreamId1, {1});
+
+ // First stream is already blocked so it can carry more blocking references.
+ EXPECT_TRUE(manager_.blocking_allowed_on_stream(kStreamId1, 1));
+ // Second stream is not allowed to block if limit is already reached.
+ EXPECT_FALSE(manager_.blocking_allowed_on_stream(kStreamId2, 1));
+
+ // Either stream can block if limit is larger than number of blocked streams.
+ EXPECT_TRUE(manager_.blocking_allowed_on_stream(kStreamId1, 2));
+ EXPECT_TRUE(manager_.blocking_allowed_on_stream(kStreamId2, 2));
+
+ // Block second stream.
+ manager_.OnHeaderBlockSent(kStreamId2, {2});
+
+ // Streams are already blocked so either can carry more blocking references.
+ EXPECT_TRUE(manager_.blocking_allowed_on_stream(kStreamId1, 2));
+ EXPECT_TRUE(manager_.blocking_allowed_on_stream(kStreamId2, 2));
+
+ // Third, unblocked stream is not allowed to block unless limit is strictly
+ // larger than number of blocked streams.
+ EXPECT_FALSE(manager_.blocking_allowed_on_stream(kStreamId3, 2));
+ EXPECT_TRUE(manager_.blocking_allowed_on_stream(kStreamId3, 3));
+
+ // Acknowledge decoding of first header block on first stream.
+ // Stream is still blocked on its second header block.
+ manager_.OnHeaderAcknowledgement(kStreamId1);
+
+ EXPECT_TRUE(manager_.blocking_allowed_on_stream(kStreamId1, 1));
+ EXPECT_TRUE(manager_.blocking_allowed_on_stream(kStreamId2, 1));
+
+ // Acknowledge decoding of second header block on first stream.
+ // This unblocks the stream.
+ manager_.OnHeaderAcknowledgement(kStreamId1);
+
+ // First stream is not allowed to block if limit is already reached.
+ EXPECT_FALSE(manager_.blocking_allowed_on_stream(kStreamId1, 1));
+ // Second stream is already blocked so it can carry more blocking references.
+ EXPECT_TRUE(manager_.blocking_allowed_on_stream(kStreamId2, 1));
+
+ // Either stream can block if limit is larger than number of blocked streams.
+ EXPECT_TRUE(manager_.blocking_allowed_on_stream(kStreamId1, 2));
+ EXPECT_TRUE(manager_.blocking_allowed_on_stream(kStreamId2, 2));
+
+ // Unblock second stream.
+ manager_.OnHeaderAcknowledgement(kStreamId2);
+
+ // No stream can block if limit is 0.
+ EXPECT_FALSE(manager_.blocking_allowed_on_stream(kStreamId1, 0));
+ EXPECT_FALSE(manager_.blocking_allowed_on_stream(kStreamId2, 0));
+
+ // Either stream can block if limit is larger.
+ EXPECT_TRUE(manager_.blocking_allowed_on_stream(kStreamId1, 1));
+ EXPECT_TRUE(manager_.blocking_allowed_on_stream(kStreamId2, 1));
+}
+
} // namespace
} // namespace test
} // namespace quic