blob: 8536a8523fc4ce5a796d62c878a58bbad10d0f79 [file] [log] [blame]
QUICHE team82dee2f2019-01-18 12:35:12 -05001// Copyright 2014 The Chromium Authors. All rights reserved.
2// Use of this source code is governed by a BSD-style license that can be
3// found in the LICENSE file.
4
QUICHE team5be974e2020-12-29 18:35:24 -05005#include "spdy/core/hpack/hpack_header_table.h"
QUICHE team82dee2f2019-01-18 12:35:12 -05006
7#include <algorithm>
8
QUICHE team1b5d09e2021-04-08 13:36:42 -07009#include "common/platform/api/quiche_logging.h"
QUICHE team5be974e2020-12-29 18:35:24 -050010#include "spdy/core/hpack/hpack_constants.h"
11#include "spdy/core/hpack/hpack_static_table.h"
QUICHE team5be974e2020-12-29 18:35:24 -050012#include "spdy/platform/api/spdy_estimate_memory_usage.h"
QUICHE team82dee2f2019-01-18 12:35:12 -050013
14namespace spdy {
15
QUICHE team82dee2f2019-01-18 12:35:12 -050016HpackHeaderTable::HpackHeaderTable()
17 : static_entries_(ObtainHpackStaticTable().GetStaticEntries()),
18 static_index_(ObtainHpackStaticTable().GetStaticIndex()),
19 static_name_index_(ObtainHpackStaticTable().GetStaticNameIndex()),
20 settings_size_bound_(kDefaultHeaderTableSizeSetting),
21 size_(0),
22 max_size_(kDefaultHeaderTableSizeSetting),
bncf5f8d702021-03-19 10:50:35 -070023 dynamic_table_insertions_(0) {}
QUICHE team82dee2f2019-01-18 12:35:12 -050024
25HpackHeaderTable::~HpackHeaderTable() = default;
26
bnca6c0a702021-03-16 10:39:14 -070027size_t HpackHeaderTable::GetByName(absl::string_view name) {
QUICHE team82dee2f2019-01-18 12:35:12 -050028 {
29 auto it = static_name_index_.find(name);
30 if (it != static_name_index_.end()) {
bncc2362402021-03-23 11:56:11 -070031 return 1 + it->second;
QUICHE team82dee2f2019-01-18 12:35:12 -050032 }
33 }
34 {
35 NameToEntryMap::const_iterator it = dynamic_name_index_.find(name);
36 if (it != dynamic_name_index_.end()) {
bncc2362402021-03-23 11:56:11 -070037 return dynamic_table_insertions_ - it->second + kStaticTableSize;
QUICHE team82dee2f2019-01-18 12:35:12 -050038 }
39 }
bnca6c0a702021-03-16 10:39:14 -070040 return kHpackEntryNotFound;
QUICHE team82dee2f2019-01-18 12:35:12 -050041}
42
bnca6c0a702021-03-16 10:39:14 -070043size_t HpackHeaderTable::GetByNameAndValue(absl::string_view name,
44 absl::string_view value) {
bnc7dcfe322021-03-18 09:49:08 -070045 HpackLookupEntry query{name, value};
QUICHE team82dee2f2019-01-18 12:35:12 -050046 {
bnc7dcfe322021-03-18 09:49:08 -070047 auto it = static_index_.find(query);
QUICHE team82dee2f2019-01-18 12:35:12 -050048 if (it != static_index_.end()) {
bncc2362402021-03-23 11:56:11 -070049 return 1 + it->second;
QUICHE team82dee2f2019-01-18 12:35:12 -050050 }
51 }
52 {
bnc7dcfe322021-03-18 09:49:08 -070053 auto it = dynamic_index_.find(query);
QUICHE team82dee2f2019-01-18 12:35:12 -050054 if (it != dynamic_index_.end()) {
bncc2362402021-03-23 11:56:11 -070055 return dynamic_table_insertions_ - it->second + kStaticTableSize;
QUICHE team82dee2f2019-01-18 12:35:12 -050056 }
57 }
bnca6c0a702021-03-16 10:39:14 -070058 return kHpackEntryNotFound;
QUICHE team82dee2f2019-01-18 12:35:12 -050059}
60
61void HpackHeaderTable::SetMaxSize(size_t max_size) {
vasilvved4f3082021-02-01 14:29:40 -080062 QUICHE_CHECK_LE(max_size, settings_size_bound_);
QUICHE team82dee2f2019-01-18 12:35:12 -050063
64 max_size_ = max_size;
65 if (size_ > max_size_) {
66 Evict(EvictionCountToReclaim(size_ - max_size_));
vasilvved4f3082021-02-01 14:29:40 -080067 QUICHE_CHECK_LE(size_, max_size_);
QUICHE team82dee2f2019-01-18 12:35:12 -050068 }
69}
70
71void HpackHeaderTable::SetSettingsHeaderTableSize(size_t settings_size) {
72 settings_size_bound_ = settings_size;
73 SetMaxSize(settings_size_bound_);
74}
75
vasilvva89e7fa2020-10-12 21:35:05 -070076void HpackHeaderTable::EvictionSet(absl::string_view name,
77 absl::string_view value,
bnc80a178f2021-03-23 13:07:47 -070078 DynamicEntryTable::iterator* begin_out,
79 DynamicEntryTable::iterator* end_out) {
QUICHE team82dee2f2019-01-18 12:35:12 -050080 size_t eviction_count = EvictionCountForEntry(name, value);
81 *begin_out = dynamic_entries_.end() - eviction_count;
82 *end_out = dynamic_entries_.end();
83}
84
vasilvva89e7fa2020-10-12 21:35:05 -070085size_t HpackHeaderTable::EvictionCountForEntry(absl::string_view name,
86 absl::string_view value) const {
QUICHE team82dee2f2019-01-18 12:35:12 -050087 size_t available_size = max_size_ - size_;
88 size_t entry_size = HpackEntry::Size(name, value);
89
90 if (entry_size <= available_size) {
91 // No evictions are required.
92 return 0;
93 }
94 return EvictionCountToReclaim(entry_size - available_size);
95}
96
97size_t HpackHeaderTable::EvictionCountToReclaim(size_t reclaim_size) const {
98 size_t count = 0;
99 for (auto it = dynamic_entries_.rbegin();
100 it != dynamic_entries_.rend() && reclaim_size != 0; ++it, ++count) {
101 reclaim_size -= std::min(reclaim_size, it->Size());
102 }
103 return count;
104}
105
106void HpackHeaderTable::Evict(size_t count) {
107 for (size_t i = 0; i != count; ++i) {
vasilvved4f3082021-02-01 14:29:40 -0800108 QUICHE_CHECK(!dynamic_entries_.empty());
bncc2362402021-03-23 11:56:11 -0700109
QUICHE team82dee2f2019-01-18 12:35:12 -0500110 HpackEntry* entry = &dynamic_entries_.back();
bncc2362402021-03-23 11:56:11 -0700111 const size_t index = dynamic_table_insertions_ - dynamic_entries_.size();
QUICHE team82dee2f2019-01-18 12:35:12 -0500112
113 size_ -= entry->Size();
bnc7dcfe322021-03-18 09:49:08 -0700114 auto it = dynamic_index_.find({entry->name(), entry->value()});
vasilvved4f3082021-02-01 14:29:40 -0800115 QUICHE_DCHECK(it != dynamic_index_.end());
QUICHE team82dee2f2019-01-18 12:35:12 -0500116 // Only remove an entry from the index if its insertion index matches;
117 // otherwise, the index refers to another entry with the same name and
118 // value.
bncc2362402021-03-23 11:56:11 -0700119 if (it->second == index) {
QUICHE team82dee2f2019-01-18 12:35:12 -0500120 dynamic_index_.erase(it);
121 }
122 auto name_it = dynamic_name_index_.find(entry->name());
vasilvved4f3082021-02-01 14:29:40 -0800123 QUICHE_DCHECK(name_it != dynamic_name_index_.end());
QUICHE team82dee2f2019-01-18 12:35:12 -0500124 // Only remove an entry from the literal index if its insertion index
125 /// matches; otherwise, the index refers to another entry with the same
126 // name.
bncc2362402021-03-23 11:56:11 -0700127 if (name_it->second == index) {
QUICHE team82dee2f2019-01-18 12:35:12 -0500128 dynamic_name_index_.erase(name_it);
129 }
130 dynamic_entries_.pop_back();
131 }
132}
133
vasilvva89e7fa2020-10-12 21:35:05 -0700134const HpackEntry* HpackHeaderTable::TryAddEntry(absl::string_view name,
135 absl::string_view value) {
bnccf5276d2021-03-18 11:35:09 -0700136 // Since |dynamic_entries_| has iterator stability, |name| and |value| are
bnc2dd24002021-04-05 11:13:54 -0700137 // valid even after evicting other entries and push_front() making room for
bnccf5276d2021-03-18 11:35:09 -0700138 // the new one.
QUICHE team82dee2f2019-01-18 12:35:12 -0500139 Evict(EvictionCountForEntry(name, value));
140
141 size_t entry_size = HpackEntry::Size(name, value);
142 if (entry_size > (max_size_ - size_)) {
143 // Entire table has been emptied, but there's still insufficient room.
vasilvved4f3082021-02-01 14:29:40 -0800144 QUICHE_DCHECK(dynamic_entries_.empty());
145 QUICHE_DCHECK_EQ(0u, size_);
QUICHE team82dee2f2019-01-18 12:35:12 -0500146 return nullptr;
147 }
bncc2362402021-03-23 11:56:11 -0700148
149 const size_t index = dynamic_table_insertions_;
bnc2dd24002021-04-05 11:13:54 -0700150 dynamic_entries_.push_front(
151 HpackEntry(std::string(name), std::string(value)));
QUICHE team82dee2f2019-01-18 12:35:12 -0500152 HpackEntry* new_entry = &dynamic_entries_.front();
bnc7dcfe322021-03-18 09:49:08 -0700153 auto index_result = dynamic_index_.insert(std::make_pair(
bncc2362402021-03-23 11:56:11 -0700154 HpackLookupEntry{new_entry->name(), new_entry->value()}, index));
QUICHE team82dee2f2019-01-18 12:35:12 -0500155 if (!index_result.second) {
156 // An entry with the same name and value already exists in the dynamic
157 // index. We should replace it with the newly added entry.
QUICHE team1b5d09e2021-04-08 13:36:42 -0700158 QUICHE_DVLOG(1) << "Found existing entry at: " << index_result.first->second
159 << " replacing with: " << new_entry->GetDebugString()
160 << " at: " << index;
bncc2362402021-03-23 11:56:11 -0700161 QUICHE_DCHECK_GT(index, index_result.first->second);
QUICHE team82dee2f2019-01-18 12:35:12 -0500162 dynamic_index_.erase(index_result.first);
bnc7dcfe322021-03-18 09:49:08 -0700163 auto insert_result = dynamic_index_.insert(std::make_pair(
bncc2362402021-03-23 11:56:11 -0700164 HpackLookupEntry{new_entry->name(), new_entry->value()}, index));
bnc7dcfe322021-03-18 09:49:08 -0700165 QUICHE_CHECK(insert_result.second);
QUICHE team82dee2f2019-01-18 12:35:12 -0500166 }
167
168 auto name_result =
bncc2362402021-03-23 11:56:11 -0700169 dynamic_name_index_.insert(std::make_pair(new_entry->name(), index));
QUICHE team82dee2f2019-01-18 12:35:12 -0500170 if (!name_result.second) {
171 // An entry with the same name already exists in the dynamic index. We
172 // should replace it with the newly added entry.
QUICHE team1b5d09e2021-04-08 13:36:42 -0700173 QUICHE_DVLOG(1) << "Found existing entry at: " << name_result.first->second
174 << " replacing with: " << new_entry->GetDebugString()
175 << " at: " << index;
bncc2362402021-03-23 11:56:11 -0700176 QUICHE_DCHECK_GT(index, name_result.first->second);
QUICHE team82dee2f2019-01-18 12:35:12 -0500177 dynamic_name_index_.erase(name_result.first);
bncc2362402021-03-23 11:56:11 -0700178 auto insert_result =
179 dynamic_name_index_.insert(std::make_pair(new_entry->name(), index));
vasilvved4f3082021-02-01 14:29:40 -0800180 QUICHE_CHECK(insert_result.second);
QUICHE team82dee2f2019-01-18 12:35:12 -0500181 }
182
183 size_ += entry_size;
bncf5f8d702021-03-19 10:50:35 -0700184 ++dynamic_table_insertions_;
QUICHE team82dee2f2019-01-18 12:35:12 -0500185
186 return &dynamic_entries_.front();
187}
188
QUICHE team82dee2f2019-01-18 12:35:12 -0500189size_t HpackHeaderTable::EstimateMemoryUsage() const {
190 return SpdyEstimateMemoryUsage(dynamic_entries_) +
191 SpdyEstimateMemoryUsage(dynamic_index_) +
192 SpdyEstimateMemoryUsage(dynamic_name_index_);
193}
194
195} // namespace spdy