diff --git a/include/grpc/impl/codegen/grpc_types.h b/include/grpc/impl/codegen/grpc_types.h index 5170621bbb9..ac9a007641d 100644 --- a/include/grpc/impl/codegen/grpc_types.h +++ b/include/grpc/impl/codegen/grpc_types.h @@ -292,8 +292,11 @@ typedef enum grpc_call_error { /** A single metadata element */ typedef struct grpc_metadata { + /* the key, value values are expected to line up with grpc_mdelem: if changing + them, update metadata.h at the same time. */ grpc_slice key; grpc_slice value; + uint32_t flags; /** The following fields are reserved for grpc internal use. diff --git a/src/core/ext/lb_policy/grpclb/grpclb.c b/src/core/ext/lb_policy/grpclb/grpclb.c index b10b9803312..795d68d5e78 100644 --- a/src/core/ext/lb_policy/grpclb/grpclb.c +++ b/src/core/ext/lb_policy/grpclb/grpclb.c @@ -381,10 +381,14 @@ static bool is_server_valid(const grpc_grpclb_server *server, size_t idx, /* vtable for LB tokens in grpc_lb_addresses. */ static void *lb_token_copy(void *token) { - return token == NULL ? NULL : GRPC_MDELEM_REF((grpc_mdelem){token}).payload; + return token == NULL + ? NULL + : (void *)GRPC_MDELEM_REF((grpc_mdelem){(uintptr_t)token}).payload; } static void lb_token_destroy(grpc_exec_ctx *exec_ctx, void *token) { - if (token != NULL) GRPC_MDELEM_UNREF(exec_ctx, (grpc_mdelem){token}); + if (token != NULL) { + GRPC_MDELEM_UNREF(exec_ctx, (grpc_mdelem){(uintptr_t)token}); + } } static int lb_token_cmp(void *token1, void *token2) { if (token1 > token2) return 1; @@ -454,9 +458,9 @@ static grpc_lb_addresses *process_serverlist_locked( strnlen(server->load_balance_token, lb_token_max_length); grpc_slice lb_token_mdstr = grpc_slice_from_copied_buffer( server->load_balance_token, lb_token_length); - user_data = - grpc_mdelem_from_slices(exec_ctx, GRPC_MDSTR_LB_TOKEN, lb_token_mdstr) - .payload; + user_data = (void *)grpc_mdelem_from_slices(exec_ctx, GRPC_MDSTR_LB_TOKEN, + lb_token_mdstr) + .payload; } else { char *uri = grpc_sockaddr_to_uri(&addr); gpr_log(GPR_INFO, @@ -464,7 +468,7 @@ static grpc_lb_addresses *process_serverlist_locked( "be used instead", uri); gpr_free(uri); - user_data = GRPC_MDELEM_LB_TOKEN_EMPTY.payload; + user_data = (void *)GRPC_MDELEM_LB_TOKEN_EMPTY.payload; } grpc_lb_addresses_set_address(lb_addresses, addr_idx, &addr.addr, addr.len, diff --git a/src/core/lib/slice/slice_intern.c b/src/core/lib/slice/slice_intern.c index 6f65a3dcc84..2d932849264 100644 --- a/src/core/lib/slice/slice_intern.c +++ b/src/core/lib/slice/slice_intern.c @@ -193,6 +193,11 @@ void grpc_slice_static_intern(grpc_slice *slice) { } } +bool grpc_slice_is_interned(grpc_slice slice) { + return (slice.refcount && slice.refcount->vtable == &interned_slice_vtable) || + grpc_is_static_metadata_string(slice); +} + grpc_slice grpc_slice_intern(grpc_slice slice) { if (grpc_is_static_metadata_string(slice)) { return slice; diff --git a/src/core/lib/slice/slice_internal.h b/src/core/lib/slice/slice_internal.h index 695bd308ad8..211d5f06be6 100644 --- a/src/core/lib/slice/slice_internal.h +++ b/src/core/lib/slice/slice_internal.h @@ -46,6 +46,9 @@ void grpc_slice_buffer_reset_and_unref_internal(grpc_exec_ctx *exec_ctx, void grpc_slice_buffer_destroy_internal(grpc_exec_ctx *exec_ctx, grpc_slice_buffer *sb); +/* Check if a slice is interned */ +bool grpc_slice_is_interned(grpc_slice slice); + void grpc_slice_intern_init(void); void grpc_slice_intern_shutdown(void); void grpc_test_only_set_slice_hash_seed(uint32_t key); diff --git a/src/core/lib/transport/metadata.c b/src/core/lib/transport/metadata.c index c114cf9a30a..f3f6b1311fc 100644 --- a/src/core/lib/transport/metadata.c +++ b/src/core/lib/transport/metadata.c @@ -80,9 +80,9 @@ typedef void (*destroy_user_data_func)(void *user_data); -/* Shadow structure for grpc_mdelem_data for non-static elements */ -typedef struct internal_metadata { - /* must be byte compatible with grpc_mdelem */ +/* Shadow structure for grpc_mdelem_data for interned elements */ +typedef struct interned_metadata { + /* must be byte compatible with grpc_mdelem_data */ grpc_slice key; grpc_slice value; @@ -93,12 +93,22 @@ typedef struct internal_metadata { gpr_atm destroy_user_data; gpr_atm user_data; - struct internal_metadata *bucket_next; -} internal_metadata; + struct interned_metadata *bucket_next; +} interned_metadata; + +/* Shadow structure for grpc_mdelem_data for allocated elements */ +typedef struct allocated_metadata { + /* must be byte compatible with grpc_mdelem_data */ + grpc_slice key; + grpc_slice value; + + /* private only data */ + gpr_atm refcnt; +} allocated_metadata; typedef struct mdtab_shard { gpr_mu mu; - internal_metadata **elems; + interned_metadata **elems; size_t count; size_t capacity; /** Estimate of the number of unreferenced mdelems in the hash table. @@ -142,12 +152,13 @@ void grpc_mdctx_global_shutdown(grpc_exec_ctx *exec_ctx) { } static int is_mdelem_static(grpc_mdelem e) { - return e.payload >= &grpc_static_mdelem_table[0] && - e.payload < &grpc_static_mdelem_table[GRPC_STATIC_MDELEM_COUNT]; + return GRPC_MDELEM_DATA(e) >= &grpc_static_mdelem_table[0] && + GRPC_MDELEM_DATA(e) < + &grpc_static_mdelem_table[GRPC_STATIC_MDELEM_COUNT]; } static void ref_md_locked(mdtab_shard *shard, - internal_metadata *md DEBUG_ARGS) { + interned_metadata *md DEBUG_ARGS) { #ifdef GRPC_METADATA_REFCOUNT_DEBUG gpr_log(file, line, GPR_LOG_SEVERITY_DEBUG, "ELM REF:%p:%zu->%zu: '%s' = '%s'", (void *)md, @@ -163,8 +174,8 @@ static void ref_md_locked(mdtab_shard *shard, static void gc_mdtab(grpc_exec_ctx *exec_ctx, mdtab_shard *shard) { size_t i; - internal_metadata **prev_next; - internal_metadata *md, *next; + interned_metadata **prev_next; + interned_metadata *md, *next; gpr_atm num_freed = 0; GPR_TIMER_BEGIN("gc_mdtab", 0); @@ -196,14 +207,14 @@ static void gc_mdtab(grpc_exec_ctx *exec_ctx, mdtab_shard *shard) { static void grow_mdtab(mdtab_shard *shard) { size_t capacity = shard->capacity * 2; size_t i; - internal_metadata **mdtab; - internal_metadata *md, *next; + interned_metadata **mdtab; + interned_metadata *md, *next; uint32_t hash; GPR_TIMER_BEGIN("grow_mdtab", 0); - mdtab = gpr_malloc(sizeof(internal_metadata *) * capacity); - memset(mdtab, 0, sizeof(internal_metadata *) * capacity); + mdtab = gpr_malloc(sizeof(interned_metadata *) * capacity); + memset(mdtab, 0, sizeof(interned_metadata *) * capacity); for (i = 0; i < shard->capacity; i++) { for (md = shard->elems[i]; md; md = next) { @@ -233,10 +244,21 @@ static void rehash_mdtab(grpc_exec_ctx *exec_ctx, mdtab_shard *shard) { } } -grpc_mdelem grpc_mdelem_from_slices(grpc_exec_ctx *exec_ctx, grpc_slice key, - grpc_slice value) { - grpc_slice_static_intern(&key); - grpc_slice_static_intern(&value); +grpc_mdelem grpc_mdelem_create( + grpc_exec_ctx *exec_ctx, grpc_slice key, grpc_slice value, + grpc_mdelem_data *compatible_external_backing_store) { + if (!grpc_slice_is_interned(key) || !grpc_slice_is_interned(value)) { + if (compatible_external_backing_store != NULL) { + return GRPC_MAKE_MDELEM(compatible_external_backing_store, + GRPC_MDELEM_STORAGE_EXTERNAL); + } + + allocated_metadata *allocated = gpr_malloc(sizeof(*allocated)); + allocated->key = grpc_slice_ref_internal(key); + allocated->value = grpc_slice_ref_internal(value); + gpr_atm_rel_store(&allocated->refcnt, 1); + return GRPC_MAKE_MDELEM(allocated, GRPC_MDELEM_STORAGE_ALLOCATED); + } grpc_mdelem static_elem = grpc_static_mdelem_for_static_strings( grpc_static_metadata_index(key), grpc_static_metadata_index(value)); @@ -246,7 +268,7 @@ grpc_mdelem grpc_mdelem_from_slices(grpc_exec_ctx *exec_ctx, grpc_slice key, uint32_t hash = GRPC_MDSTR_KV_HASH(grpc_slice_hash(key), grpc_slice_hash(value)); - internal_metadata *md; + interned_metadata *md; mdtab_shard *shard = &g_shards[SHARD_IDX(hash)]; size_t idx; @@ -261,18 +283,16 @@ grpc_mdelem grpc_mdelem_from_slices(grpc_exec_ctx *exec_ctx, grpc_slice key, grpc_slice_cmp(value, md->value) == 0) { REF_MD_LOCKED(shard, md); gpr_mu_unlock(&shard->mu); - grpc_slice_unref_internal(exec_ctx, key); - grpc_slice_unref_internal(exec_ctx, value); GPR_TIMER_END("grpc_mdelem_from_metadata_strings", 0); - return (grpc_mdelem){(grpc_mdelem_data *)md}; + return GRPC_MAKE_MDELEM(md, GRPC_MDELEM_STORAGE_INTERNED); } } /* not found: create a new pair */ - md = gpr_malloc(sizeof(internal_metadata)); + md = gpr_malloc(sizeof(interned_metadata)); gpr_atm_rel_store(&md->refcnt, 1); - md->key = key; - md->value = value; + md->key = grpc_slice_ref_internal(key); + md->value = grpc_slice_ref_internal(value); md->user_data = 0; md->destroy_user_data = 0; md->bucket_next = shard->elems[idx]; @@ -294,7 +314,21 @@ grpc_mdelem grpc_mdelem_from_slices(grpc_exec_ctx *exec_ctx, grpc_slice key, GPR_TIMER_END("grpc_mdelem_from_metadata_strings", 0); - return (grpc_mdelem){(grpc_mdelem_data *)md}; + return GRPC_MAKE_MDELEM(md, GRPC_MDELEM_STORAGE_INTERNED); +} + +grpc_mdelem grpc_mdelem_from_slices(grpc_exec_ctx *exec_ctx, grpc_slice key, + grpc_slice value) { + grpc_mdelem out = grpc_mdelem_create(exec_ctx, key, value, NULL); + grpc_slice_unref_internal(exec_ctx, key); + grpc_slice_unref_internal(exec_ctx, value); + return out; +} + +grpc_mdelem grpc_mdelem_from_grpc_metadata(grpc_exec_ctx *exec_ctx, + grpc_metadata *metadata) { + return grpc_mdelem_create(exec_ctx, metadata->key, metadata->value, + (grpc_mdelem_data *)metadata); } static size_t get_base64_encoded_size(size_t raw_length) { @@ -313,81 +347,151 @@ size_t grpc_mdelem_get_size_in_hpack_table(grpc_mdelem elem) { } grpc_mdelem grpc_mdelem_ref(grpc_mdelem gmd DEBUG_ARGS) { - if (gmd.payload == NULL || is_mdelem_static(gmd)) return gmd; - internal_metadata *md = (internal_metadata *)gmd.payload; + switch (GRPC_MDELEM_STORAGE(gmd)) { + case GRPC_MDELEM_STORAGE_EXTERNAL: + case GRPC_MDELEM_STORAGE_STATIC: + break; + case GRPC_MDELEM_STORAGE_INTERNED: { + interned_metadata *md = (interned_metadata *)GRPC_MDELEM_DATA(gmd); #ifdef GRPC_METADATA_REFCOUNT_DEBUG - gpr_log(file, line, GPR_LOG_SEVERITY_DEBUG, - "ELM REF:%p:%zu->%zu: '%s' = '%s'", (void *)md, - gpr_atm_no_barrier_load(&md->refcnt), - gpr_atm_no_barrier_load(&md->refcnt) + 1, - grpc_mdstr_as_c_string((grpc_slice)md->key), - grpc_mdstr_as_c_string((grpc_slice)md->value)); + gpr_log(file, line, GPR_LOG_SEVERITY_DEBUG, + "ELM REF:%p:%zu->%zu: '%s' = '%s'", (void *)md, + gpr_atm_no_barrier_load(&md->refcnt), + gpr_atm_no_barrier_load(&md->refcnt) + 1, + grpc_mdstr_as_c_string((grpc_slice)md->key), + grpc_mdstr_as_c_string((grpc_slice)md->value)); +#endif + /* we can assume the ref count is >= 1 as the application is calling + this function - meaning that no adjustment to mdtab_free is necessary, + simplifying the logic here to be just an atomic increment */ + /* use C assert to have this removed in opt builds */ + GPR_ASSERT(gpr_atm_no_barrier_load(&md->refcnt) >= 1); + gpr_atm_no_barrier_fetch_add(&md->refcnt, 1); + break; + } + case GRPC_MDELEM_STORAGE_ALLOCATED: { + allocated_metadata *md = (allocated_metadata *)GRPC_MDELEM_DATA(gmd); +#ifdef GRPC_METADATA_REFCOUNT_DEBUG + gpr_log(file, line, GPR_LOG_SEVERITY_DEBUG, + "ELM REF:%p:%zu->%zu: '%s' = '%s'", (void *)md, + gpr_atm_no_barrier_load(&md->refcnt), + gpr_atm_no_barrier_load(&md->refcnt) + 1, + grpc_mdstr_as_c_string((grpc_slice)md->key), + grpc_mdstr_as_c_string((grpc_slice)md->value)); #endif - /* we can assume the ref count is >= 1 as the application is calling - this function - meaning that no adjustment to mdtab_free is necessary, - simplifying the logic here to be just an atomic increment */ - /* use C assert to have this removed in opt builds */ - GPR_ASSERT(gpr_atm_no_barrier_load(&md->refcnt) >= 1); - gpr_atm_no_barrier_fetch_add(&md->refcnt, 1); + /* we can assume the ref count is >= 1 as the application is calling + this function - meaning that no adjustment to mdtab_free is necessary, + simplifying the logic here to be just an atomic increment */ + /* use C assert to have this removed in opt builds */ + gpr_atm_no_barrier_fetch_add(&md->refcnt, 1); + break; + } + } return gmd; } void grpc_mdelem_unref(grpc_exec_ctx *exec_ctx, grpc_mdelem gmd DEBUG_ARGS) { - if (gmd.payload == NULL || is_mdelem_static(gmd)) return; - internal_metadata *md = (internal_metadata *)gmd.payload; + switch (GRPC_MDELEM_STORAGE(gmd)) { + case GRPC_MDELEM_STORAGE_EXTERNAL: + case GRPC_MDELEM_STORAGE_STATIC: + break; + case GRPC_MDELEM_STORAGE_INTERNED: { + interned_metadata *md = (interned_metadata *)GRPC_MDELEM_DATA(gmd); #ifdef GRPC_METADATA_REFCOUNT_DEBUG - gpr_log(file, line, GPR_LOG_SEVERITY_DEBUG, - "ELM UNREF:%p:%zu->%zu: '%s' = '%s'", (void *)md, - gpr_atm_no_barrier_load(&md->refcnt), - gpr_atm_no_barrier_load(&md->refcnt) - 1, - grpc_mdstr_as_c_string((grpc_slice)md->key), - grpc_mdstr_as_c_string((grpc_slice)md->value)); + gpr_log(file, line, GPR_LOG_SEVERITY_DEBUG, + "ELM UNREF:%p:%zu->%zu: '%s' = '%s'", (void *)md, + gpr_atm_no_barrier_load(&md->refcnt), + gpr_atm_no_barrier_load(&md->refcnt) - 1, + grpc_mdstr_as_c_string((grpc_slice)md->key), + grpc_mdstr_as_c_string((grpc_slice)md->value)); #endif - uint32_t hash = - GRPC_MDSTR_KV_HASH(grpc_slice_hash(md->key), grpc_slice_hash(md->value)); - const gpr_atm prev_refcount = gpr_atm_full_fetch_add(&md->refcnt, -1); - GPR_ASSERT(prev_refcount >= 1); - if (1 == prev_refcount) { - /* once the refcount hits zero, some other thread can come along and - free md at any time: it's unsafe from this point on to access it */ - mdtab_shard *shard = &g_shards[SHARD_IDX(hash)]; - gpr_atm_no_barrier_fetch_add(&shard->free_estimate, 1); + uint32_t hash = GRPC_MDSTR_KV_HASH(grpc_slice_hash(md->key), + grpc_slice_hash(md->value)); + const gpr_atm prev_refcount = gpr_atm_full_fetch_add(&md->refcnt, -1); + GPR_ASSERT(prev_refcount >= 1); + if (1 == prev_refcount) { + /* once the refcount hits zero, some other thread can come along and + free md at any time: it's unsafe from this point on to access it */ + mdtab_shard *shard = &g_shards[SHARD_IDX(hash)]; + gpr_atm_no_barrier_fetch_add(&shard->free_estimate, 1); + } + break; + } + case GRPC_MDELEM_STORAGE_ALLOCATED: { + allocated_metadata *md = (allocated_metadata *)GRPC_MDELEM_DATA(gmd); +#ifdef GRPC_METADATA_REFCOUNT_DEBUG + gpr_log(file, line, GPR_LOG_SEVERITY_DEBUG, + "ELM UNREF:%p:%zu->%zu: '%s' = '%s'", (void *)md, + gpr_atm_no_barrier_load(&md->refcnt), + gpr_atm_no_barrier_load(&md->refcnt) - 1, + grpc_mdstr_as_c_string((grpc_slice)md->key), + grpc_mdstr_as_c_string((grpc_slice)md->value)); +#endif + const gpr_atm prev_refcount = gpr_atm_full_fetch_add(&md->refcnt, -1); + GPR_ASSERT(prev_refcount >= 1); + if (1 == prev_refcount) { + grpc_slice_unref_internal(exec_ctx, md->key); + grpc_slice_unref_internal(exec_ctx, md->value); + gpr_free(md); + } + break; + } } } void *grpc_mdelem_get_user_data(grpc_mdelem md, void (*destroy_func)(void *)) { - internal_metadata *im = (internal_metadata *)md.payload; - void *result; - if (is_mdelem_static(md)) { - return (void *) - grpc_static_mdelem_user_data[md.payload - grpc_static_mdelem_table]; - } - if (gpr_atm_acq_load(&im->destroy_user_data) == (gpr_atm)destroy_func) { - return (void *)gpr_atm_no_barrier_load(&im->user_data); - } else { - return NULL; + switch (GRPC_MDELEM_STORAGE(md)) { + case GRPC_MDELEM_STORAGE_EXTERNAL: + case GRPC_MDELEM_STORAGE_ALLOCATED: + return NULL; + case GRPC_MDELEM_STORAGE_STATIC: + return (void *)grpc_static_mdelem_user_data[GRPC_MDELEM_DATA(md) - + grpc_static_mdelem_table]; + case GRPC_MDELEM_STORAGE_INTERNED: { + interned_metadata *im = (interned_metadata *)GRPC_MDELEM_DATA(md); + void *result; + if (gpr_atm_acq_load(&im->destroy_user_data) == (gpr_atm)destroy_func) { + return (void *)gpr_atm_no_barrier_load(&im->user_data); + } else { + return NULL; + } + return result; + } } - return result; + GPR_UNREACHABLE_CODE(return NULL); } void *grpc_mdelem_set_user_data(grpc_mdelem md, void (*destroy_func)(void *), void *user_data) { - internal_metadata *im = (internal_metadata *)md.payload; - GPR_ASSERT(!is_mdelem_static(md)); - GPR_ASSERT((user_data == NULL) == (destroy_func == NULL)); - gpr_mu_lock(&im->mu_user_data); - if (gpr_atm_no_barrier_load(&im->destroy_user_data)) { - /* user data can only be set once */ - gpr_mu_unlock(&im->mu_user_data); - if (destroy_func != NULL) { + switch (GRPC_MDELEM_STORAGE(md)) { + case GRPC_MDELEM_STORAGE_EXTERNAL: + case GRPC_MDELEM_STORAGE_ALLOCATED: destroy_func(user_data); + return NULL; + case GRPC_MDELEM_STORAGE_STATIC: + destroy_func(user_data); + return (void *)grpc_static_mdelem_user_data[GRPC_MDELEM_DATA(md) - + grpc_static_mdelem_table]; + case GRPC_MDELEM_STORAGE_INTERNED: { + interned_metadata *im = (interned_metadata *)GRPC_MDELEM_DATA(md); + GPR_ASSERT(!is_mdelem_static(md)); + GPR_ASSERT((user_data == NULL) == (destroy_func == NULL)); + gpr_mu_lock(&im->mu_user_data); + if (gpr_atm_no_barrier_load(&im->destroy_user_data)) { + /* user data can only be set once */ + gpr_mu_unlock(&im->mu_user_data); + if (destroy_func != NULL) { + destroy_func(user_data); + } + return (void *)gpr_atm_no_barrier_load(&im->user_data); + } + gpr_atm_no_barrier_store(&im->user_data, (gpr_atm)user_data); + gpr_atm_rel_store(&im->destroy_user_data, (gpr_atm)destroy_func); + gpr_mu_unlock(&im->mu_user_data); + return user_data; } - return (void *)gpr_atm_no_barrier_load(&im->user_data); } - gpr_atm_no_barrier_store(&im->user_data, (gpr_atm)user_data); - gpr_atm_rel_store(&im->destroy_user_data, (gpr_atm)destroy_func); - gpr_mu_unlock(&im->mu_user_data); - return user_data; + GPR_UNREACHABLE_CODE(return NULL); } bool grpc_mdelem_eq(grpc_mdelem a, grpc_mdelem b) { diff --git a/src/core/lib/transport/metadata.h b/src/core/lib/transport/metadata.h index da5416bf762..6d0afbe7891 100644 --- a/src/core/lib/transport/metadata.h +++ b/src/core/lib/transport/metadata.h @@ -34,6 +34,7 @@ #ifndef GRPC_CORE_LIB_TRANSPORT_METADATA_H #define GRPC_CORE_LIB_TRANSPORT_METADATA_H +#include <grpc/grpc.h> #include <grpc/slice.h> #include <grpc/support/useful.h> @@ -76,22 +77,58 @@ extern "C" { /* Forward declarations */ typedef struct grpc_mdelem grpc_mdelem; -/* if changing this, make identical changes in internal_metadata in - metadata.c */ +/* if changing this, make identical changes in: + - interned_metadata, allocated_metadata in metadata.c + - grpc_metadata in grpc_types.h */ typedef struct grpc_mdelem_data { const grpc_slice key; const grpc_slice value; /* there is a private part to this in metadata.c */ } grpc_mdelem_data; +typedef enum { + /* memory pointed to by grpc_mdelem::payload is owned by an external system */ + GRPC_MDELEM_STORAGE_EXTERNAL = 0, + /* memory pointed to by grpc_mdelem::payload is interned by the metadata + system */ + GRPC_MDELEM_STORAGE_INTERNED = 1, + /* memory pointed to by grpc_mdelem::payload is allocated by the metadata + system */ + GRPC_MDELEM_STORAGE_ALLOCATED = 2, + /* memory is in the static metadata table */ + GRPC_MDELEM_STORAGE_STATIC = 3, +} grpc_mdelem_data_storage; + struct grpc_mdelem { - grpc_mdelem_data *payload; + /* a grpc_mdelem_data* generally, with the two lower bits signalling memory + ownership as per grpc_mdelem_data_storage */ + uintptr_t payload; }; +#define GRPC_MDELEM_DATA(md) \ + ((grpc_mdelem_data *)((md).payload & ~(uintptr_t)3)) +#define GRPC_MDELEM_STORAGE(md) \ + ((grpc_mdelem_data_storage)((md).payload & (uintptr_t)3)) +#define GRPC_MAKE_MDELEM(data, storage) \ + ((grpc_mdelem){((uintptr_t)(data)) | ((uintptr_t)storage)}) + /* Unrefs the slices. */ grpc_mdelem grpc_mdelem_from_slices(grpc_exec_ctx *exec_ctx, grpc_slice key, grpc_slice value); +/* Cheaply convert a grpc_metadata to a grpc_mdelem; may use the grpc_metadata + object as backing storage (so lifetimes should align) */ +grpc_mdelem grpc_mdelem_from_grpc_metadata(grpc_exec_ctx *exec_ctx, + grpc_metadata *metadata); + +/* Does not unref the slices; if a new non-interned mdelem is needed, allocates + one if compatible_external_backing_store is NULL, or uses + compatible_external_backing_store if it is non-NULL (in which case it's the + users responsibility to ensure that it outlives usage) */ +grpc_mdelem grpc_mdelem_create( + grpc_exec_ctx *exec_ctx, grpc_slice key, grpc_slice value, + grpc_mdelem_data *compatible_external_backing_store); + bool grpc_mdelem_eq(grpc_mdelem a, grpc_mdelem b); size_t grpc_mdelem_get_size_in_hpack_table(grpc_mdelem elem); @@ -119,11 +156,11 @@ grpc_mdelem grpc_mdelem_ref(grpc_mdelem md); void grpc_mdelem_unref(grpc_exec_ctx *exec_ctx, grpc_mdelem md); #endif -#define GRPC_MDKEY(md) ((md).payload->key) -#define GRPC_MDVALUE(md) ((md).payload->value) +#define GRPC_MDKEY(md) (GRPC_MDELEM_DATA(md)->key) +#define GRPC_MDVALUE(md) (GRPC_MDELEM_DATA(md)->value) -#define GRPC_MDNULL ((grpc_mdelem){NULL}) -#define GRPC_MDISNULL(md) ((md).payload == NULL) +#define GRPC_MDNULL GRPC_MAKE_MDELEM(NULL, GRPC_MDELEM_STORAGE_EXTERNAL) +#define GRPC_MDISNULL(md) (GRPC_MDELEM_DATA(md) == NULL) /* We add 32 bytes of padding as per RFC-7540 section 6.5.2. */ #define GRPC_MDELEM_LENGTH(e) \ diff --git a/src/core/lib/transport/static_metadata.c b/src/core/lib/transport/static_metadata.c index 42daabfd89d..575f442a9b0 100644 --- a/src/core/lib/transport/static_metadata.c +++ b/src/core/lib/transport/static_metadata.c @@ -459,7 +459,8 @@ grpc_mdelem grpc_static_mdelem_for_static_strings(int a, int b) { uint32_t k = (uint32_t)(a * 98 + b); uint32_t h = elems_phash(k); return elem_keys[h] == k - ? (grpc_mdelem){&grpc_static_mdelem_table[elem_idxs[h]]} + ? GRPC_MAKE_MDELEM(&grpc_static_mdelem_table[elem_idxs[h]], + GRPC_MDELEM_STORAGE_STATIC) : GRPC_MDNULL; } diff --git a/src/core/lib/transport/static_metadata.h b/src/core/lib/transport/static_metadata.h index f5ef5d6dd72..3d3911de16b 100644 --- a/src/core/lib/transport/static_metadata.h +++ b/src/core/lib/transport/static_metadata.h @@ -255,216 +255,252 @@ extern grpc_mdelem_data grpc_static_mdelem_table[GRPC_STATIC_MDELEM_COUNT]; extern uintptr_t grpc_static_mdelem_user_data[GRPC_STATIC_MDELEM_COUNT]; /* "accept-charset": "" */ #define GRPC_MDELEM_ACCEPT_CHARSET_EMPTY \ - ((grpc_mdelem){&grpc_static_mdelem_table[0]}) + (GRPC_MAKE_MDELEM(&grpc_static_mdelem_table[0], GRPC_MDELEM_STORAGE_STATIC)) /* "accept": "" */ -#define GRPC_MDELEM_ACCEPT_EMPTY ((grpc_mdelem){&grpc_static_mdelem_table[1]}) +#define GRPC_MDELEM_ACCEPT_EMPTY \ + (GRPC_MAKE_MDELEM(&grpc_static_mdelem_table[1], GRPC_MDELEM_STORAGE_STATIC)) /* "accept-encoding": "" */ #define GRPC_MDELEM_ACCEPT_ENCODING_EMPTY \ - ((grpc_mdelem){&grpc_static_mdelem_table[2]}) + (GRPC_MAKE_MDELEM(&grpc_static_mdelem_table[2], GRPC_MDELEM_STORAGE_STATIC)) /* "accept-encoding": "gzip, deflate" */ #define GRPC_MDELEM_ACCEPT_ENCODING_GZIP_COMMA_DEFLATE \ - ((grpc_mdelem){&grpc_static_mdelem_table[3]}) + (GRPC_MAKE_MDELEM(&grpc_static_mdelem_table[3], GRPC_MDELEM_STORAGE_STATIC)) /* "accept-language": "" */ #define GRPC_MDELEM_ACCEPT_LANGUAGE_EMPTY \ - ((grpc_mdelem){&grpc_static_mdelem_table[4]}) + (GRPC_MAKE_MDELEM(&grpc_static_mdelem_table[4], GRPC_MDELEM_STORAGE_STATIC)) /* "accept-ranges": "" */ #define GRPC_MDELEM_ACCEPT_RANGES_EMPTY \ - ((grpc_mdelem){&grpc_static_mdelem_table[5]}) + (GRPC_MAKE_MDELEM(&grpc_static_mdelem_table[5], GRPC_MDELEM_STORAGE_STATIC)) /* "access-control-allow-origin": "" */ #define GRPC_MDELEM_ACCESS_CONTROL_ALLOW_ORIGIN_EMPTY \ - ((grpc_mdelem){&grpc_static_mdelem_table[6]}) + (GRPC_MAKE_MDELEM(&grpc_static_mdelem_table[6], GRPC_MDELEM_STORAGE_STATIC)) /* "age": "" */ -#define GRPC_MDELEM_AGE_EMPTY ((grpc_mdelem){&grpc_static_mdelem_table[7]}) +#define GRPC_MDELEM_AGE_EMPTY \ + (GRPC_MAKE_MDELEM(&grpc_static_mdelem_table[7], GRPC_MDELEM_STORAGE_STATIC)) /* "allow": "" */ -#define GRPC_MDELEM_ALLOW_EMPTY ((grpc_mdelem){&grpc_static_mdelem_table[8]}) +#define GRPC_MDELEM_ALLOW_EMPTY \ + (GRPC_MAKE_MDELEM(&grpc_static_mdelem_table[8], GRPC_MDELEM_STORAGE_STATIC)) /* ":authority": "" */ #define GRPC_MDELEM_AUTHORITY_EMPTY \ - ((grpc_mdelem){&grpc_static_mdelem_table[9]}) + (GRPC_MAKE_MDELEM(&grpc_static_mdelem_table[9], GRPC_MDELEM_STORAGE_STATIC)) /* "authorization": "" */ #define GRPC_MDELEM_AUTHORIZATION_EMPTY \ - ((grpc_mdelem){&grpc_static_mdelem_table[10]}) + (GRPC_MAKE_MDELEM(&grpc_static_mdelem_table[10], GRPC_MDELEM_STORAGE_STATIC)) /* "cache-control": "" */ #define GRPC_MDELEM_CACHE_CONTROL_EMPTY \ - ((grpc_mdelem){&grpc_static_mdelem_table[11]}) + (GRPC_MAKE_MDELEM(&grpc_static_mdelem_table[11], GRPC_MDELEM_STORAGE_STATIC)) /* "content-disposition": "" */ #define GRPC_MDELEM_CONTENT_DISPOSITION_EMPTY \ - ((grpc_mdelem){&grpc_static_mdelem_table[12]}) + (GRPC_MAKE_MDELEM(&grpc_static_mdelem_table[12], GRPC_MDELEM_STORAGE_STATIC)) /* "content-encoding": "" */ #define GRPC_MDELEM_CONTENT_ENCODING_EMPTY \ - ((grpc_mdelem){&grpc_static_mdelem_table[13]}) + (GRPC_MAKE_MDELEM(&grpc_static_mdelem_table[13], GRPC_MDELEM_STORAGE_STATIC)) /* "content-language": "" */ #define GRPC_MDELEM_CONTENT_LANGUAGE_EMPTY \ - ((grpc_mdelem){&grpc_static_mdelem_table[14]}) + (GRPC_MAKE_MDELEM(&grpc_static_mdelem_table[14], GRPC_MDELEM_STORAGE_STATIC)) /* "content-length": "" */ #define GRPC_MDELEM_CONTENT_LENGTH_EMPTY \ - ((grpc_mdelem){&grpc_static_mdelem_table[15]}) + (GRPC_MAKE_MDELEM(&grpc_static_mdelem_table[15], GRPC_MDELEM_STORAGE_STATIC)) /* "content-location": "" */ #define GRPC_MDELEM_CONTENT_LOCATION_EMPTY \ - ((grpc_mdelem){&grpc_static_mdelem_table[16]}) + (GRPC_MAKE_MDELEM(&grpc_static_mdelem_table[16], GRPC_MDELEM_STORAGE_STATIC)) /* "content-range": "" */ #define GRPC_MDELEM_CONTENT_RANGE_EMPTY \ - ((grpc_mdelem){&grpc_static_mdelem_table[17]}) + (GRPC_MAKE_MDELEM(&grpc_static_mdelem_table[17], GRPC_MDELEM_STORAGE_STATIC)) /* "content-type": "application/grpc" */ #define GRPC_MDELEM_CONTENT_TYPE_APPLICATION_SLASH_GRPC \ - ((grpc_mdelem){&grpc_static_mdelem_table[18]}) + (GRPC_MAKE_MDELEM(&grpc_static_mdelem_table[18], GRPC_MDELEM_STORAGE_STATIC)) /* "content-type": "" */ #define GRPC_MDELEM_CONTENT_TYPE_EMPTY \ - ((grpc_mdelem){&grpc_static_mdelem_table[19]}) + (GRPC_MAKE_MDELEM(&grpc_static_mdelem_table[19], GRPC_MDELEM_STORAGE_STATIC)) /* "cookie": "" */ -#define GRPC_MDELEM_COOKIE_EMPTY ((grpc_mdelem){&grpc_static_mdelem_table[20]}) +#define GRPC_MDELEM_COOKIE_EMPTY \ + (GRPC_MAKE_MDELEM(&grpc_static_mdelem_table[20], GRPC_MDELEM_STORAGE_STATIC)) /* "date": "" */ -#define GRPC_MDELEM_DATE_EMPTY ((grpc_mdelem){&grpc_static_mdelem_table[21]}) +#define GRPC_MDELEM_DATE_EMPTY \ + (GRPC_MAKE_MDELEM(&grpc_static_mdelem_table[21], GRPC_MDELEM_STORAGE_STATIC)) /* "etag": "" */ -#define GRPC_MDELEM_ETAG_EMPTY ((grpc_mdelem){&grpc_static_mdelem_table[22]}) +#define GRPC_MDELEM_ETAG_EMPTY \ + (GRPC_MAKE_MDELEM(&grpc_static_mdelem_table[22], GRPC_MDELEM_STORAGE_STATIC)) /* "expect": "" */ -#define GRPC_MDELEM_EXPECT_EMPTY ((grpc_mdelem){&grpc_static_mdelem_table[23]}) +#define GRPC_MDELEM_EXPECT_EMPTY \ + (GRPC_MAKE_MDELEM(&grpc_static_mdelem_table[23], GRPC_MDELEM_STORAGE_STATIC)) /* "expires": "" */ -#define GRPC_MDELEM_EXPIRES_EMPTY ((grpc_mdelem){&grpc_static_mdelem_table[24]}) +#define GRPC_MDELEM_EXPIRES_EMPTY \ + (GRPC_MAKE_MDELEM(&grpc_static_mdelem_table[24], GRPC_MDELEM_STORAGE_STATIC)) /* "from": "" */ -#define GRPC_MDELEM_FROM_EMPTY ((grpc_mdelem){&grpc_static_mdelem_table[25]}) +#define GRPC_MDELEM_FROM_EMPTY \ + (GRPC_MAKE_MDELEM(&grpc_static_mdelem_table[25], GRPC_MDELEM_STORAGE_STATIC)) /* "grpc-accept-encoding": "deflate" */ #define GRPC_MDELEM_GRPC_ACCEPT_ENCODING_DEFLATE \ - ((grpc_mdelem){&grpc_static_mdelem_table[26]}) + (GRPC_MAKE_MDELEM(&grpc_static_mdelem_table[26], GRPC_MDELEM_STORAGE_STATIC)) /* "grpc-accept-encoding": "deflate,gzip" */ #define GRPC_MDELEM_GRPC_ACCEPT_ENCODING_DEFLATE_COMMA_GZIP \ - ((grpc_mdelem){&grpc_static_mdelem_table[27]}) + (GRPC_MAKE_MDELEM(&grpc_static_mdelem_table[27], GRPC_MDELEM_STORAGE_STATIC)) /* "grpc-accept-encoding": "gzip" */ #define GRPC_MDELEM_GRPC_ACCEPT_ENCODING_GZIP \ - ((grpc_mdelem){&grpc_static_mdelem_table[28]}) + (GRPC_MAKE_MDELEM(&grpc_static_mdelem_table[28], GRPC_MDELEM_STORAGE_STATIC)) /* "grpc-accept-encoding": "identity" */ #define GRPC_MDELEM_GRPC_ACCEPT_ENCODING_IDENTITY \ - ((grpc_mdelem){&grpc_static_mdelem_table[29]}) + (GRPC_MAKE_MDELEM(&grpc_static_mdelem_table[29], GRPC_MDELEM_STORAGE_STATIC)) /* "grpc-accept-encoding": "identity,deflate" */ #define GRPC_MDELEM_GRPC_ACCEPT_ENCODING_IDENTITY_COMMA_DEFLATE \ - ((grpc_mdelem){&grpc_static_mdelem_table[30]}) + (GRPC_MAKE_MDELEM(&grpc_static_mdelem_table[30], GRPC_MDELEM_STORAGE_STATIC)) /* "grpc-accept-encoding": "identity,deflate,gzip" */ #define GRPC_MDELEM_GRPC_ACCEPT_ENCODING_IDENTITY_COMMA_DEFLATE_COMMA_GZIP \ - ((grpc_mdelem){&grpc_static_mdelem_table[31]}) + (GRPC_MAKE_MDELEM(&grpc_static_mdelem_table[31], GRPC_MDELEM_STORAGE_STATIC)) /* "grpc-accept-encoding": "identity,gzip" */ #define GRPC_MDELEM_GRPC_ACCEPT_ENCODING_IDENTITY_COMMA_GZIP \ - ((grpc_mdelem){&grpc_static_mdelem_table[32]}) + (GRPC_MAKE_MDELEM(&grpc_static_mdelem_table[32], GRPC_MDELEM_STORAGE_STATIC)) /* "grpc-encoding": "deflate" */ #define GRPC_MDELEM_GRPC_ENCODING_DEFLATE \ - ((grpc_mdelem){&grpc_static_mdelem_table[33]}) + (GRPC_MAKE_MDELEM(&grpc_static_mdelem_table[33], GRPC_MDELEM_STORAGE_STATIC)) /* "grpc-encoding": "gzip" */ #define GRPC_MDELEM_GRPC_ENCODING_GZIP \ - ((grpc_mdelem){&grpc_static_mdelem_table[34]}) + (GRPC_MAKE_MDELEM(&grpc_static_mdelem_table[34], GRPC_MDELEM_STORAGE_STATIC)) /* "grpc-encoding": "identity" */ #define GRPC_MDELEM_GRPC_ENCODING_IDENTITY \ - ((grpc_mdelem){&grpc_static_mdelem_table[35]}) + (GRPC_MAKE_MDELEM(&grpc_static_mdelem_table[35], GRPC_MDELEM_STORAGE_STATIC)) /* "grpc-status": "0" */ -#define GRPC_MDELEM_GRPC_STATUS_0 ((grpc_mdelem){&grpc_static_mdelem_table[36]}) +#define GRPC_MDELEM_GRPC_STATUS_0 \ + (GRPC_MAKE_MDELEM(&grpc_static_mdelem_table[36], GRPC_MDELEM_STORAGE_STATIC)) /* "grpc-status": "1" */ -#define GRPC_MDELEM_GRPC_STATUS_1 ((grpc_mdelem){&grpc_static_mdelem_table[37]}) +#define GRPC_MDELEM_GRPC_STATUS_1 \ + (GRPC_MAKE_MDELEM(&grpc_static_mdelem_table[37], GRPC_MDELEM_STORAGE_STATIC)) /* "grpc-status": "2" */ -#define GRPC_MDELEM_GRPC_STATUS_2 ((grpc_mdelem){&grpc_static_mdelem_table[38]}) +#define GRPC_MDELEM_GRPC_STATUS_2 \ + (GRPC_MAKE_MDELEM(&grpc_static_mdelem_table[38], GRPC_MDELEM_STORAGE_STATIC)) /* "host": "" */ -#define GRPC_MDELEM_HOST_EMPTY ((grpc_mdelem){&grpc_static_mdelem_table[39]}) +#define GRPC_MDELEM_HOST_EMPTY \ + (GRPC_MAKE_MDELEM(&grpc_static_mdelem_table[39], GRPC_MDELEM_STORAGE_STATIC)) /* "if-match": "" */ #define GRPC_MDELEM_IF_MATCH_EMPTY \ - ((grpc_mdelem){&grpc_static_mdelem_table[40]}) + (GRPC_MAKE_MDELEM(&grpc_static_mdelem_table[40], GRPC_MDELEM_STORAGE_STATIC)) /* "if-modified-since": "" */ #define GRPC_MDELEM_IF_MODIFIED_SINCE_EMPTY \ - ((grpc_mdelem){&grpc_static_mdelem_table[41]}) + (GRPC_MAKE_MDELEM(&grpc_static_mdelem_table[41], GRPC_MDELEM_STORAGE_STATIC)) /* "if-none-match": "" */ #define GRPC_MDELEM_IF_NONE_MATCH_EMPTY \ - ((grpc_mdelem){&grpc_static_mdelem_table[42]}) + (GRPC_MAKE_MDELEM(&grpc_static_mdelem_table[42], GRPC_MDELEM_STORAGE_STATIC)) /* "if-range": "" */ #define GRPC_MDELEM_IF_RANGE_EMPTY \ - ((grpc_mdelem){&grpc_static_mdelem_table[43]}) + (GRPC_MAKE_MDELEM(&grpc_static_mdelem_table[43], GRPC_MDELEM_STORAGE_STATIC)) /* "if-unmodified-since": "" */ #define GRPC_MDELEM_IF_UNMODIFIED_SINCE_EMPTY \ - ((grpc_mdelem){&grpc_static_mdelem_table[44]}) + (GRPC_MAKE_MDELEM(&grpc_static_mdelem_table[44], GRPC_MDELEM_STORAGE_STATIC)) /* "last-modified": "" */ #define GRPC_MDELEM_LAST_MODIFIED_EMPTY \ - ((grpc_mdelem){&grpc_static_mdelem_table[45]}) + (GRPC_MAKE_MDELEM(&grpc_static_mdelem_table[45], GRPC_MDELEM_STORAGE_STATIC)) /* "lb-cost-bin": "" */ #define GRPC_MDELEM_LB_COST_BIN_EMPTY \ - ((grpc_mdelem){&grpc_static_mdelem_table[46]}) + (GRPC_MAKE_MDELEM(&grpc_static_mdelem_table[46], GRPC_MDELEM_STORAGE_STATIC)) /* "lb-token": "" */ #define GRPC_MDELEM_LB_TOKEN_EMPTY \ - ((grpc_mdelem){&grpc_static_mdelem_table[47]}) + (GRPC_MAKE_MDELEM(&grpc_static_mdelem_table[47], GRPC_MDELEM_STORAGE_STATIC)) /* "link": "" */ -#define GRPC_MDELEM_LINK_EMPTY ((grpc_mdelem){&grpc_static_mdelem_table[48]}) +#define GRPC_MDELEM_LINK_EMPTY \ + (GRPC_MAKE_MDELEM(&grpc_static_mdelem_table[48], GRPC_MDELEM_STORAGE_STATIC)) /* "location": "" */ #define GRPC_MDELEM_LOCATION_EMPTY \ - ((grpc_mdelem){&grpc_static_mdelem_table[49]}) + (GRPC_MAKE_MDELEM(&grpc_static_mdelem_table[49], GRPC_MDELEM_STORAGE_STATIC)) /* "max-forwards": "" */ #define GRPC_MDELEM_MAX_FORWARDS_EMPTY \ - ((grpc_mdelem){&grpc_static_mdelem_table[50]}) + (GRPC_MAKE_MDELEM(&grpc_static_mdelem_table[50], GRPC_MDELEM_STORAGE_STATIC)) /* ":method": "GET" */ -#define GRPC_MDELEM_METHOD_GET ((grpc_mdelem){&grpc_static_mdelem_table[51]}) +#define GRPC_MDELEM_METHOD_GET \ + (GRPC_MAKE_MDELEM(&grpc_static_mdelem_table[51], GRPC_MDELEM_STORAGE_STATIC)) /* ":method": "POST" */ -#define GRPC_MDELEM_METHOD_POST ((grpc_mdelem){&grpc_static_mdelem_table[52]}) +#define GRPC_MDELEM_METHOD_POST \ + (GRPC_MAKE_MDELEM(&grpc_static_mdelem_table[52], GRPC_MDELEM_STORAGE_STATIC)) /* ":method": "PUT" */ -#define GRPC_MDELEM_METHOD_PUT ((grpc_mdelem){&grpc_static_mdelem_table[53]}) +#define GRPC_MDELEM_METHOD_PUT \ + (GRPC_MAKE_MDELEM(&grpc_static_mdelem_table[53], GRPC_MDELEM_STORAGE_STATIC)) /* ":path": "/" */ -#define GRPC_MDELEM_PATH_SLASH ((grpc_mdelem){&grpc_static_mdelem_table[54]}) +#define GRPC_MDELEM_PATH_SLASH \ + (GRPC_MAKE_MDELEM(&grpc_static_mdelem_table[54], GRPC_MDELEM_STORAGE_STATIC)) /* ":path": "/index.html" */ #define GRPC_MDELEM_PATH_SLASH_INDEX_DOT_HTML \ - ((grpc_mdelem){&grpc_static_mdelem_table[55]}) + (GRPC_MAKE_MDELEM(&grpc_static_mdelem_table[55], GRPC_MDELEM_STORAGE_STATIC)) /* "proxy-authenticate": "" */ #define GRPC_MDELEM_PROXY_AUTHENTICATE_EMPTY \ - ((grpc_mdelem){&grpc_static_mdelem_table[56]}) + (GRPC_MAKE_MDELEM(&grpc_static_mdelem_table[56], GRPC_MDELEM_STORAGE_STATIC)) /* "proxy-authorization": "" */ #define GRPC_MDELEM_PROXY_AUTHORIZATION_EMPTY \ - ((grpc_mdelem){&grpc_static_mdelem_table[57]}) + (GRPC_MAKE_MDELEM(&grpc_static_mdelem_table[57], GRPC_MDELEM_STORAGE_STATIC)) /* "range": "" */ -#define GRPC_MDELEM_RANGE_EMPTY ((grpc_mdelem){&grpc_static_mdelem_table[58]}) +#define GRPC_MDELEM_RANGE_EMPTY \ + (GRPC_MAKE_MDELEM(&grpc_static_mdelem_table[58], GRPC_MDELEM_STORAGE_STATIC)) /* "referer": "" */ -#define GRPC_MDELEM_REFERER_EMPTY ((grpc_mdelem){&grpc_static_mdelem_table[59]}) +#define GRPC_MDELEM_REFERER_EMPTY \ + (GRPC_MAKE_MDELEM(&grpc_static_mdelem_table[59], GRPC_MDELEM_STORAGE_STATIC)) /* "refresh": "" */ -#define GRPC_MDELEM_REFRESH_EMPTY ((grpc_mdelem){&grpc_static_mdelem_table[60]}) +#define GRPC_MDELEM_REFRESH_EMPTY \ + (GRPC_MAKE_MDELEM(&grpc_static_mdelem_table[60], GRPC_MDELEM_STORAGE_STATIC)) /* "retry-after": "" */ #define GRPC_MDELEM_RETRY_AFTER_EMPTY \ - ((grpc_mdelem){&grpc_static_mdelem_table[61]}) + (GRPC_MAKE_MDELEM(&grpc_static_mdelem_table[61], GRPC_MDELEM_STORAGE_STATIC)) /* ":scheme": "grpc" */ -#define GRPC_MDELEM_SCHEME_GRPC ((grpc_mdelem){&grpc_static_mdelem_table[62]}) +#define GRPC_MDELEM_SCHEME_GRPC \ + (GRPC_MAKE_MDELEM(&grpc_static_mdelem_table[62], GRPC_MDELEM_STORAGE_STATIC)) /* ":scheme": "http" */ -#define GRPC_MDELEM_SCHEME_HTTP ((grpc_mdelem){&grpc_static_mdelem_table[63]}) +#define GRPC_MDELEM_SCHEME_HTTP \ + (GRPC_MAKE_MDELEM(&grpc_static_mdelem_table[63], GRPC_MDELEM_STORAGE_STATIC)) /* ":scheme": "https" */ -#define GRPC_MDELEM_SCHEME_HTTPS ((grpc_mdelem){&grpc_static_mdelem_table[64]}) +#define GRPC_MDELEM_SCHEME_HTTPS \ + (GRPC_MAKE_MDELEM(&grpc_static_mdelem_table[64], GRPC_MDELEM_STORAGE_STATIC)) /* "server": "" */ -#define GRPC_MDELEM_SERVER_EMPTY ((grpc_mdelem){&grpc_static_mdelem_table[65]}) +#define GRPC_MDELEM_SERVER_EMPTY \ + (GRPC_MAKE_MDELEM(&grpc_static_mdelem_table[65], GRPC_MDELEM_STORAGE_STATIC)) /* "set-cookie": "" */ #define GRPC_MDELEM_SET_COOKIE_EMPTY \ - ((grpc_mdelem){&grpc_static_mdelem_table[66]}) + (GRPC_MAKE_MDELEM(&grpc_static_mdelem_table[66], GRPC_MDELEM_STORAGE_STATIC)) /* ":status": "200" */ -#define GRPC_MDELEM_STATUS_200 ((grpc_mdelem){&grpc_static_mdelem_table[67]}) +#define GRPC_MDELEM_STATUS_200 \ + (GRPC_MAKE_MDELEM(&grpc_static_mdelem_table[67], GRPC_MDELEM_STORAGE_STATIC)) /* ":status": "204" */ -#define GRPC_MDELEM_STATUS_204 ((grpc_mdelem){&grpc_static_mdelem_table[68]}) +#define GRPC_MDELEM_STATUS_204 \ + (GRPC_MAKE_MDELEM(&grpc_static_mdelem_table[68], GRPC_MDELEM_STORAGE_STATIC)) /* ":status": "206" */ -#define GRPC_MDELEM_STATUS_206 ((grpc_mdelem){&grpc_static_mdelem_table[69]}) +#define GRPC_MDELEM_STATUS_206 \ + (GRPC_MAKE_MDELEM(&grpc_static_mdelem_table[69], GRPC_MDELEM_STORAGE_STATIC)) /* ":status": "304" */ -#define GRPC_MDELEM_STATUS_304 ((grpc_mdelem){&grpc_static_mdelem_table[70]}) +#define GRPC_MDELEM_STATUS_304 \ + (GRPC_MAKE_MDELEM(&grpc_static_mdelem_table[70], GRPC_MDELEM_STORAGE_STATIC)) /* ":status": "400" */ -#define GRPC_MDELEM_STATUS_400 ((grpc_mdelem){&grpc_static_mdelem_table[71]}) +#define GRPC_MDELEM_STATUS_400 \ + (GRPC_MAKE_MDELEM(&grpc_static_mdelem_table[71], GRPC_MDELEM_STORAGE_STATIC)) /* ":status": "404" */ -#define GRPC_MDELEM_STATUS_404 ((grpc_mdelem){&grpc_static_mdelem_table[72]}) +#define GRPC_MDELEM_STATUS_404 \ + (GRPC_MAKE_MDELEM(&grpc_static_mdelem_table[72], GRPC_MDELEM_STORAGE_STATIC)) /* ":status": "500" */ -#define GRPC_MDELEM_STATUS_500 ((grpc_mdelem){&grpc_static_mdelem_table[73]}) +#define GRPC_MDELEM_STATUS_500 \ + (GRPC_MAKE_MDELEM(&grpc_static_mdelem_table[73], GRPC_MDELEM_STORAGE_STATIC)) /* "strict-transport-security": "" */ #define GRPC_MDELEM_STRICT_TRANSPORT_SECURITY_EMPTY \ - ((grpc_mdelem){&grpc_static_mdelem_table[74]}) + (GRPC_MAKE_MDELEM(&grpc_static_mdelem_table[74], GRPC_MDELEM_STORAGE_STATIC)) /* "te": "trailers" */ -#define GRPC_MDELEM_TE_TRAILERS ((grpc_mdelem){&grpc_static_mdelem_table[75]}) +#define GRPC_MDELEM_TE_TRAILERS \ + (GRPC_MAKE_MDELEM(&grpc_static_mdelem_table[75], GRPC_MDELEM_STORAGE_STATIC)) /* "transfer-encoding": "" */ #define GRPC_MDELEM_TRANSFER_ENCODING_EMPTY \ - ((grpc_mdelem){&grpc_static_mdelem_table[76]}) + (GRPC_MAKE_MDELEM(&grpc_static_mdelem_table[76], GRPC_MDELEM_STORAGE_STATIC)) /* "user-agent": "" */ #define GRPC_MDELEM_USER_AGENT_EMPTY \ - ((grpc_mdelem){&grpc_static_mdelem_table[77]}) + (GRPC_MAKE_MDELEM(&grpc_static_mdelem_table[77], GRPC_MDELEM_STORAGE_STATIC)) /* "vary": "" */ -#define GRPC_MDELEM_VARY_EMPTY ((grpc_mdelem){&grpc_static_mdelem_table[78]}) +#define GRPC_MDELEM_VARY_EMPTY \ + (GRPC_MAKE_MDELEM(&grpc_static_mdelem_table[78], GRPC_MDELEM_STORAGE_STATIC)) /* "via": "" */ -#define GRPC_MDELEM_VIA_EMPTY ((grpc_mdelem){&grpc_static_mdelem_table[79]}) +#define GRPC_MDELEM_VIA_EMPTY \ + (GRPC_MAKE_MDELEM(&grpc_static_mdelem_table[79], GRPC_MDELEM_STORAGE_STATIC)) /* "www-authenticate": "" */ #define GRPC_MDELEM_WWW_AUTHENTICATE_EMPTY \ - ((grpc_mdelem){&grpc_static_mdelem_table[80]}) + (GRPC_MAKE_MDELEM(&grpc_static_mdelem_table[80], GRPC_MDELEM_STORAGE_STATIC)) grpc_mdelem grpc_static_mdelem_for_static_strings(int a, int b); extern const uint8_t grpc_static_accept_encoding_metadata[8]; -#define GRPC_MDELEM_ACCEPT_ENCODING_FOR_ALGORITHMS(algs) \ - ((grpc_mdelem){&grpc_static_mdelem_table \ - [grpc_static_accept_encoding_metadata[(algs)]]}) +#define GRPC_MDELEM_ACCEPT_ENCODING_FOR_ALGORITHMS(algs) \ + (GRPC_MAKE_MDELEM( \ + &grpc_static_mdelem_table[grpc_static_accept_encoding_metadata[(algs)]], \ + GRPC_MDELEM_STORAGE_STATIC)) #endif /* GRPC_CORE_LIB_TRANSPORT_STATIC_METADATA_H */ diff --git a/test/core/transport/metadata_test.c b/test/core/transport/metadata_test.c index d31bc1eedf5..ce8f1813ffd 100644 --- a/test/core/transport/metadata_test.c +++ b/test/core/transport/metadata_test.c @@ -189,8 +189,39 @@ static void test_spin_creating_the_same_thing(bool intern_keys, &exec_ctx, maybe_intern(grpc_slice_from_static_string("a"), intern_keys), maybe_intern(grpc_slice_from_static_string("b"), intern_values))); + if (intern_keys && intern_values) { + GPR_ASSERT(a.payload == b.payload); + GPR_ASSERT(a.payload == c.payload); + } + grpc_exec_ctx_finish(&exec_ctx); + grpc_shutdown(); +} + +static void test_identity_laws(bool intern_keys, bool intern_values) { + gpr_log(GPR_INFO, "test_identity_laws: intern_keys=%d intern_values=%d", + intern_keys, intern_values); + + grpc_init(); + grpc_exec_ctx exec_ctx = GRPC_EXEC_CTX_INIT; + grpc_mdelem a, b, c; + a = grpc_mdelem_from_slices( + &exec_ctx, maybe_intern(grpc_slice_from_static_string("a"), intern_keys), + maybe_intern(grpc_slice_from_static_string("b"), intern_values)); + b = grpc_mdelem_from_slices( + &exec_ctx, maybe_intern(grpc_slice_from_static_string("a"), intern_keys), + maybe_intern(grpc_slice_from_static_string("b"), intern_values)); + c = grpc_mdelem_from_slices( + &exec_ctx, maybe_intern(grpc_slice_from_static_string("a"), intern_keys), + maybe_intern(grpc_slice_from_static_string("b"), intern_values)); + GPR_ASSERT(grpc_mdelem_eq(a, a)); + GPR_ASSERT(grpc_mdelem_eq(b, b)); + GPR_ASSERT(grpc_mdelem_eq(c, c)); GPR_ASSERT(grpc_mdelem_eq(a, b)); + GPR_ASSERT(grpc_mdelem_eq(b, c)); GPR_ASSERT(grpc_mdelem_eq(a, c)); + GPR_ASSERT(grpc_mdelem_eq(b, a)); + GPR_ASSERT(grpc_mdelem_eq(c, b)); + GPR_ASSERT(grpc_mdelem_eq(c, a)); if (intern_keys && intern_values) { GPR_ASSERT(a.payload == b.payload); GPR_ASSERT(a.payload == c.payload); @@ -199,6 +230,9 @@ static void test_spin_creating_the_same_thing(bool intern_keys, GPR_ASSERT(a.payload != c.payload); GPR_ASSERT(b.payload != c.payload); } + GRPC_MDELEM_UNREF(&exec_ctx, a); + GRPC_MDELEM_UNREF(&exec_ctx, b); + GRPC_MDELEM_UNREF(&exec_ctx, c); grpc_exec_ctx_finish(&exec_ctx); grpc_shutdown(); } @@ -344,7 +378,8 @@ static void test_copied_static_metadata(bool dup_key, bool dup_value) { grpc_exec_ctx exec_ctx = GRPC_EXEC_CTX_INIT; for (size_t i = 0; i < GRPC_STATIC_MDELEM_COUNT; i++) { - grpc_mdelem p = (grpc_mdelem){&grpc_static_mdelem_table[i]}; + grpc_mdelem p = GRPC_MAKE_MDELEM(&grpc_static_mdelem_table[i], + GRPC_MDELEM_STORAGE_STATIC); grpc_mdelem q = grpc_mdelem_from_slices(&exec_ctx, maybe_dup(GRPC_MDKEY(p), dup_key), maybe_dup(GRPC_MDVALUE(p), dup_value)); @@ -367,6 +402,7 @@ int main(int argc, char **argv) { for (int v = 0; v <= 1; v++) { test_create_metadata(k, v); test_create_many_ephemeral_metadata(k, v); + test_identity_laws(k, v); test_spin_creating_the_same_thing(k, v); test_mdelem_sizes_in_hpack(k, v); test_copied_static_metadata(k, v); diff --git a/tools/codegen/core/gen_static_metadata.py b/tools/codegen/core/gen_static_metadata.py index e1acdc12c6f..b1b7840cfd7 100755 --- a/tools/codegen/core/gen_static_metadata.py +++ b/tools/codegen/core/gen_static_metadata.py @@ -359,7 +359,7 @@ print >>H, 'extern grpc_mdelem_data grpc_static_mdelem_table[GRPC_STATIC_MDELEM_ print >>H, 'extern uintptr_t grpc_static_mdelem_user_data[GRPC_STATIC_MDELEM_COUNT];' for i, elem in enumerate(all_elems): print >>H, '/* "%s": "%s" */' % elem - print >>H, '#define %s ((grpc_mdelem){&grpc_static_mdelem_table[%d]})' % (mangle(elem).upper(), i) + print >>H, '#define %s (GRPC_MAKE_MDELEM(&grpc_static_mdelem_table[%d], GRPC_MDELEM_STORAGE_STATIC))' % (mangle(elem).upper(), i) print >>H print >>C, 'uintptr_t grpc_static_mdelem_user_data[GRPC_STATIC_MDELEM_COUNT] = {' print >>C, ' %s' % ','.join('%d' % static_userdata.get(elem, 0) for elem in all_elems) @@ -440,7 +440,7 @@ print >>C, 'grpc_mdelem grpc_static_mdelem_for_static_strings(int a, int b) {' print >>C, ' if (a == -1 || b == -1) return GRPC_MDNULL;' print >>C, ' uint32_t k = (uint32_t)(a * %d + b);' % len(all_strs) print >>C, ' uint32_t h = elems_phash(k);' -print >>C, ' return elem_keys[h] == k ? (grpc_mdelem){&grpc_static_mdelem_table[elem_idxs[h]]} : GRPC_MDNULL;' +print >>C, ' return elem_keys[h] == k ? GRPC_MAKE_MDELEM(&grpc_static_mdelem_table[elem_idxs[h]], GRPC_MDELEM_STORAGE_STATIC) : GRPC_MDNULL;' print >>C, '}' print >>C @@ -455,7 +455,7 @@ print >>C, '0,%s' % ','.join('%d' % md_idx(elem) for elem in compression_elems) print >>C, '};' print >>C -print >>H, '#define GRPC_MDELEM_ACCEPT_ENCODING_FOR_ALGORITHMS(algs) ((grpc_mdelem){&grpc_static_mdelem_table[grpc_static_accept_encoding_metadata[(algs)]]})' +print >>H, '#define GRPC_MDELEM_ACCEPT_ENCODING_FOR_ALGORITHMS(algs) (GRPC_MAKE_MDELEM(&grpc_static_mdelem_table[grpc_static_accept_encoding_metadata[(algs)]], GRPC_MDELEM_STORAGE_STATIC))' print >>H, '#endif /* GRPC_CORE_LIB_TRANSPORT_STATIC_METADATA_H */'