aboutsummaryrefslogtreecommitdiffhomepage
path: root/src/core/transport/chttp2/hpack_table.c
diff options
context:
space:
mode:
authorGravatar Craig Tiller <craig.tiller@gmail.com>2015-11-10 08:37:46 +0000
committerGravatar Craig Tiller <craig.tiller@gmail.com>2015-11-10 08:37:46 +0000
commit027a74cd3b3ce350ba5890d0fd8f6399a200227f (patch)
treee192513c5db0291fb4487cce7e9d2fb34d8674e5 /src/core/transport/chttp2/hpack_table.c
parent83e73373cb63be5ec5a97d894e7a06faf81d3df8 (diff)
First round changes to handle dynamic hpack table size
Diffstat (limited to 'src/core/transport/chttp2/hpack_table.c')
-rw-r--r--src/core/transport/chttp2/hpack_table.c95
1 files changed, 79 insertions, 16 deletions
diff --git a/src/core/transport/chttp2/hpack_table.c b/src/core/transport/chttp2/hpack_table.c
index c442c2c341..fde74b3acd 100644
--- a/src/core/transport/chttp2/hpack_table.c
+++ b/src/core/transport/chttp2/hpack_table.c
@@ -36,7 +36,9 @@
#include <assert.h>
#include <string.h>
+#include <grpc/support/alloc.h>
#include <grpc/support/log.h>
+
#include "src/core/support/murmur_hash.h"
static struct {
@@ -169,12 +171,19 @@ static struct {
{"www-authenticate", ""},
};
+static gpr_uint32 entries_for_bytes(gpr_uint32 bytes) {
+ return (bytes + GRPC_CHTTP2_HPACK_ENTRY_OVERHEAD - 1) / GRPC_CHTTP2_HPACK_ENTRY_OVERHEAD;
+}
+
void grpc_chttp2_hptbl_init(grpc_chttp2_hptbl *tbl, grpc_mdctx *mdctx) {
size_t i;
memset(tbl, 0, sizeof(*tbl));
tbl->mdctx = mdctx;
- tbl->max_bytes = GRPC_CHTTP2_INITIAL_HPACK_TABLE_SIZE;
+ tbl->current_table_bytes = tbl->max_bytes = GRPC_CHTTP2_INITIAL_HPACK_TABLE_SIZE;
+ tbl->max_entries = tbl->cap_entries = entries_for_bytes(tbl->current_table_bytes);
+ tbl->ents = gpr_malloc(sizeof(*tbl->ents) * tbl->cap_entries);
+ memset(tbl->ents, 0, sizeof(*tbl->ents) * tbl->cap_entries);
for (i = 1; i <= GRPC_CHTTP2_LAST_STATIC_ENTRY; i++) {
tbl->static_ents[i - 1] = grpc_mdelem_from_strings(
mdctx, static_table[i].key, static_table[i].value);
@@ -188,7 +197,7 @@ void grpc_chttp2_hptbl_destroy(grpc_chttp2_hptbl *tbl) {
}
for (i = 0; i < tbl->num_ents; i++) {
GRPC_MDELEM_UNREF(
- tbl->ents[(tbl->first_ent + i) % GRPC_CHTTP2_MAX_TABLE_COUNT]);
+ tbl->ents[(tbl->first_ent + i) % tbl->cap_entries]);
}
}
@@ -202,7 +211,7 @@ grpc_mdelem *grpc_chttp2_hptbl_lookup(const grpc_chttp2_hptbl *tbl,
tbl_index -= (GRPC_CHTTP2_LAST_STATIC_ENTRY + 1);
if (tbl_index < tbl->num_ents) {
gpr_uint32 offset = (tbl->num_ents - 1u - tbl_index + tbl->first_ent) %
- GRPC_CHTTP2_MAX_TABLE_COUNT;
+ tbl->cap_entries;
return tbl->ents[offset];
}
/* Invalid entry: return error */
@@ -216,21 +225,74 @@ static void evict1(grpc_chttp2_hptbl *tbl) {
GPR_SLICE_LENGTH(first_ent->value->slice) +
GRPC_CHTTP2_HPACK_ENTRY_OVERHEAD;
GPR_ASSERT(elem_bytes <= tbl->mem_used);
- tbl->mem_used = (gpr_uint16)(tbl->mem_used - elem_bytes);
+ tbl->mem_used -= elem_bytes;
tbl->first_ent =
- (gpr_uint16)((tbl->first_ent + 1) % GRPC_CHTTP2_MAX_TABLE_COUNT);
+ ((tbl->first_ent + 1) % tbl->cap_entries);
tbl->num_ents--;
GRPC_MDELEM_UNREF(first_ent);
}
-void grpc_chttp2_hptbl_add(grpc_chttp2_hptbl *tbl, grpc_mdelem *md) {
+static void rebuild_ents(grpc_chttp2_hptbl *tbl, gpr_uint32 new_cap) {
+ grpc_mdelem **ents = gpr_malloc(sizeof(*ents) * new_cap);
+ gpr_uint32 i;
+
+ for (i = 0; i < tbl->num_ents; i++) {
+ ents[i] = tbl->ents[(tbl->first_ent + i) % tbl->cap_entries];
+ }
+ gpr_free(tbl->ents);
+ tbl->cap_entries = new_cap;
+ tbl->first_ent = 0;
+}
+
+void grpc_chttp2_hptbl_set_max_bytes(grpc_chttp2_hptbl *tbl, gpr_uint32 max_bytes) {
+ if (tbl->max_bytes == max_bytes) {
+ return;
+ }
+ gpr_log(GPR_DEBUG, "Update hpack parser max size to %d", max_bytes);
+ while (tbl->mem_used > max_bytes) {
+ evict1(tbl);
+ }
+ tbl->max_bytes = max_bytes;
+}
+
+int grpc_chttp2_hptbl_set_current_table_size(grpc_chttp2_hptbl *tbl, gpr_uint32 bytes) {
+ if (tbl->current_table_bytes == bytes) {
+ return 1;
+ }
+ if (bytes > tbl->max_bytes) {
+ gpr_log(GPR_ERROR, "Attempt to make hpack table %d bytes when max is %d bytes", bytes, tbl->max_bytes);
+ return 0;
+ }
+ gpr_log(GPR_DEBUG, "Update hpack parser table size to %d", bytes);
+ while (tbl->mem_used > bytes) {
+ evict1(tbl);
+ }
+ tbl->current_table_bytes = bytes;
+ tbl->max_entries = entries_for_bytes(bytes);
+ if (tbl->max_entries > tbl->cap_entries) {
+ rebuild_ents(tbl, GPR_MAX(tbl->max_entries, 2 * tbl->cap_entries));
+ } else if (tbl->max_entries < tbl->cap_entries / 3) {
+ gpr_uint32 new_cap = GPR_MAX(tbl->max_entries, 16u);
+ if (new_cap != tbl->cap_entries) {
+ rebuild_ents(tbl, new_cap);
+ }
+ }
+ return 1;
+}
+
+int grpc_chttp2_hptbl_add(grpc_chttp2_hptbl *tbl, grpc_mdelem *md) {
/* determine how many bytes of buffer this entry represents */
size_t elem_bytes = GPR_SLICE_LENGTH(md->key->slice) +
GPR_SLICE_LENGTH(md->value->slice) +
GRPC_CHTTP2_HPACK_ENTRY_OVERHEAD;
+ if (tbl->current_table_bytes > tbl->max_bytes) {
+ gpr_log(GPR_ERROR, "HPACK max table size reduced to %d but not reflected by hpack stream", tbl->max_bytes);
+ return 0;
+ }
+
/* we can't add elements bigger than the max table size */
- if (elem_bytes > tbl->max_bytes) {
+ if (elem_bytes > tbl->current_table_bytes) {
/* HPACK draft 10 section 4.4 states:
* If the size of the new entry is less than or equal to the maximum
* size, that entry is added to the table. It is not an error to
@@ -243,11 +305,11 @@ void grpc_chttp2_hptbl_add(grpc_chttp2_hptbl *tbl, grpc_mdelem *md) {
while (tbl->num_ents) {
evict1(tbl);
}
- return;
+ return 1;
}
/* evict entries to ensure no overflow */
- while (elem_bytes > (size_t)tbl->max_bytes - tbl->mem_used) {
+ while (elem_bytes > (size_t)tbl->current_table_bytes - tbl->mem_used) {
evict1(tbl);
}
@@ -256,31 +318,32 @@ void grpc_chttp2_hptbl_add(grpc_chttp2_hptbl *tbl, grpc_mdelem *md) {
/* update accounting values */
tbl->last_ent =
- (gpr_uint16)((tbl->last_ent + 1) % GRPC_CHTTP2_MAX_TABLE_COUNT);
+ ((tbl->last_ent + 1) % tbl->cap_entries);
tbl->num_ents++;
- tbl->mem_used = (gpr_uint16)(tbl->mem_used + elem_bytes);
+ tbl->mem_used += elem_bytes;
+ return 1;
}
grpc_chttp2_hptbl_find_result grpc_chttp2_hptbl_find(
const grpc_chttp2_hptbl *tbl, grpc_mdelem *md) {
grpc_chttp2_hptbl_find_result r = {0, 0};
- gpr_uint16 i;
+ gpr_uint32 i;
/* See if the string is in the static table */
for (i = 0; i < GRPC_CHTTP2_LAST_STATIC_ENTRY; i++) {
grpc_mdelem *ent = tbl->static_ents[i];
if (md->key != ent->key) continue;
- r.index = (gpr_uint16)(i + 1);
+ r.index = i + 1u;
r.has_value = md->value == ent->value;
if (r.has_value) return r;
}
/* Scan the dynamic table */
for (i = 0; i < tbl->num_ents; i++) {
- gpr_uint16 idx =
- (gpr_uint16)(tbl->num_ents - i + GRPC_CHTTP2_LAST_STATIC_ENTRY);
+ gpr_uint32 idx =
+ (gpr_uint32)(tbl->num_ents - i + GRPC_CHTTP2_LAST_STATIC_ENTRY);
grpc_mdelem *ent =
- tbl->ents[(tbl->first_ent + i) % GRPC_CHTTP2_MAX_TABLE_COUNT];
+ tbl->ents[(tbl->first_ent + i) % tbl->cap_entries];
if (md->key != ent->key) continue;
r.index = idx;
r.has_value = md->value == ent->value;