Return absolute index instead of QpackEntry* from QpackHeaderTable::InsertEntry().
The immediate goal is to eliminate uses of InsertionIndex(). The long-term goal
is to eliminate the need for interator stability on the container that holds
QpackEntries.
PiperOrigin-RevId: 363000091
Change-Id: Ic1e9ce61d4e3b263687ca854b1bd400c288b7368
diff --git a/quic/core/qpack/qpack_decoder.cc b/quic/core/qpack/qpack_decoder.cc
index c1ac28c..b992616 100644
--- a/quic/core/qpack/qpack_decoder.cc
+++ b/quic/core/qpack/qpack_decoder.cc
@@ -81,11 +81,12 @@
return;
}
- entry = header_table_.InsertEntry(entry->name(), value);
- if (!entry) {
+ if (!header_table_.EntryFitsDynamicTableCapacity(entry->name(), value)) {
OnErrorDetected(QUIC_QPACK_ENCODER_STREAM_ERROR_INSERTING_STATIC,
"Error inserting entry with name reference.");
+ return;
}
+ header_table_.InsertEntry(entry->name(), value);
return;
}
@@ -104,20 +105,22 @@
"Dynamic table entry not found.");
return;
}
- entry = header_table_.InsertEntry(entry->name(), value);
- if (!entry) {
+ if (!header_table_.EntryFitsDynamicTableCapacity(entry->name(), value)) {
OnErrorDetected(QUIC_QPACK_ENCODER_STREAM_ERROR_INSERTING_DYNAMIC,
"Error inserting entry with name reference.");
+ return;
}
+ header_table_.InsertEntry(entry->name(), value);
}
void QpackDecoder::OnInsertWithoutNameReference(absl::string_view name,
absl::string_view value) {
- const QpackEntry* entry = header_table_.InsertEntry(name, value);
- if (!entry) {
+ if (!header_table_.EntryFitsDynamicTableCapacity(name, value)) {
OnErrorDetected(QUIC_QPACK_ENCODER_STREAM_ERROR_INSERTING_LITERAL,
"Error inserting literal entry.");
+ return;
}
+ header_table_.InsertEntry(name, value);
}
void QpackDecoder::OnDuplicate(uint64_t index) {
@@ -136,13 +139,13 @@
"Dynamic table entry not found.");
return;
}
- entry = header_table_.InsertEntry(entry->name(), entry->value());
- if (!entry) {
- // InsertEntry() can only fail if entry is larger then dynamic table
- // capacity, but that is impossible since entry was retrieved from the
- // dynamic table.
+ if (!header_table_.EntryFitsDynamicTableCapacity(entry->name(),
+ entry->value())) {
+ // This is impossible since entry was retrieved from the dynamic table.
OnErrorDetected(QUIC_INTERNAL_ERROR, "Error inserting duplicate entry.");
+ return;
}
+ header_table_.InsertEntry(entry->name(), entry->value());
}
void QpackDecoder::OnSetDynamicTableCapacity(uint64_t capacity) {
diff --git a/quic/core/qpack/qpack_encoder.cc b/quic/core/qpack/qpack_encoder.cc
index 8138266..de42996 100644
--- a/quic/core/qpack/qpack_encoder.cc
+++ b/quic/core/qpack/qpack_encoder.cc
@@ -156,9 +156,9 @@
encoder_stream_sender_.SendDuplicate(
QpackAbsoluteIndexToEncoderStreamRelativeIndex(
index, header_table_.inserted_entry_count()));
- auto entry = header_table_.InsertEntry(name, value);
+ uint64_t new_index = header_table_.InsertEntry(name, value);
instructions.push_back(EncodeIndexedHeaderField(
- is_static, entry->InsertionIndex(), referred_indices));
+ is_static, new_index, referred_indices));
smallest_blocking_index = std::min(smallest_blocking_index, index);
header_table_.set_dynamic_table_entry_referenced();
@@ -184,12 +184,11 @@
// If allowed, insert entry into dynamic table and refer to it.
encoder_stream_sender_.SendInsertWithNameReference(is_static, index,
value);
- auto entry = header_table_.InsertEntry(name, value);
+ uint64_t new_index = header_table_.InsertEntry(name, value);
instructions.push_back(EncodeIndexedHeaderField(
- /* is_static = */ false, entry->InsertionIndex(),
- referred_indices));
- smallest_blocking_index = std::min<uint64_t>(
- smallest_blocking_index, entry->InsertionIndex());
+ /* is_static = */ false, new_index, referred_indices));
+ smallest_blocking_index =
+ std::min<uint64_t>(smallest_blocking_index, new_index);
break;
}
@@ -214,9 +213,9 @@
QpackAbsoluteIndexToEncoderStreamRelativeIndex(
index, header_table_.inserted_entry_count()),
value);
- auto entry = header_table_.InsertEntry(name, value);
- instructions.push_back(EncodeIndexedHeaderField(
- is_static, entry->InsertionIndex(), referred_indices));
+ uint64_t new_index = header_table_.InsertEntry(name, value);
+ instructions.push_back(
+ EncodeIndexedHeaderField(is_static, new_index, referred_indices));
smallest_blocking_index = std::min(smallest_blocking_index, index);
header_table_.set_dynamic_table_entry_referenced();
@@ -253,12 +252,11 @@
dynamic_table_insertion_blocked = true;
} else {
encoder_stream_sender_.SendInsertWithoutNameReference(name, value);
- auto entry = header_table_.InsertEntry(name, value);
+ uint64_t new_index = header_table_.InsertEntry(name, value);
instructions.push_back(EncodeIndexedHeaderField(
- /* is_static = */ false, entry->InsertionIndex(),
- referred_indices));
- smallest_blocking_index = std::min<uint64_t>(smallest_blocking_index,
- entry->InsertionIndex());
+ /* is_static = */ false, new_index, referred_indices));
+ smallest_blocking_index =
+ std::min<uint64_t>(smallest_blocking_index, new_index);
break;
}
diff --git a/quic/core/qpack/qpack_header_table.cc b/quic/core/qpack/qpack_header_table.cc
index 6171d84..e8d4c24 100644
--- a/quic/core/qpack/qpack_header_table.cc
+++ b/quic/core/qpack/qpack_header_table.cc
@@ -96,12 +96,15 @@
return MatchType::kNoMatch;
}
-const QpackEntry* QpackHeaderTable::InsertEntry(absl::string_view name,
- absl::string_view value) {
- const uint64_t entry_size = QpackEntry::Size(name, value);
- if (entry_size > dynamic_table_capacity_) {
- return nullptr;
- }
+bool QpackHeaderTable::EntryFitsDynamicTableCapacity(
+ absl::string_view name,
+ absl::string_view value) const {
+ return QpackEntry::Size(name, value) <= dynamic_table_capacity_;
+}
+
+uint64_t QpackHeaderTable::InsertEntry(absl::string_view name,
+ absl::string_view value) {
+ QUICHE_DCHECK(EntryFitsDynamicTableCapacity(name, value));
const uint64_t index = dropped_entry_count_ + dynamic_entries_.size();
dynamic_entries_.push_back({name, value, /* is_static = */ false, index});
@@ -109,7 +112,7 @@
// Evict entries after inserting the new entry instead of before
// in order to avoid invalidating |name| and |value|.
- dynamic_table_size_ += entry_size;
+ dynamic_table_size_ += QpackEntry::Size(name, value);
EvictDownToCurrentCapacity();
auto index_result = dynamic_index_.insert(new_entry);
@@ -147,7 +150,7 @@
observer->OnInsertCountReachedThreshold();
}
- return new_entry;
+ return index;
}
uint64_t QpackHeaderTable::MaxInsertSizeWithoutEvictingGivenEntry(
diff --git a/quic/core/qpack/qpack_header_table.h b/quic/core/qpack/qpack_header_table.h
index 4f0a1b5..0e9a5a5 100644
--- a/quic/core/qpack/qpack_header_table.h
+++ b/quic/core/qpack/qpack_header_table.h
@@ -75,11 +75,16 @@
bool* is_static,
uint64_t* index) const;
- // Insert (name, value) into the dynamic table. May evict entries. Returns a
- // pointer to the inserted owned entry on success. Returns nullptr if entry
- // is larger than the capacity of the dynamic table.
- const QpackEntry* InsertEntry(absl::string_view name,
- absl::string_view value);
+ // Returns whether an entry with |name| and |value| has a size (including
+ // overhead) that is smaller than or equal to the capacity of the dynamic
+ // table.
+ bool EntryFitsDynamicTableCapacity(absl::string_view name,
+ absl::string_view value) const;
+
+ // Inserts (name, value) into the dynamic table. Entry must not be larger
+ // than the capacity of the dynamic table. May evict entries. Returns the
+ // absolute index of the inserted dynamic table entry.
+ uint64_t InsertEntry(absl::string_view name, absl::string_view value);
// Returns the size of the largest entry that could be inserted into the
// dynamic table without evicting entry |index|. |index| might be larger than
diff --git a/quic/core/qpack/qpack_header_table_test.cc b/quic/core/qpack/qpack_header_table_test.cc
index 801ab8f..0af250e 100644
--- a/quic/core/qpack/qpack_header_table_test.cc
+++ b/quic/core/qpack/qpack_header_table_test.cc
@@ -81,13 +81,13 @@
<< name << ": " << value;
}
- void InsertEntry(absl::string_view name, absl::string_view value) {
- EXPECT_TRUE(table_.InsertEntry(name, value));
+ bool EntryFitsDynamicTableCapacity(absl::string_view name,
+ absl::string_view value) const {
+ return table_.EntryFitsDynamicTableCapacity(name, value);
}
- void ExpectToFailInsertingEntry(absl::string_view name,
- absl::string_view value) {
- EXPECT_FALSE(table_.InsertEntry(name, value));
+ void InsertEntry(absl::string_view name, absl::string_view value) {
+ table_.InsertEntry(name, value);
}
bool SetDynamicTableCapacity(uint64_t capacity) {
@@ -293,9 +293,6 @@
ExpectNoMatch("foo", "bar");
ExpectMatch("baz", "qux", QpackHeaderTable::MatchType::kNameAndValue,
/* expected_is_static = */ false, 1u);
-
- // Inserting an entry that does not fit results in error.
- ExpectToFailInsertingEntry("foobar", "foobar");
}
TEST_F(QpackHeaderTableTest, EvictByUpdateTableSize) {
@@ -389,7 +386,7 @@
table.MaxInsertSizeWithoutEvictingGivenEntry(0));
const uint64_t entry_size1 = QpackEntry::Size("foo", "bar");
- EXPECT_TRUE(table.InsertEntry("foo", "bar"));
+ table.InsertEntry("foo", "bar");
EXPECT_EQ(dynamic_table_capacity - entry_size1,
table.MaxInsertSizeWithoutEvictingGivenEntry(0));
// Table can take an entry up to its capacity if all entries are allowed to be
@@ -398,7 +395,7 @@
table.MaxInsertSizeWithoutEvictingGivenEntry(1));
const uint64_t entry_size2 = QpackEntry::Size("baz", "foobar");
- EXPECT_TRUE(table.InsertEntry("baz", "foobar"));
+ table.InsertEntry("baz", "foobar");
// Table can take an entry up to its capacity if all entries are allowed to be
// evicted.
EXPECT_EQ(dynamic_table_capacity,
@@ -412,7 +409,7 @@
// Third entry evicts first one.
const uint64_t entry_size3 = QpackEntry::Size("last", "entry");
- EXPECT_TRUE(table.InsertEntry("last", "entry"));
+ table.InsertEntry("last", "entry");
EXPECT_EQ(1u, table.dropped_entry_count());
// Table can take an entry up to its capacity if all entries are allowed to be
// evicted.
@@ -497,14 +494,14 @@
EXPECT_EQ(0u, table.draining_index(1.0));
// Table with one entry.
- EXPECT_TRUE(table.InsertEntry("foo", "bar"));
+ 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"));
+ 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));
@@ -513,8 +510,8 @@
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"));
+ table.InsertEntry("foo", "bar");
+ 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
@@ -533,6 +530,14 @@
table.reset();
}
+TEST_F(QpackHeaderTableTest, EntryFitsDynamicTableCapacity) {
+ EXPECT_TRUE(SetDynamicTableCapacity(39));
+
+ EXPECT_TRUE(EntryFitsDynamicTableCapacity("foo", "bar"));
+ EXPECT_TRUE(EntryFitsDynamicTableCapacity("foo", "bar2"));
+ EXPECT_FALSE(EntryFitsDynamicTableCapacity("foo", "bar12"));
+}
+
} // namespace
} // namespace test
} // namespace quic