Skip to content

Commit

Permalink
Use static metadata table in metadata.c
Browse files Browse the repository at this point in the history
  • Loading branch information
ctiller committed Nov 19, 2015
1 parent 328d4b1 commit 0e72ede
Show file tree
Hide file tree
Showing 11 changed files with 154 additions and 11 deletions.
3 changes: 3 additions & 0 deletions include/grpc/support/slice.h
Original file line number Diff line number Diff line change
Expand Up @@ -144,6 +144,9 @@ gpr_slice gpr_slice_from_copied_string(const char *source);
memcpy(slice->data, source, len); */
gpr_slice gpr_slice_from_copied_buffer(const char *source, size_t len);

/* Create a slice pointing to constant memory */
gpr_slice gpr_slice_from_static_string(const char *source);

/* Return a result slice derived from s, which shares a ref count with s, where
result.data==s.data+begin, and result.length==end-begin.
The ref count of s is increased by one.
Expand Down
14 changes: 14 additions & 0 deletions src/core/support/slice.c
Original file line number Diff line number Diff line change
Expand Up @@ -57,6 +57,20 @@ void gpr_slice_unref(gpr_slice slice) {
}
}

/* gpr_slice_from_static_string support structure - a refcount that does
nothing */
static void noop_ref_or_unref(void *unused) {}

static gpr_slice_refcount noop_refcount = {noop_ref_or_unref, noop_ref_or_unref};

gpr_slice gpr_slice_from_static_string(const char *s) {
gpr_slice slice;
slice.refcount = &noop_refcount;
slice.data.refcounted.bytes = (gpr_uint8*)s;
slice.data.refcounted.length = strlen(s);
return slice;
}

/* gpr_slice_new support structures - we create a refcount object extended
with the user provided data pointer & destroy function */
typedef struct new_slice_refcount {
Expand Down
2 changes: 2 additions & 0 deletions src/core/surface/init.c
Original file line number Diff line number Diff line change
Expand Up @@ -93,6 +93,7 @@ void grpc_init(void) {
gpr_mu_lock(&g_init_mu);
if (++g_initializations == 1) {
gpr_time_init();
grpc_mdctx_global_init();
grpc_lb_policy_registry_init(grpc_pick_first_lb_factory_create());
grpc_register_lb_policy(grpc_pick_first_lb_factory_create());
grpc_register_lb_policy(grpc_round_robin_lb_factory_create());
Expand Down Expand Up @@ -147,6 +148,7 @@ void grpc_shutdown(void) {
g_all_of_the_plugins[i].destroy();
}
}
grpc_mdctx_global_shutdown();
}
gpr_mu_unlock(&g_init_mu);
}
Expand Down
125 changes: 116 additions & 9 deletions src/core/transport/metadata.c
Original file line number Diff line number Diff line change
Expand Up @@ -31,7 +31,6 @@
*
*/

#include "src/core/iomgr/sockaddr.h"
#include "src/core/transport/metadata.h"

#include <assert.h>
Expand All @@ -45,21 +44,22 @@
#include "src/core/profiling/timers.h"
#include "src/core/support/murmur_hash.h"
#include "src/core/transport/chttp2/bin_encoder.h"
#include "src/core/transport/static_metadata.h"

#define INITIAL_STRTAB_CAPACITY 4
#define INITIAL_MDTAB_CAPACITY 4

#ifdef GRPC_METADATA_REFCOUNT_DEBUG
#define DEBUG_ARGS , const char *file, int line
#define FWD_DEBUG_ARGS , file, line
#define INTERNAL_STRING_REF(s) internal_string_ref((s), __FILE__, __LINE__)
#define INTERNAL_STRING_UNREF(s) internal_string_unref((s), __FILE__, __LINE__)
#define INTERNAL_STRING_REF(s) if (is_mdstr_static((grpc_mdstr*)(s))); else internal_string_ref((s), __FILE__, __LINE__)
#define INTERNAL_STRING_UNREF(s) if (is_mdstr_static((grpc_mdstr*)(s))); else internal_string_unref((s), __FILE__, __LINE__)
#define REF_MD_LOCKED(s) ref_md_locked((s), __FILE__, __LINE__)
#else
#define DEBUG_ARGS
#define FWD_DEBUG_ARGS
#define INTERNAL_STRING_REF(s) internal_string_ref((s))
#define INTERNAL_STRING_UNREF(s) internal_string_unref((s))
#define INTERNAL_STRING_REF(s) if (is_mdstr_static((grpc_mdstr*)(s))); else internal_string_ref((s))
#define INTERNAL_STRING_UNREF(s) if (is_mdstr_static((grpc_mdstr*)(s))); else internal_string_unref((s))
#define REF_MD_LOCKED(s) ref_md_locked((s))
#endif

Expand Down Expand Up @@ -98,12 +98,27 @@ typedef struct internal_metadata {
struct internal_metadata *bucket_next;
} internal_metadata;

typedef struct static_string {
grpc_mdstr *mdstr;
gpr_uint32 hash;
} static_string;

typedef struct static_mdelem {
grpc_mdelem *mdelem;
gpr_uint32 hash;
} static_mdelem;

struct grpc_mdctx {
gpr_uint32 hash_seed;
int refs;

gpr_mu mu;

static_string static_strtab[GRPC_STATIC_MDSTR_COUNT * 2];
static_mdelem static_mdtab[GRPC_STATIC_MDELEM_COUNT * 2];
size_t static_strtab_maxprobe;
size_t static_mdtab_maxprobe;

internal_string **strtab;
size_t strtab_count;
size_t strtab_capacity;
Expand All @@ -120,6 +135,34 @@ static void discard_metadata(grpc_mdctx *ctx);
static void gc_mdtab(grpc_mdctx *ctx);
static void metadata_context_destroy_locked(grpc_mdctx *ctx);

void grpc_mdctx_global_init(void) {
size_t i;
for (i = 0; i < GRPC_STATIC_MDSTR_COUNT; i++) {
grpc_mdstr *elem = &grpc_static_mdstr_table[i];
const char *str = grpc_static_metadata_strings[i];
*(gpr_slice*)&elem->slice = gpr_slice_from_static_string(str);
*(gpr_uint32*)&elem->hash = gpr_murmur_hash3(str, strlen(str), 0);
}
for (i = 0; i < GRPC_STATIC_MDELEM_COUNT; i++) {
grpc_mdelem *elem = &grpc_static_mdelem_table[i];
grpc_mdstr *key = &grpc_static_mdstr_table[2 * i + 0];
grpc_mdstr *value = &grpc_static_mdstr_table[2 * i + 1];
*(grpc_mdstr**)&elem->key = key;
*(grpc_mdstr**)&elem->value = value;
}
}

void grpc_mdctx_global_shutdown(void) {
}

static int is_mdstr_static(grpc_mdstr *s) {
return s >= &grpc_static_mdstr_table[0] && s < &grpc_static_mdstr_table[GRPC_STATIC_MDSTR_COUNT];
}

static int is_mdelem_static(grpc_mdelem *e) {
return e >= &grpc_static_mdelem_table[0] && e < &grpc_static_mdelem_table[GRPC_STATIC_MDELEM_COUNT];
}

static void lock(grpc_mdctx *ctx) { gpr_mu_lock(&ctx->mu); }

static void unlock(grpc_mdctx *ctx) {
Expand Down Expand Up @@ -170,6 +213,9 @@ static void ref_md_locked(internal_metadata *md DEBUG_ARGS) {

grpc_mdctx *grpc_mdctx_create_with_seed(gpr_uint32 seed) {
grpc_mdctx *ctx = gpr_malloc(sizeof(grpc_mdctx));
size_t i, j;

memset(ctx, 0, sizeof(*ctx));

ctx->refs = 1;
ctx->hash_seed = seed;
Expand All @@ -184,6 +230,38 @@ grpc_mdctx *grpc_mdctx_create_with_seed(gpr_uint32 seed) {
ctx->mdtab_capacity = INITIAL_MDTAB_CAPACITY;
ctx->mdtab_free = 0;

for (i = 0; i < GRPC_STATIC_MDSTR_COUNT; i++) {
const char *str = grpc_static_metadata_strings[i];
gpr_uint32 lup_hash = gpr_murmur_hash3(str, strlen(str), seed);
for (j = 0;; j++) {
size_t idx = (lup_hash + j) % GPR_ARRAY_SIZE(ctx->static_strtab);
if (ctx->static_strtab[idx].mdstr == NULL) {
ctx->static_strtab[idx].mdstr = &grpc_static_mdstr_table[i];
ctx->static_strtab[idx].hash = lup_hash;
break;
}
}
if (j > ctx->static_strtab_maxprobe) {
ctx->static_strtab_maxprobe = j;
}
}

for (i = 0; i < GRPC_STATIC_MDELEM_COUNT; i++) {
grpc_mdelem *elem = &grpc_static_mdelem_table[i];
gpr_uint32 hash = GRPC_MDSTR_KV_HASH(elem->key->hash, elem->value->hash);
for (j = 0;; j++) {
size_t idx = (hash + j) % GPR_ARRAY_SIZE(ctx->static_mdtab);
if (ctx->static_mdtab[idx].mdelem == NULL) {
ctx->static_mdtab[idx].mdelem = elem;
ctx->static_mdtab[idx].hash = hash;
break;
}
}
if (j > ctx->static_mdtab_maxprobe) {
ctx->static_mdtab_maxprobe = j;
}
}

return ctx;
}

Expand Down Expand Up @@ -350,8 +428,20 @@ grpc_mdstr *grpc_mdstr_from_buffer(grpc_mdctx *ctx, const gpr_uint8 *buf,
size_t length) {
gpr_uint32 hash = gpr_murmur_hash3(buf, length, ctx->hash_seed);
internal_string *s;
size_t i;

GPR_TIMER_BEGIN("grpc_mdstr_from_buffer", 0);

/* search for a static string */
for (i = 0; i <= ctx->static_strtab_maxprobe; i++) {
size_t idx = (hash + i) % GPR_ARRAY_SIZE(ctx->static_strtab);
static_string *ss = &ctx->static_strtab[idx];
if (ss->hash == hash && GPR_SLICE_LENGTH(ss->mdstr->slice) == length &&
0 == memcmp(buf, GPR_SLICE_START_PTR(ss->mdstr->slice), length)) {
return ss->mdstr;
}
}

lock(ctx);

/* search for an existing string */
Expand Down Expand Up @@ -479,12 +569,23 @@ grpc_mdelem *grpc_mdelem_from_metadata_strings(grpc_mdctx *ctx,
internal_string *value = (internal_string *)mvalue;
gpr_uint32 hash = GRPC_MDSTR_KV_HASH(mkey->hash, mvalue->hash);
internal_metadata *md;
size_t i;

GPR_ASSERT(key->context == ctx);
GPR_ASSERT(value->context == ctx);
GPR_ASSERT(is_mdstr_static(mkey) || key->context == ctx);
GPR_ASSERT(is_mdstr_static(mvalue) || value->context == ctx);

GPR_TIMER_BEGIN("grpc_mdelem_from_metadata_strings", 0);

if (is_mdstr_static(mkey) && is_mdstr_static(mvalue)) {
for (i = 0; i <= ctx->static_mdtab_maxprobe; i++) {
size_t idx = (hash + i) % GPR_ARRAY_SIZE(ctx->static_mdtab);
static_mdelem *smd = &ctx->static_mdtab[idx];
if (smd->hash == hash && smd->mdelem->key == mkey && smd->mdelem->value == mvalue) {
return smd->mdelem;
}
}
}

lock(ctx);

/* search for an existing pair */
Expand Down Expand Up @@ -553,6 +654,7 @@ grpc_mdelem *grpc_mdelem_from_string_and_buffer(grpc_mdctx *ctx,

grpc_mdelem *grpc_mdelem_ref(grpc_mdelem *gmd DEBUG_ARGS) {
internal_metadata *md = (internal_metadata *)gmd;
if (is_mdelem_static(gmd)) return gmd;
#ifdef GRPC_METADATA_REFCOUNT_DEBUG
gpr_log(file, line, GPR_LOG_SEVERITY_DEBUG,
"ELM REF:%p:%d->%d: '%s' = '%s'", md,
Expand All @@ -573,6 +675,7 @@ grpc_mdelem *grpc_mdelem_ref(grpc_mdelem *gmd DEBUG_ARGS) {
void grpc_mdelem_unref(grpc_mdelem *gmd DEBUG_ARGS) {
internal_metadata *md = (internal_metadata *)gmd;
if (!md) return;
if (is_mdelem_static(gmd)) return;
#ifdef GRPC_METADATA_REFCOUNT_DEBUG
gpr_log(file, line, GPR_LOG_SEVERITY_DEBUG,
"ELM UNREF:%p:%d->%d: '%s' = '%s'", md,
Expand Down Expand Up @@ -600,7 +703,9 @@ const char *grpc_mdstr_as_c_string(grpc_mdstr *s) {

grpc_mdstr *grpc_mdstr_ref(grpc_mdstr *gs DEBUG_ARGS) {
internal_string *s = (internal_string *)gs;
grpc_mdctx *ctx = s->context;
grpc_mdctx *ctx;
if (is_mdstr_static(gs)) return gs;
ctx = s->context;
lock(ctx);
internal_string_ref(s FWD_DEBUG_ARGS);
unlock(ctx);
Expand All @@ -609,7 +714,9 @@ grpc_mdstr *grpc_mdstr_ref(grpc_mdstr *gs DEBUG_ARGS) {

void grpc_mdstr_unref(grpc_mdstr *gs DEBUG_ARGS) {
internal_string *s = (internal_string *)gs;
grpc_mdctx *ctx = s->context;
grpc_mdctx *ctx;
if (is_mdstr_static(gs)) return;
ctx = s->context;
lock(ctx);
internal_string_unref(s FWD_DEBUG_ARGS);
unlock(ctx);
Expand Down
3 changes: 3 additions & 0 deletions src/core/transport/metadata.h
Original file line number Diff line number Diff line change
Expand Up @@ -157,4 +157,7 @@ int grpc_mdstr_is_bin_suffixed(grpc_mdstr *s);

#define GRPC_MDSTR_KV_HASH(k_hash, v_hash) (GPR_ROTL((k_hash), 2) ^ (v_hash))

void grpc_mdctx_global_init(void);
void grpc_mdctx_global_shutdown(void);

#endif /* GRPC_INTERNAL_CORE_TRANSPORT_METADATA_H */
4 changes: 3 additions & 1 deletion test/core/bad_client/bad_client.c
Original file line number Diff line number Diff line change
Expand Up @@ -84,7 +84,7 @@ void grpc_run_bad_client_test(grpc_bad_client_server_side_validator validator,
gpr_thd_id id;
char *hex;
grpc_transport *transport;
grpc_mdctx *mdctx = grpc_mdctx_create();
grpc_mdctx *mdctx;
gpr_slice slice =
gpr_slice_from_copied_buffer(client_payload, client_payload_length);
gpr_slice_buffer outgoing;
Expand All @@ -102,6 +102,8 @@ void grpc_run_bad_client_test(grpc_bad_client_server_side_validator validator,
/* Init grpc */
grpc_init();

mdctx = grpc_mdctx_create();

/* Create endpoints */
sfd = grpc_iomgr_create_endpoint_pair("fixture", 65536);

Expand Down
2 changes: 2 additions & 0 deletions test/core/channel/channel_stack_test.c
Original file line number Diff line number Diff line change
Expand Up @@ -140,6 +140,8 @@ static void test_create_channel_stack(void) {

int main(int argc, char **argv) {
grpc_test_init(argc, argv);
grpc_init();
test_create_channel_stack();
grpc_shutdown();
return 0;
}
2 changes: 2 additions & 0 deletions test/core/transport/chttp2/hpack_encoder_test.c
Original file line number Diff line number Diff line change
Expand Up @@ -191,8 +191,10 @@ static void run_test(void (*test)(), const char *name) {
int main(int argc, char **argv) {
size_t i;
grpc_test_init(argc, argv);
grpc_init();
TEST(test_basic_headers);
TEST(test_decode_table_overflow);
grpc_shutdown();
for (i = 0; i < num_to_delete; i++) {
gpr_free(to_delete[i]);
}
Expand Down
2 changes: 2 additions & 0 deletions test/core/transport/chttp2/hpack_parser_test.c
Original file line number Diff line number Diff line change
Expand Up @@ -217,7 +217,9 @@ static void test_vectors(grpc_slice_split_mode mode) {

int main(int argc, char **argv) {
grpc_test_init(argc, argv);
grpc_init();
test_vectors(GRPC_SLICE_SPLIT_MERGE_ALL);
test_vectors(GRPC_SLICE_SPLIT_ONE_BYTE);
grpc_shutdown();
return 0;
}
6 changes: 5 additions & 1 deletion test/core/transport/chttp2/hpack_table_test.c
Original file line number Diff line number Diff line change
Expand Up @@ -36,10 +36,12 @@
#include <string.h>
#include <stdio.h>

#include "src/core/support/string.h"
#include <grpc/support/alloc.h>
#include <grpc/support/log.h>
#include <grpc/support/string_util.h>
#include <grpc/grpc.h>

#include "src/core/support/string.h"
#include "test/core/util/test_config.h"

#define LOG_TEST(x) gpr_log(GPR_INFO, "%s", x)
Expand Down Expand Up @@ -268,8 +270,10 @@ static void test_find(void) {

int main(int argc, char **argv) {
grpc_test_init(argc, argv);
grpc_init();
test_static_lookup();
test_many_additions();
test_find();
grpc_shutdown();
return 0;
}
2 changes: 2 additions & 0 deletions test/core/transport/metadata_test.c
Original file line number Diff line number Diff line change
Expand Up @@ -270,6 +270,7 @@ static void test_base64_and_huffman_works(void) {

int main(int argc, char **argv) {
grpc_test_init(argc, argv);
grpc_init();
test_no_op();
test_create_string();
test_create_metadata();
Expand All @@ -279,5 +280,6 @@ int main(int argc, char **argv) {
test_things_stick_around();
test_slices_work();
test_base64_and_huffman_works();
grpc_shutdown();
return 0;
}

0 comments on commit 0e72ede

Please sign in to comment.