Add QpackHeaderTable::draining_index(). gfe-relnote: n/a, change to QUIC v99-only code. Protected by existing disabled gfe2_reloadable_flag_quic_enable_version_99. PiperOrigin-RevId: 259954990 Change-Id: I896a5b039f2d61e7b4e9f97299b9ebb2234e2820
diff --git a/quic/core/qpack/qpack_header_table.cc b/quic/core/qpack/qpack_header_table.cc index 6fa6412..92eb072 100644 --- a/quic/core/qpack/qpack_header_table.cc +++ b/quic/core/qpack/qpack_header_table.cc
@@ -173,6 +173,31 @@ observers_.push({observer, required_insert_count}); } +uint64_t QpackHeaderTable::draining_index(float draining_fraction) const { + DCHECK_LE(0.0, draining_fraction); + DCHECK_LE(draining_fraction, 1.0); + + const uint64_t required_space = draining_fraction * dynamic_table_capacity_; + uint64_t space_above_draining_index = + dynamic_table_capacity_ - dynamic_table_size_; + + if (dynamic_entries_.empty() || + space_above_draining_index >= required_space) { + return dropped_entry_count_; + } + + auto it = dynamic_entries_.begin(); + while (space_above_draining_index < required_space) { + space_above_draining_index += it->Size(); + ++it; + if (it == dynamic_entries_.end()) { + return inserted_entry_count(); + } + } + + return it->InsertionIndex(); +} + bool QpackHeaderTable::ObserverWithThreshold::operator>( const ObserverWithThreshold& other) const { return required_insert_count > other.required_insert_count;
diff --git a/quic/core/qpack/qpack_header_table.h b/quic/core/qpack/qpack_header_table.h index 39d7326..54b0829 100644 --- a/quic/core/qpack/qpack_header_table.h +++ b/quic/core/qpack/qpack_header_table.h
@@ -99,6 +99,14 @@ // The number of entries dropped from the dynamic table. uint64_t dropped_entry_count() const { return dropped_entry_count_; } + // Returns the draining index described at + // https://quicwg.org/base-drafts/draft-ietf-quic-qpack.html#avoiding-blocked-insertions. + // Entries with an index larger than or equal to the draining index take up + // approximately |1.0 - draining_fraction| of dynamic table capacity. The + // remaining capacity is taken up by draining entries and unused space. + // The returned index might not be the index of a valid entry. + uint64_t draining_index(float draining_fraction) const; + private: // Evict entries from the dynamic table until table size is less than or equal // to current value of |dynamic_table_capacity_|.
diff --git a/quic/core/qpack/qpack_header_table_test.cc b/quic/core/qpack/qpack_header_table_test.cc index ff7ef48..7d1044b 100644 --- a/quic/core/qpack/qpack_header_table_test.cc +++ b/quic/core/qpack/qpack_header_table_test.cc
@@ -404,6 +404,42 @@ Mock::VerifyAndClearExpectations(&observer5); } +TEST_F(QpackHeaderTableTest, DrainingIndex) { + QpackHeaderTable table; + table.SetMaximumDynamicTableCapacity(4 * QpackEntry::Size("foo", "bar")); + + // Empty table: no draining entry. + EXPECT_EQ(0u, table.draining_index(0.0)); + EXPECT_EQ(0u, table.draining_index(1.0)); + + // Table with one entry. + EXPECT_TRUE(table.InsertEntry("foo", "bar")); + // Any entry can be referenced if none of the table is draining. + EXPECT_EQ(0u, table.draining_index(0.0)); + // No entry can be referenced if all of the table is draining. + EXPECT_EQ(1u, table.draining_index(1.0)); + + // Table with two entries is at half capacity. + EXPECT_TRUE(table.InsertEntry("foo", "bar")); + // Any entry can be referenced if at most half of the table is draining, + // because current entries only take up half of total capacity. + EXPECT_EQ(0u, table.draining_index(0.0)); + EXPECT_EQ(0u, table.draining_index(0.5)); + // No entry can be referenced if all of the table is draining. + EXPECT_EQ(2u, table.draining_index(1.0)); + + // Table with four entries is full. + EXPECT_TRUE(table.InsertEntry("foo", "bar")); + EXPECT_TRUE(table.InsertEntry("foo", "bar")); + // Any entry can be referenced if none of the table is draining. + EXPECT_EQ(0u, table.draining_index(0.0)); + // In a full table with identically sized entries, |draining_fraction| of all + // entries are draining. + EXPECT_EQ(2u, table.draining_index(0.5)); + // No entry can be referenced if all of the table is draining. + EXPECT_EQ(4u, table.draining_index(1.0)); +} + } // namespace } // namespace test } // namespace quic