diff options
author | 2015-11-10 08:37:46 +0000 | |
---|---|---|
committer | 2015-11-10 08:37:46 +0000 | |
commit | 027a74cd3b3ce350ba5890d0fd8f6399a200227f (patch) | |
tree | e192513c5db0291fb4487cce7e9d2fb34d8674e5 /src/core/transport/chttp2/hpack_table.c | |
parent | 83e73373cb63be5ec5a97d894e7a06faf81d3df8 (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.c | 95 |
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; |