Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Automated fix for refs/heads/hpack_use_vector #1

Open
wants to merge 2 commits into
base: hpack_use_vector
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
68 changes: 46 additions & 22 deletions src/core/ext/transport/chttp2/transport/hpack_parser_table.cc
Original file line number Diff line number Diff line change
Expand Up @@ -20,8 +20,9 @@

#include "src/core/ext/transport/chttp2/transport/hpack_parser_table.h"

#include <assert.h>
#include <string.h>
#include <cassert>
#include <cstddef>
#include <cstring>

#include "absl/strings/str_format.h"

Expand All @@ -38,17 +39,52 @@ extern grpc_core::TraceFlag grpc_http_trace;

namespace grpc_core {

void MementoRingBuffer::Put(Memento m) {
GPR_ASSERT(num_entries_ < max_entries_);
if (entries_.size() < max_entries_) {
++num_entries_;
return entries_.push_back(std::move(m));
}
size_t index = (first_entry_ + num_entries_) % max_entries_;
entries_[index] = std::move(m);
++num_entries_;
}

auto MementoRingBuffer::PopOne() -> Memento {
GPR_ASSERT(num_entries_ > 0);
size_t index = first_entry_ % max_entries_;
++first_entry_;
--num_entries_;
return std::move(entries_[index]);
}

auto MementoRingBuffer::Lookup(uint32_t index) const -> const Memento* {
if (index >= num_entries_) return nullptr;
uint32_t offset = (num_entries_ - 1u - index + first_entry_) % max_entries_;
return &entries_[offset];
}

void MementoRingBuffer::Rebuild(uint32_t max_entries) {
if (max_entries == max_entries_) return;
std::vector<Memento> entries;
entries.reserve(num_entries_);
for (size_t i = 0; i < num_entries_; i++) {
entries.push_back(
std::move(entries_[(first_entry_ + i) % entries_.size()]));
}
first_entry_ = 0;
entries_.swap(entries);
}

HPackTable::HPackTable() : static_metadata_(GetStaticMementos()) {}

HPackTable::~HPackTable() = default;

/* Evict one element from the table */
void HPackTable::EvictOne() {
auto first_entry = std::move(entries_[first_entry_]);
auto first_entry = entries_.PopOne();
GPR_ASSERT(first_entry.transport_size() <= mem_used_);
mem_used_ -= first_entry.transport_size();
first_entry_ = ((first_entry_ + 1) % entries_.size());
num_entries_--;
}

void HPackTable::Rebuild(uint32_t new_cap) {
Expand Down Expand Up @@ -90,18 +126,9 @@ grpc_error_handle HPackTable::SetCurrentTableSize(uint32_t bytes) {
EvictOne();
}
current_table_bytes_ = bytes;
max_entries_ = hpack_constants::EntriesForBytes(bytes);
if (max_entries_ > entries_.size()) {
Rebuild(max_entries_);
} else if (max_entries_ < entries_.size() / 3) {
// TODO(ctiller): move to resource quota system, only shrink under memory
// pressure
uint32_t new_cap =
std::max(max_entries_, static_cast<uint32_t>(kInlineEntries));
if (new_cap != entries_.size()) {
Rebuild(new_cap);
}
}
uint32_t new_cap = std::max(hpack_constants::EntriesForBytes(bytes),
hpack_constants::kInitialTableEntries);
entries_.Rebuild(new_cap);
return GRPC_ERROR_NONE;
}

Expand All @@ -122,7 +149,7 @@ grpc_error_handle HPackTable::Add(Memento md) {
// attempt to add an entry larger than the entire table causes
// the table to be emptied of all existing entries, and results in an
// empty table.
while (num_entries_) {
while (entries_.num_entries()) {
EvictOne();
}
return GRPC_ERROR_NONE;
Expand All @@ -136,10 +163,7 @@ grpc_error_handle HPackTable::Add(Memento md) {

// copy the finalized entry in
mem_used_ += md.transport_size();
entries_[(first_entry_ + num_entries_) % entries_.size()] = std::move(md);

// update accounting values
num_entries_++;
entries_.Put(std::move(md));
return GRPC_ERROR_NONE;
}

Expand Down
59 changes: 38 additions & 21 deletions src/core/ext/transport/chttp2/transport/hpack_parser_table.h
Original file line number Diff line number Diff line change
Expand Up @@ -30,6 +30,40 @@

namespace grpc_core {

using Memento = ParsedMetadata<grpc_metadata_batch>;

class MementoRingBuffer {
public:
// Rebuild this buffer with a new max_entries_ size.
void Rebuild(uint32_t max_entries);

// Put a new memento.
// REQUIRES: num_entries < max_entries
void Put(Memento m);

// Pop the oldest memento.
// REQUIRES: num_entries > 0
Memento PopOne();

// Lookup the entry at index, or return nullptr if none exists.
const Memento* Lookup(uint32_t index) const;

uint32_t max_entries() const { return max_entries_; }
uint32_t num_entries() const { return num_entries_; }

private:
// The index of the first entry in the buffer. May be greater than
// max_entries_, in which case a wraparound has occurred.
uint32_t first_entry_ = 0;
// How many entries are in the table.
uint32_t num_entries_ = 0;
// Maximum number of entries we could possibly fit in the table, given defined
// overheads.
uint32_t max_entries_ = hpack_constants::kInitialTableEntries;

std::vector<Memento> entries_;
};

// HPACK header table
class HPackTable {
public:
Expand All @@ -42,7 +76,7 @@ class HPackTable {
void SetMaxBytes(uint32_t max_bytes);
grpc_error_handle SetCurrentTableSize(uint32_t bytes);

using Memento = ParsedMetadata<grpc_metadata_batch>;
using Memento = Memento;

// Lookup, but don't ref.
const Memento* Lookup(uint32_t index) const {
Expand All @@ -63,7 +97,7 @@ class HPackTable {
grpc_error_handle Add(Memento md) GRPC_MUST_USE_RESULT;

// Current entry count in the table.
uint32_t num_entries() const { return num_entries_; }
uint32_t num_entries() const { return entries_.num_entries(); }

private:
struct StaticMementos {
Expand All @@ -72,40 +106,23 @@ class HPackTable {
};
static const StaticMementos& GetStaticMementos() GPR_ATTRIBUTE_NOINLINE;

enum { kInlineEntries = hpack_constants::kInitialTableEntries };
using EntriesVec = absl::InlinedVector<Memento, kInlineEntries>;

const Memento* LookupDynamic(uint32_t index) const {
// Not static - find the value in the list of valid entries
const uint32_t tbl_index = index - (hpack_constants::kLastStaticEntry + 1);
if (tbl_index < num_entries_) {
uint32_t offset =
(num_entries_ - 1u - tbl_index + first_entry_) % entries_.size();
return &entries_[offset];
}
// Invalid entry: return error
return nullptr;
return entries_.Lookup(tbl_index);
}

void EvictOne();
void Rebuild(uint32_t new_cap);

// The first used entry in ents.
uint32_t first_entry_ = 0;
// How many entries are in the table.
uint32_t num_entries_ = 0;
// The amount of memory used by the table, according to the hpack algorithm
uint32_t mem_used_ = 0;
// The max memory allowed to be used by the table, according to the hpack
// algorithm.
uint32_t max_bytes_ = hpack_constants::kInitialTableSize;
// The currently agreed size of the table, according to the hpack algorithm.
uint32_t current_table_bytes_ = hpack_constants::kInitialTableSize;
// Maximum number of entries we could possibly fit in the table, given defined
// overheads.
uint32_t max_entries_ = hpack_constants::kInitialTableEntries;
// HPack table entries
EntriesVec entries_{hpack_constants::kInitialTableEntries};
MementoRingBuffer entries_;
// Mementos for static data
const StaticMementos& static_metadata_;
};
Expand Down