proxygen
HeaderTable.cpp
Go to the documentation of this file.
1 /*
2  * Copyright (c) 2015-present, Facebook, Inc.
3  * All rights reserved.
4  *
5  * This source code is licensed under the BSD-style license found in the
6  * LICENSE file in the root directory of this source tree. An additional grant
7  * of patent rights can be found in the PATENTS file in the same directory.
8  *
9  */
11 
12 #include <glog/logging.h>
13 
14 using std::list;
15 using std::pair;
16 using std::string;
17 
18 namespace proxygen {
19 
20 void HeaderTable::init(uint32_t capacityVal) {
21  bytes_ = 0;
22  size_ = 0;
23  head_ = 0;
24  capacity_ = capacityVal;
25  uint32_t initLength = getMaxTableLength(capacity_) / 2;
26  table_.reserve(initLength);
27  for (uint32_t i = 0; i < initLength; i++) {
28  table_.emplace_back();
29  }
30  names_.clear();
31 }
32 
34  if (header.bytes() > capacity_) {
35  // Per the RFC spec https://tools.ietf.org/html/rfc7541#page-11, we must
36  // flush the underlying table if a request is made for a header that is
37  // larger than the current table capacity
38  reset();
39  return false;
40  }
41 
42  // Make the necessary room in the table if appropriate per RFC spec
43  if ((bytes_ + header.bytes()) > capacity_) {
44  if (evict(header.bytes(), capacity_) == 0) {
45  return false;
46  }
47  }
48 
49  if (size_ == length()) {
52  }
53  head_ = next(head_);
54  // index name
55  names_[header.name].push_back(head_);
56  bytes_ += header.bytes();
57  table_[head_] = std::move(header);
58 
59  ++size_;
60  return true;
61 }
62 
64  return getIndexImpl(header.name, header.value, false);
65 }
66 
68  const folly::fbstring& value,
69  bool nameOnly) const {
70  auto it = names_.find(headerName);
71  if (it == names_.end()) {
72  return 0;
73  }
74  for (auto indexIt = it->second.rbegin(); indexIt != it->second.rend();
75  ++indexIt) {
76  auto i = *indexIt;
77  if (nameOnly || table_[i].value == value) {
78  return toExternal(i);
79  }
80  }
81  return 0;
82 }
83 
84 bool HeaderTable::hasName(const HPACKHeaderName& headerName) {
85  return names_.find(headerName) != names_.end();
86 }
87 
90  return getIndexImpl(headerName, value, true /* name only */);
91 }
92 
94  CHECK(isValid(index));
95  return table_[toInternal(index)];
96 }
97 
99  // At a minimum an entry will take 32 bytes
100  // No need to add an extra slot; i.e. a capacity of 32 to 63 bytes can hold
101  // at most one entry.
102  return (capacityVal >> 5);
103 }
104 
106  auto t = tail();
107  // remove the first element from the names index
108  auto names_it = names_.find(table_[t].name);
109  DCHECK(names_it != names_.end());
110  auto &ilist = names_it->second;
111  DCHECK_EQ(ilist.front(), t);
112  ilist.pop_front();
113 
114  // remove the name if there are no indices associated with it
115  if (ilist.empty()) {
116  names_.erase(names_it);
117  }
118  const auto& header = table_[t];
119  uint32_t headerBytes = header.bytes();
120  bytes_ -= headerBytes;
121  VLOG(10) << "Removing local idx=" << t << " name=" << header.name
122  << " value=" << header.value;
123  --size_;
124  return headerBytes;
125 }
126 
128  names_.clear();
129 
130  bytes_ = 0;
131  size_ = 0;
132 
133  // Capacity remains unchanged and for now we leave head_ index the same
134 }
135 
137  if (newCapacity == capacity_) {
138  return true;
139  } else if (newCapacity < capacity_) {
140  // NOTE: currently no actual resizing is performed...
141  evict(0, newCapacity);
142  if (bytes_ > newCapacity) {
143  // eviction failed!
144  return false;
145  }
146  } else {
147  // NOTE: due to the above lack of resizing, we must determine whether a
148  // resize is actually appropriate (to handle cases where the underlying
149  // vector is still >= to the size related to the new capacity requested)
150  uint32_t newLength = getMaxTableLength(newCapacity) / 2;
151  if (newLength > length()) {
152  increaseTableLengthTo(newLength);
153  }
154  }
155  capacity_ = newCapacity;
156  return true;
157 }
158 
160  DCHECK_GE(newLength, length());
161  uint32_t oldTail = (size_ > 0) ? tail() : 0;
162  auto oldLength = length();
163  resizeTable(newLength);
164 
165  // TODO: referenence to head here is incompatible with baseIndex
166  if (size_ > 0 && oldTail > head_) {
167  // the list wrapped around, need to move oldTail..oldLength to the end
168  // of the now-larger table_
169  updateResizedTable(oldTail, oldLength, newLength);
170  // Update the names indecies that pointed to the old range
171  for (auto& names_it: names_) {
172  for (auto& idx: names_it.second) {
173  if (idx >= oldTail) {
174  DCHECK_LT(idx + (length() - oldLength), length());
175  idx += (length() - oldLength);
176  } else {
177  // remaining indecies in the list were smaller than oldTail, so
178  // should be indexed from 0
179  break;
180  }
181  }
182  }
183  }
184 }
185 
187  table_.resize(newLength);
188 }
189 
191  uint32_t newLength) {
192  std::move_backward(table_.begin() + oldTail, table_.begin() + oldLength,
193  table_.begin() + newLength);
194 }
195 
196 uint32_t HeaderTable::evict(uint32_t needed, uint32_t desiredCapacity) {
197  uint32_t previousSize = size_;
198  while (size_ > 0 && (bytes_ + needed > desiredCapacity)) {
199  removeLast();
200  }
201  return previousSize - size_;
202 }
203 
204 bool HeaderTable::isValid(uint32_t index) const {
205  bool result = false;
206  result = 0 < index && index <= size_;
207  if (!result) {
208  LOG(ERROR) << "Invalid index=" << index << " size_=" << size_;
209  }
210  return result;
211 }
212 
214  return (i + 1) % length();
215 }
216 
218  // tail is private, and only called in the encoder, where head_ is always
219  // valid
220  DCHECK_GT(size_, 0) << "tail() undefined";
221  return (head_ + length() - size_ + 1) % length();
222 }
223 
225  return toExternal(head_, length(), internalIndex);
226 }
227 
229  uint32_t internalIndex) {
230  return ((head + length - internalIndex) % length) + 1;
231 }
232 
234  return toInternal(head_, length(), externalIndex);
235 }
236 
238  uint32_t externalIndex) {
239  // remove the offset
240  --externalIndex;
241  return (head + length - externalIndex) % length;
242 }
243 
244 bool HeaderTable::operator==(const HeaderTable& other) const {
245  if (size() != other.size()) {
246  return false;
247  }
248  if (bytes() != other.bytes()) {
249  return false;
250  }
251  return true;
252 }
253 
254 std::ostream& operator<<(std::ostream& os, const HeaderTable& table) {
255  os << std::endl;
256  for (size_t i = 1; i <= table.size(); i++) {
257  const HPACKHeader& h = table.getHeader(i);
258  os << '[' << i << "] (s=" << h.bytes() << ") "
259  << h.name << ": " << h.value << std::endl;
260  }
261  os << "total size: " << table.bytes() << std::endl;
262  return os;
263 }
264 
265 }
*than *hazptr_holder h
Definition: Hazptr.h:116
constexpr To ceil(std::chrono::duration< Rep, Period > const &d)
Definition: Chrono.h:91
virtual uint32_t evict(uint32_t needed, uint32_t desiredCapacity)
std::ostream & operator<<(std::ostream &os, const HeaderTable &table)
bool operator==(const HeaderTable &other) const
bool hasName(const HPACKHeaderName &headerName)
Definition: HeaderTable.cpp:84
uint32_t getMaxTableLength(uint32_t capacityVal)
Definition: HeaderTable.cpp:98
constexpr detail::Map< Move > move
Definition: Base-inl.h:2567
const HPACKHeader & getHeader(uint32_t index) const
Definition: HeaderTable.cpp:93
uint32_t bytes() const
Definition: HeaderTable.h:112
bool isValid(uint32_t index) const
uint32_t next(uint32_t i) const
static uint32_t toExternal(uint32_t head, uint32_t length, uint32_t internalIndex)
uint32_t getIndexImpl(const HPACKHeaderName &header, const folly::fbstring &value, bool nameOnly) const
Definition: HeaderTable.cpp:67
virtual void increaseTableLengthTo(uint32_t newLength)
const char * name
Definition: http_parser.c:437
uint32_t bytes() const
Definition: HPACKHeader.h:49
LogLevel min
Definition: LogLevel.cpp:30
Encoder::MutableCompressedList list
static uint32_t toInternal(uint32_t head, uint32_t length, uint32_t externalIndex)
size_t length() const
Definition: HeaderTable.h:119
HPACKHeaderName name
Definition: HPACKHeader.h:82
static const char *const value
Definition: Conv.cpp:50
uint32_t nameIndex(const HPACKHeaderName &headerName) const
Definition: HeaderTable.cpp:88
virtual void updateResizedTable(uint32_t oldTail, uint32_t oldLength, uint32_t newLength)
virtual uint32_t removeLast()
folly::fbstring value
Definition: HPACKHeader.h:83
void init(uint32_t capacityVal)
Definition: HeaderTable.cpp:20
virtual void resizeTable(uint32_t newLength)
const char * string
Definition: Conv.cpp:212
std::vector< HPACKHeader > table_
Definition: HeaderTable.h:189
virtual bool setCapacity(uint32_t capacity)
uint32_t size() const
Definition: HeaderTable.h:105
uint32_t tail() const
uint32_t getIndex(const HPACKHeader &header) const
Definition: HeaderTable.cpp:63
virtual bool add(HPACKHeader header)
Definition: HeaderTable.cpp:33