blob: ef5fd32b52e00b8173095b941635d8de7be197d8 [file] [log] [blame]
Nicolas Nobleb7ebd3b2014-11-26 16:33:03 -08001/*
2 *
Craig Tiller6169d5f2016-03-31 07:46:18 -07003 * Copyright 2015, Google Inc.
Nicolas Nobleb7ebd3b2014-11-26 16:33:03 -08004 * All rights reserved.
5 *
6 * Redistribution and use in source and binary forms, with or without
7 * modification, are permitted provided that the following conditions are
8 * met:
9 *
10 * * Redistributions of source code must retain the above copyright
11 * notice, this list of conditions and the following disclaimer.
12 * * Redistributions in binary form must reproduce the above
13 * copyright notice, this list of conditions and the following disclaimer
14 * in the documentation and/or other materials provided with the
15 * distribution.
16 * * Neither the name of Google Inc. nor the names of its
17 * contributors may be used to endorse or promote products derived from
18 * this software without specific prior written permission.
19 *
20 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
21 * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
22 * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
23 * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
24 * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
25 * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
26 * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
27 * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
28 * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
29 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
30 * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
31 *
32 */
33
Craig Tiller9533d042016-03-25 17:11:06 -070034#include "src/core/lib/transport/metadata.h"
Nicolas Nobleb7ebd3b2014-11-26 16:33:03 -080035
Craig Tiller9fa41b92015-04-10 15:08:03 -070036#include <assert.h>
Nicolas Nobleb7ebd3b2014-11-26 16:33:03 -080037#include <stddef.h>
38#include <string.h>
39
Craig Tillerebdef9d2015-11-19 17:09:49 -080040#include <grpc/compression.h>
yang-gcb7a8022016-03-30 14:58:53 -070041#include <grpc/grpc.h>
Nicolas Nobleb7ebd3b2014-11-26 16:33:03 -080042#include <grpc/support/alloc.h>
Craig Tiller9fa41b92015-04-10 15:08:03 -070043#include <grpc/support/atm.h>
Nicolas Nobleb7ebd3b2014-11-26 16:33:03 -080044#include <grpc/support/log.h>
Craig Tillerebdef9d2015-11-19 17:09:49 -080045#include <grpc/support/string_util.h>
Craig Tiller9d35a1f2015-11-02 14:16:12 -080046#include <grpc/support/time.h>
Craig Tiller0cb803d2016-03-02 22:17:24 -080047
Craig Tiller9533d042016-03-25 17:11:06 -070048#include "src/core/lib/iomgr/iomgr_internal.h"
49#include "src/core/lib/profiling/timers.h"
Craig Tillera59c16c2016-10-31 07:25:01 -070050#include "src/core/lib/slice/slice_internal.h"
Craig Tiller9533d042016-03-25 17:11:06 -070051#include "src/core/lib/support/murmur_hash.h"
52#include "src/core/lib/support/string.h"
Craig Tiller9533d042016-03-25 17:11:06 -070053#include "src/core/lib/transport/static_metadata.h"
Nicolas Nobleb7ebd3b2014-11-26 16:33:03 -080054
Craig Tillerd41a4a72016-10-26 16:16:06 -070055grpc_slice (*grpc_chttp2_base64_encode_and_huffman_compress)(grpc_slice input);
Craig Tillerf82ddc42016-04-05 17:15:07 -070056
Craig Tiller70b080d2015-11-19 08:04:48 -080057/* There are two kinds of mdelem and mdstr instances.
58 * Static instances are declared in static_metadata.{h,c} and
59 * are initialized by grpc_mdctx_global_init().
60 * Dynamic instances are stored in hash tables on grpc_mdctx, and are backed
61 * by internal_string and internal_element structures.
62 * Internal helper functions here-in (is_mdstr_static, is_mdelem_static) are
63 * used to determine which kind of element a pointer refers to.
64 */
65
Nicolas Nobleb7ebd3b2014-11-26 16:33:03 -080066#define INITIAL_STRTAB_CAPACITY 4
67#define INITIAL_MDTAB_CAPACITY 4
68
Craig Tiller1a65a232015-07-06 10:22:32 -070069#ifdef GRPC_METADATA_REFCOUNT_DEBUG
70#define DEBUG_ARGS , const char *file, int line
71#define FWD_DEBUG_ARGS , file, line
Craig Tillerb2b42612015-11-20 12:02:17 -080072#define REF_MD_LOCKED(shard, s) ref_md_locked((shard), (s), __FILE__, __LINE__)
Craig Tiller1a65a232015-07-06 10:22:32 -070073#else
74#define DEBUG_ARGS
75#define FWD_DEBUG_ARGS
Craig Tillerb2b42612015-11-20 12:02:17 -080076#define REF_MD_LOCKED(shard, s) ref_md_locked((shard), (s))
Craig Tiller1a65a232015-07-06 10:22:32 -070077#endif
78
Craig Tillerb2b42612015-11-20 12:02:17 -080079#define TABLE_IDX(hash, log2_shards, capacity) \
80 (((hash) >> (log2_shards)) % (capacity))
81#define SHARD_IDX(hash, log2_shards) ((hash) & ((1 << (log2_shards)) - 1))
82
Craig Tiller8344daa2015-10-09 18:10:57 -070083typedef void (*destroy_user_data_func)(void *user_data);
84
yang-g4a530b02016-03-31 11:44:44 -070085#define SIZE_IN_DECODER_TABLE_NOT_SET -1
Craig Tiller70b080d2015-11-19 08:04:48 -080086/* Shadow structure for grpc_mdstr for non-static values */
Nicolas Nobleb7ebd3b2014-11-26 16:33:03 -080087typedef struct internal_string {
88 /* must be byte compatible with grpc_mdstr */
Craig Tillerd41a4a72016-10-26 16:16:06 -070089 grpc_slice slice;
Craig Tiller7536af02015-12-22 13:49:30 -080090 uint32_t hash;
Nicolas Nobleb7ebd3b2014-11-26 16:33:03 -080091
92 /* private only data */
Craig Tillerb2b42612015-11-20 12:02:17 -080093 gpr_atm refcnt;
94
Craig Tiller7536af02015-12-22 13:49:30 -080095 uint8_t has_base64_and_huffman_encoded;
Craig Tillerd41a4a72016-10-26 16:16:06 -070096 grpc_slice_refcount refcount;
Nicolas Nobleb7ebd3b2014-11-26 16:33:03 -080097
Craig Tillerd41a4a72016-10-26 16:16:06 -070098 grpc_slice base64_and_huffman;
ctiller430c4992014-12-11 09:15:41 -080099
yang-g4a530b02016-03-31 11:44:44 -0700100 gpr_atm size_in_decoder_table;
yang-gcb7a8022016-03-30 14:58:53 -0700101
Nicolas Nobleb7ebd3b2014-11-26 16:33:03 -0800102 struct internal_string *bucket_next;
103} internal_string;
104
Craig Tiller70b080d2015-11-19 08:04:48 -0800105/* Shadow structure for grpc_mdelem for non-static elements */
Nicolas Nobleb7ebd3b2014-11-26 16:33:03 -0800106typedef struct internal_metadata {
107 /* must be byte compatible with grpc_mdelem */
108 internal_string *key;
109 internal_string *value;
110
Craig Tillerb2b42612015-11-20 12:02:17 -0800111 /* private only data */
Craig Tiller9fa41b92015-04-10 15:08:03 -0700112 gpr_atm refcnt;
113
Craig Tiller83901532015-07-10 14:02:45 -0700114 gpr_mu mu_user_data;
Craig Tiller8344daa2015-10-09 18:10:57 -0700115 gpr_atm destroy_user_data;
116 gpr_atm user_data;
Nicolas Nobleb7ebd3b2014-11-26 16:33:03 -0800117
Nicolas Nobleb7ebd3b2014-11-26 16:33:03 -0800118 struct internal_metadata *bucket_next;
119} internal_metadata;
120
Craig Tillerb2b42612015-11-20 12:02:17 -0800121typedef struct strtab_shard {
Nicolas Nobleb7ebd3b2014-11-26 16:33:03 -0800122 gpr_mu mu;
Craig Tillerb2b42612015-11-20 12:02:17 -0800123 internal_string **strs;
124 size_t count;
125 size_t capacity;
126} strtab_shard;
Nicolas Nobleb7ebd3b2014-11-26 16:33:03 -0800127
Craig Tillerb2b42612015-11-20 12:02:17 -0800128typedef struct mdtab_shard {
129 gpr_mu mu;
130 internal_metadata **elems;
131 size_t count;
132 size_t capacity;
Craig Tiller8d8f9a82016-06-03 08:49:11 -0700133 /** Estimate of the number of unreferenced mdelems in the hash table.
134 This will eventually converge to the exact number, but it's instantaneous
135 accuracy is not guaranteed */
136 gpr_atm free_estimate;
Craig Tillerb2b42612015-11-20 12:02:17 -0800137} mdtab_shard;
Craig Tiller0e72ede2015-11-19 07:48:53 -0800138
Craig Tillerb2b42612015-11-20 12:02:17 -0800139#define LOG2_STRTAB_SHARD_COUNT 5
140#define LOG2_MDTAB_SHARD_COUNT 4
141#define STRTAB_SHARD_COUNT ((size_t)(1 << LOG2_STRTAB_SHARD_COUNT))
142#define MDTAB_SHARD_COUNT ((size_t)(1 << LOG2_MDTAB_SHARD_COUNT))
Nicolas Nobleb7ebd3b2014-11-26 16:33:03 -0800143
Craig Tillerb2b42612015-11-20 12:02:17 -0800144/* hash seed: decided at initialization time */
Craig Tiller7536af02015-12-22 13:49:30 -0800145static uint32_t g_hash_seed;
Craig Tillere62bf982015-12-02 17:11:49 -0800146static int g_forced_hash_seed = 0;
Craig Tillerebdef9d2015-11-19 17:09:49 -0800147
Craig Tillerb2b42612015-11-20 12:02:17 -0800148/* linearly probed hash tables for static element lookup */
149static grpc_mdstr *g_static_strtab[GRPC_STATIC_MDSTR_COUNT * 2];
150static grpc_mdelem *g_static_mdtab[GRPC_STATIC_MDELEM_COUNT * 2];
151static size_t g_static_strtab_maxprobe;
152static size_t g_static_mdtab_maxprobe;
Nicolas Nobleb7ebd3b2014-11-26 16:33:03 -0800153
Craig Tillerb2b42612015-11-20 12:02:17 -0800154static strtab_shard g_strtab_shard[STRTAB_SHARD_COUNT];
155static mdtab_shard g_mdtab_shard[MDTAB_SHARD_COUNT];
156
Craig Tillera59c16c2016-10-31 07:25:01 -0700157static void gc_mdtab(grpc_exec_ctx *exec_ctx, mdtab_shard *shard);
Nicolas Nobleb7ebd3b2014-11-26 16:33:03 -0800158
Craig Tiller7536af02015-12-22 13:49:30 -0800159void grpc_test_only_set_metadata_hash_seed(uint32_t seed) {
Craig Tillere62bf982015-12-02 17:11:49 -0800160 g_hash_seed = seed;
161 g_forced_hash_seed = 1;
162}
163
Craig Tiller0e72ede2015-11-19 07:48:53 -0800164void grpc_mdctx_global_init(void) {
Craig Tillerb2b42612015-11-20 12:02:17 -0800165 size_t i, j;
Craig Tillere62bf982015-12-02 17:11:49 -0800166 if (!g_forced_hash_seed) {
Craig Tiller7536af02015-12-22 13:49:30 -0800167 g_hash_seed = (uint32_t)gpr_now(GPR_CLOCK_REALTIME).tv_nsec;
Craig Tillere62bf982015-12-02 17:11:49 -0800168 }
Craig Tillerb2b42612015-11-20 12:02:17 -0800169 g_static_strtab_maxprobe = 0;
170 g_static_mdtab_maxprobe = 0;
171 /* build static tables */
172 memset(g_static_mdtab, 0, sizeof(g_static_mdtab));
173 memset(g_static_strtab, 0, sizeof(g_static_strtab));
Craig Tiller0e72ede2015-11-19 07:48:53 -0800174 for (i = 0; i < GRPC_STATIC_MDSTR_COUNT; i++) {
175 grpc_mdstr *elem = &grpc_static_mdstr_table[i];
176 const char *str = grpc_static_metadata_strings[i];
Craig Tiller7536af02015-12-22 13:49:30 -0800177 uint32_t hash = gpr_murmur_hash3(str, strlen(str), g_hash_seed);
Craig Tillerd41a4a72016-10-26 16:16:06 -0700178 *(grpc_slice *)&elem->slice = grpc_slice_from_static_string(str);
Craig Tiller7536af02015-12-22 13:49:30 -0800179 *(uint32_t *)&elem->hash = hash;
Craig Tillerb2b42612015-11-20 12:02:17 -0800180 for (j = 0;; j++) {
181 size_t idx = (hash + j) % GPR_ARRAY_SIZE(g_static_strtab);
182 if (g_static_strtab[idx] == NULL) {
183 g_static_strtab[idx] = &grpc_static_mdstr_table[i];
184 break;
185 }
186 }
187 if (j > g_static_strtab_maxprobe) {
188 g_static_strtab_maxprobe = j;
189 }
Craig Tiller0e72ede2015-11-19 07:48:53 -0800190 }
191 for (i = 0; i < GRPC_STATIC_MDELEM_COUNT; i++) {
192 grpc_mdelem *elem = &grpc_static_mdelem_table[i];
Craig Tillerebdef9d2015-11-19 17:09:49 -0800193 grpc_mdstr *key =
194 &grpc_static_mdstr_table[grpc_static_metadata_elem_indices[2 * i + 0]];
195 grpc_mdstr *value =
196 &grpc_static_mdstr_table[grpc_static_metadata_elem_indices[2 * i + 1]];
Craig Tiller7536af02015-12-22 13:49:30 -0800197 uint32_t hash = GRPC_MDSTR_KV_HASH(key->hash, value->hash);
Craig Tillerb774be42015-11-19 07:56:13 -0800198 *(grpc_mdstr **)&elem->key = key;
199 *(grpc_mdstr **)&elem->value = value;
Craig Tillerb2b42612015-11-20 12:02:17 -0800200 for (j = 0;; j++) {
201 size_t idx = (hash + j) % GPR_ARRAY_SIZE(g_static_mdtab);
202 if (g_static_mdtab[idx] == NULL) {
203 g_static_mdtab[idx] = elem;
204 break;
205 }
206 }
207 if (j > g_static_mdtab_maxprobe) {
208 g_static_mdtab_maxprobe = j;
209 }
210 }
211 /* initialize shards */
212 for (i = 0; i < STRTAB_SHARD_COUNT; i++) {
213 strtab_shard *shard = &g_strtab_shard[i];
214 gpr_mu_init(&shard->mu);
215 shard->count = 0;
216 shard->capacity = INITIAL_STRTAB_CAPACITY;
217 shard->strs = gpr_malloc(sizeof(*shard->strs) * shard->capacity);
218 memset(shard->strs, 0, sizeof(*shard->strs) * shard->capacity);
219 }
220 for (i = 0; i < MDTAB_SHARD_COUNT; i++) {
221 mdtab_shard *shard = &g_mdtab_shard[i];
222 gpr_mu_init(&shard->mu);
223 shard->count = 0;
Craig Tiller8d8f9a82016-06-03 08:49:11 -0700224 gpr_atm_no_barrier_store(&shard->free_estimate, 0);
Craig Tillerb2b42612015-11-20 12:02:17 -0800225 shard->capacity = INITIAL_MDTAB_CAPACITY;
226 shard->elems = gpr_malloc(sizeof(*shard->elems) * shard->capacity);
227 memset(shard->elems, 0, sizeof(*shard->elems) * shard->capacity);
Craig Tiller0e72ede2015-11-19 07:48:53 -0800228 }
229}
230
Craig Tillera59c16c2016-10-31 07:25:01 -0700231void grpc_mdctx_global_shutdown(grpc_exec_ctx *exec_ctx) {
Craig Tillerb2b42612015-11-20 12:02:17 -0800232 size_t i;
233 for (i = 0; i < MDTAB_SHARD_COUNT; i++) {
234 mdtab_shard *shard = &g_mdtab_shard[i];
235 gpr_mu_destroy(&shard->mu);
Craig Tillera59c16c2016-10-31 07:25:01 -0700236 gc_mdtab(exec_ctx, shard);
Craig Tiller34075442015-11-23 16:16:54 -0800237 /* TODO(ctiller): GPR_ASSERT(shard->count == 0); */
238 if (shard->count != 0) {
Yuchen Zeng64c0e8d2016-06-10 11:19:51 -0700239 gpr_log(GPR_DEBUG, "WARNING: %" PRIuPTR " metadata elements were leaked",
yang-gd88e1d82015-12-02 13:23:33 -0800240 shard->count);
Craig Tiller0cb803d2016-03-02 22:17:24 -0800241 if (grpc_iomgr_abort_on_leaks()) {
242 abort();
243 }
Craig Tiller34075442015-11-23 16:16:54 -0800244 }
Craig Tillerb2b42612015-11-20 12:02:17 -0800245 gpr_free(shard->elems);
246 }
247 for (i = 0; i < STRTAB_SHARD_COUNT; i++) {
248 strtab_shard *shard = &g_strtab_shard[i];
249 gpr_mu_destroy(&shard->mu);
Craig Tiller34075442015-11-23 16:16:54 -0800250 /* TODO(ctiller): GPR_ASSERT(shard->count == 0); */
251 if (shard->count != 0) {
Yuchen Zeng64c0e8d2016-06-10 11:19:51 -0700252 gpr_log(GPR_DEBUG, "WARNING: %" PRIuPTR " metadata strings were leaked",
yang-gd88e1d82015-12-02 13:23:33 -0800253 shard->count);
Craig Tiller36930782016-04-04 20:57:53 -0700254 for (size_t j = 0; j < shard->capacity; j++) {
255 for (internal_string *s = shard->strs[j]; s; s = s->bucket_next) {
Craig Tiller7bfd8be2016-04-04 22:10:25 -0700256 gpr_log(GPR_DEBUG, "LEAKED: %s",
257 grpc_mdstr_as_c_string((grpc_mdstr *)s));
Craig Tiller36930782016-04-04 20:57:53 -0700258 }
259 }
Craig Tiller0cb803d2016-03-02 22:17:24 -0800260 if (grpc_iomgr_abort_on_leaks()) {
261 abort();
262 }
Craig Tiller34075442015-11-23 16:16:54 -0800263 }
Craig Tillerb2b42612015-11-20 12:02:17 -0800264 gpr_free(shard->strs);
265 }
266}
Craig Tiller0e72ede2015-11-19 07:48:53 -0800267
268static int is_mdstr_static(grpc_mdstr *s) {
Craig Tillerb774be42015-11-19 07:56:13 -0800269 return s >= &grpc_static_mdstr_table[0] &&
270 s < &grpc_static_mdstr_table[GRPC_STATIC_MDSTR_COUNT];
Craig Tiller0e72ede2015-11-19 07:48:53 -0800271}
272
273static int is_mdelem_static(grpc_mdelem *e) {
Craig Tillerb774be42015-11-19 07:56:13 -0800274 return e >= &grpc_static_mdelem_table[0] &&
275 e < &grpc_static_mdelem_table[GRPC_STATIC_MDELEM_COUNT];
Craig Tiller0e72ede2015-11-19 07:48:53 -0800276}
277
Craig Tillerb2b42612015-11-20 12:02:17 -0800278static void ref_md_locked(mdtab_shard *shard,
279 internal_metadata *md DEBUG_ARGS) {
Craig Tiller1a65a232015-07-06 10:22:32 -0700280#ifdef GRPC_METADATA_REFCOUNT_DEBUG
281 gpr_log(file, line, GPR_LOG_SEVERITY_DEBUG,
David Garcia Quintas331b9c02016-09-12 18:37:05 -0700282 "ELM REF:%p:%zu->%zu: '%s' = '%s'", (void *)md,
Craig Tiller1a65a232015-07-06 10:22:32 -0700283 gpr_atm_no_barrier_load(&md->refcnt),
284 gpr_atm_no_barrier_load(&md->refcnt) + 1,
285 grpc_mdstr_as_c_string((grpc_mdstr *)md->key),
286 grpc_mdstr_as_c_string((grpc_mdstr *)md->value));
287#endif
Craig Tiller8d8f9a82016-06-03 08:49:11 -0700288 if (0 == gpr_atm_no_barrier_fetch_add(&md->refcnt, 1)) {
289 gpr_atm_no_barrier_fetch_add(&shard->free_estimate, -1);
Nicolas Nobleb7ebd3b2014-11-26 16:33:03 -0800290 }
291}
292
Craig Tillerb2b42612015-11-20 12:02:17 -0800293static void grow_strtab(strtab_shard *shard) {
294 size_t capacity = shard->capacity * 2;
Nicolas Nobleb7ebd3b2014-11-26 16:33:03 -0800295 size_t i;
Craig Tiller9d35a1f2015-11-02 14:16:12 -0800296 internal_string **strtab;
Nicolas Nobleb7ebd3b2014-11-26 16:33:03 -0800297 internal_string *s, *next;
Craig Tiller9d35a1f2015-11-02 14:16:12 -0800298
299 GPR_TIMER_BEGIN("grow_strtab", 0);
300
301 strtab = gpr_malloc(sizeof(internal_string *) * capacity);
Nicolas Nobleb7ebd3b2014-11-26 16:33:03 -0800302 memset(strtab, 0, sizeof(internal_string *) * capacity);
303
Craig Tillerb2b42612015-11-20 12:02:17 -0800304 for (i = 0; i < shard->capacity; i++) {
305 for (s = shard->strs[i]; s; s = next) {
306 size_t idx = TABLE_IDX(s->hash, LOG2_STRTAB_SHARD_COUNT, capacity);
Nicolas Nobleb7ebd3b2014-11-26 16:33:03 -0800307 next = s->bucket_next;
Craig Tillerb2b42612015-11-20 12:02:17 -0800308 s->bucket_next = strtab[idx];
309 strtab[idx] = s;
Nicolas Nobleb7ebd3b2014-11-26 16:33:03 -0800310 }
311 }
312
Craig Tillerb2b42612015-11-20 12:02:17 -0800313 gpr_free(shard->strs);
314 shard->strs = strtab;
315 shard->capacity = capacity;
Craig Tiller9d35a1f2015-11-02 14:16:12 -0800316
317 GPR_TIMER_END("grow_strtab", 0);
Nicolas Nobleb7ebd3b2014-11-26 16:33:03 -0800318}
319
Craig Tillera59c16c2016-10-31 07:25:01 -0700320static void internal_destroy_string(grpc_exec_ctx *exec_ctx,
321 strtab_shard *shard, internal_string *is) {
Nicolas Nobleb7ebd3b2014-11-26 16:33:03 -0800322 internal_string **prev_next;
323 internal_string *cur;
Craig Tiller9d35a1f2015-11-02 14:16:12 -0800324 GPR_TIMER_BEGIN("internal_destroy_string", 0);
ctiller430c4992014-12-11 09:15:41 -0800325 if (is->has_base64_and_huffman_encoded) {
Craig Tillera59c16c2016-10-31 07:25:01 -0700326 grpc_slice_unref_internal(exec_ctx, is->base64_and_huffman);
ctiller430c4992014-12-11 09:15:41 -0800327 }
Craig Tillerb2b42612015-11-20 12:02:17 -0800328 for (prev_next = &shard->strs[TABLE_IDX(is->hash, LOG2_STRTAB_SHARD_COUNT,
329 shard->capacity)],
Nicolas Nobleb7ebd3b2014-11-26 16:33:03 -0800330 cur = *prev_next;
331 cur != is; prev_next = &cur->bucket_next, cur = cur->bucket_next)
332 ;
333 *prev_next = cur->bucket_next;
Craig Tillerb2b42612015-11-20 12:02:17 -0800334 shard->count--;
Nicolas Nobleb7ebd3b2014-11-26 16:33:03 -0800335 gpr_free(is);
Craig Tiller9d35a1f2015-11-02 14:16:12 -0800336 GPR_TIMER_END("internal_destroy_string", 0);
Nicolas Nobleb7ebd3b2014-11-26 16:33:03 -0800337}
338
Nicolas Nobleb7ebd3b2014-11-26 16:33:03 -0800339static void slice_ref(void *p) {
340 internal_string *is =
341 (internal_string *)((char *)p - offsetof(internal_string, refcount));
Craig Tillerb2b42612015-11-20 12:02:17 -0800342 GRPC_MDSTR_REF((grpc_mdstr *)(is));
Nicolas Nobleb7ebd3b2014-11-26 16:33:03 -0800343}
344
Craig Tillera59c16c2016-10-31 07:25:01 -0700345static void slice_unref(grpc_exec_ctx *exec_ctx, void *p) {
Nicolas Nobleb7ebd3b2014-11-26 16:33:03 -0800346 internal_string *is =
347 (internal_string *)((char *)p - offsetof(internal_string, refcount));
Craig Tillera59c16c2016-10-31 07:25:01 -0700348 GRPC_MDSTR_UNREF(exec_ctx, (grpc_mdstr *)(is));
Nicolas Nobleb7ebd3b2014-11-26 16:33:03 -0800349}
350
Craig Tillerb2b42612015-11-20 12:02:17 -0800351grpc_mdstr *grpc_mdstr_from_string(const char *str) {
Craig Tiller7536af02015-12-22 13:49:30 -0800352 return grpc_mdstr_from_buffer((const uint8_t *)str, strlen(str));
Nicolas Nobleb7ebd3b2014-11-26 16:33:03 -0800353}
354
Craig Tillera59c16c2016-10-31 07:25:01 -0700355grpc_mdstr *grpc_mdstr_from_slice(grpc_exec_ctx *exec_ctx, grpc_slice slice) {
Craig Tiller618e67d2016-10-26 21:08:10 -0700356 grpc_mdstr *result = grpc_mdstr_from_buffer(GRPC_SLICE_START_PTR(slice),
357 GRPC_SLICE_LENGTH(slice));
Craig Tillera59c16c2016-10-31 07:25:01 -0700358 grpc_slice_unref_internal(exec_ctx, slice);
Nicolas Nobleb7ebd3b2014-11-26 16:33:03 -0800359 return result;
360}
361
Craig Tiller7536af02015-12-22 13:49:30 -0800362grpc_mdstr *grpc_mdstr_from_buffer(const uint8_t *buf, size_t length) {
363 uint32_t hash = gpr_murmur_hash3(buf, length, g_hash_seed);
Nicolas Nobleb7ebd3b2014-11-26 16:33:03 -0800364 internal_string *s;
Craig Tillerb2b42612015-11-20 12:02:17 -0800365 strtab_shard *shard =
366 &g_strtab_shard[SHARD_IDX(hash, LOG2_STRTAB_SHARD_COUNT)];
Craig Tiller0e72ede2015-11-19 07:48:53 -0800367 size_t i;
Craig Tillerb2b42612015-11-20 12:02:17 -0800368 size_t idx;
Nicolas Nobleb7ebd3b2014-11-26 16:33:03 -0800369
Craig Tiller9d35a1f2015-11-02 14:16:12 -0800370 GPR_TIMER_BEGIN("grpc_mdstr_from_buffer", 0);
Craig Tiller0e72ede2015-11-19 07:48:53 -0800371
372 /* search for a static string */
Craig Tillerb2b42612015-11-20 12:02:17 -0800373 for (i = 0; i <= g_static_strtab_maxprobe; i++) {
374 grpc_mdstr *ss;
375 idx = (hash + i) % GPR_ARRAY_SIZE(g_static_strtab);
376 ss = g_static_strtab[idx];
377 if (ss == NULL) break;
Craig Tiller618e67d2016-10-26 21:08:10 -0700378 if (ss->hash == hash && GRPC_SLICE_LENGTH(ss->slice) == length &&
Craig Tiller93dd0472016-05-18 15:06:37 -0700379 (length == 0 ||
Craig Tiller618e67d2016-10-26 21:08:10 -0700380 0 == memcmp(buf, GRPC_SLICE_START_PTR(ss->slice), length))) {
Craig Tiller07718b82015-11-21 14:06:45 -0800381 GPR_TIMER_END("grpc_mdstr_from_buffer", 0);
Craig Tillerb2b42612015-11-20 12:02:17 -0800382 return ss;
Craig Tiller0e72ede2015-11-19 07:48:53 -0800383 }
384 }
385
Craig Tillerb2b42612015-11-20 12:02:17 -0800386 gpr_mu_lock(&shard->mu);
Nicolas Nobleb7ebd3b2014-11-26 16:33:03 -0800387
388 /* search for an existing string */
Craig Tillerb2b42612015-11-20 12:02:17 -0800389 idx = TABLE_IDX(hash, LOG2_STRTAB_SHARD_COUNT, shard->capacity);
390 for (s = shard->strs[idx]; s; s = s->bucket_next) {
Craig Tiller618e67d2016-10-26 21:08:10 -0700391 if (s->hash == hash && GRPC_SLICE_LENGTH(s->slice) == length &&
392 0 == memcmp(buf, GRPC_SLICE_START_PTR(s->slice), length)) {
Craig Tiller773d9902016-04-26 18:27:31 -0700393 if (gpr_atm_full_fetch_add(&s->refcnt, 1) == 0) {
394 /* If we get here, we've added a ref to something that was about to
395 * die - drop it immediately.
396 * The *only* possible path here (given the shard mutex) should be to
397 * drop from one ref back to zero - assert that with a CAS */
398 GPR_ASSERT(gpr_atm_rel_cas(&s->refcnt, 1, 0));
399 /* and treat this as if we were never here... sshhh */
400 } else {
401 gpr_mu_unlock(&shard->mu);
402 GPR_TIMER_END("grpc_mdstr_from_buffer", 0);
403 return (grpc_mdstr *)s;
404 }
Nicolas Nobleb7ebd3b2014-11-26 16:33:03 -0800405 }
406 }
407
408 /* not found: create a new string */
Craig Tiller618e67d2016-10-26 21:08:10 -0700409 if (length + 1 < GRPC_SLICE_INLINED_SIZE) {
Nicolas Nobleb7ebd3b2014-11-26 16:33:03 -0800410 /* string data goes directly into the slice */
411 s = gpr_malloc(sizeof(internal_string));
Craig Tiller773d9902016-04-26 18:27:31 -0700412 gpr_atm_rel_store(&s->refcnt, 1);
Nicolas Nobleb7ebd3b2014-11-26 16:33:03 -0800413 s->slice.refcount = NULL;
414 memcpy(s->slice.data.inlined.bytes, buf, length);
415 s->slice.data.inlined.bytes[length] = 0;
Craig Tiller7536af02015-12-22 13:49:30 -0800416 s->slice.data.inlined.length = (uint8_t)length;
Nicolas Nobleb7ebd3b2014-11-26 16:33:03 -0800417 } else {
418 /* string data goes after the internal_string header, and we +1 for null
419 terminator */
420 s = gpr_malloc(sizeof(internal_string) + length + 1);
Craig Tiller773d9902016-04-26 18:27:31 -0700421 gpr_atm_rel_store(&s->refcnt, 1);
Nicolas Nobleb7ebd3b2014-11-26 16:33:03 -0800422 s->refcount.ref = slice_ref;
423 s->refcount.unref = slice_unref;
424 s->slice.refcount = &s->refcount;
Craig Tiller7536af02015-12-22 13:49:30 -0800425 s->slice.data.refcounted.bytes = (uint8_t *)(s + 1);
Nicolas Nobleb7ebd3b2014-11-26 16:33:03 -0800426 s->slice.data.refcounted.length = length;
427 memcpy(s->slice.data.refcounted.bytes, buf, length);
428 /* add a null terminator for cheap c string conversion when desired */
429 s->slice.data.refcounted.bytes[length] = 0;
430 }
ctiller430c4992014-12-11 09:15:41 -0800431 s->has_base64_and_huffman_encoded = 0;
Nicolas Nobleb7ebd3b2014-11-26 16:33:03 -0800432 s->hash = hash;
yang-g4a530b02016-03-31 11:44:44 -0700433 s->size_in_decoder_table = SIZE_IN_DECODER_TABLE_NOT_SET;
Craig Tillerb2b42612015-11-20 12:02:17 -0800434 s->bucket_next = shard->strs[idx];
435 shard->strs[idx] = s;
Nicolas Nobleb7ebd3b2014-11-26 16:33:03 -0800436
Craig Tillerb2b42612015-11-20 12:02:17 -0800437 shard->count++;
Nicolas Nobleb7ebd3b2014-11-26 16:33:03 -0800438
Craig Tillerb2b42612015-11-20 12:02:17 -0800439 if (shard->count > shard->capacity * 2) {
440 grow_strtab(shard);
Nicolas Nobleb7ebd3b2014-11-26 16:33:03 -0800441 }
442
Craig Tillerb2b42612015-11-20 12:02:17 -0800443 gpr_mu_unlock(&shard->mu);
Craig Tiller9d35a1f2015-11-02 14:16:12 -0800444 GPR_TIMER_END("grpc_mdstr_from_buffer", 0);
Nicolas Nobleb7ebd3b2014-11-26 16:33:03 -0800445
446 return (grpc_mdstr *)s;
447}
448
Craig Tillera59c16c2016-10-31 07:25:01 -0700449static void gc_mdtab(grpc_exec_ctx *exec_ctx, mdtab_shard *shard) {
Nicolas Nobleb7ebd3b2014-11-26 16:33:03 -0800450 size_t i;
451 internal_metadata **prev_next;
452 internal_metadata *md, *next;
Craig Tiller8d8f9a82016-06-03 08:49:11 -0700453 gpr_atm num_freed = 0;
Nicolas Nobleb7ebd3b2014-11-26 16:33:03 -0800454
Craig Tiller9d35a1f2015-11-02 14:16:12 -0800455 GPR_TIMER_BEGIN("gc_mdtab", 0);
Craig Tillerb2b42612015-11-20 12:02:17 -0800456 for (i = 0; i < shard->capacity; i++) {
457 prev_next = &shard->elems[i];
458 for (md = shard->elems[i]; md; md = next) {
Craig Tiller8344daa2015-10-09 18:10:57 -0700459 void *user_data = (void *)gpr_atm_no_barrier_load(&md->user_data);
Nicolas Nobleb7ebd3b2014-11-26 16:33:03 -0800460 next = md->bucket_next;
Craig Tiller9fa41b92015-04-10 15:08:03 -0700461 if (gpr_atm_acq_load(&md->refcnt) == 0) {
Craig Tillera59c16c2016-10-31 07:25:01 -0700462 GRPC_MDSTR_UNREF(exec_ctx, (grpc_mdstr *)md->key);
463 GRPC_MDSTR_UNREF(exec_ctx, (grpc_mdstr *)md->value);
Nicolas Nobleb7ebd3b2014-11-26 16:33:03 -0800464 if (md->user_data) {
Craig Tiller8344daa2015-10-09 18:10:57 -0700465 ((destroy_user_data_func)gpr_atm_no_barrier_load(
466 &md->destroy_user_data))(user_data);
Nicolas Nobleb7ebd3b2014-11-26 16:33:03 -0800467 }
468 gpr_free(md);
469 *prev_next = next;
Craig Tiller8d8f9a82016-06-03 08:49:11 -0700470 num_freed++;
Craig Tillerb2b42612015-11-20 12:02:17 -0800471 shard->count--;
Nicolas Nobleb7ebd3b2014-11-26 16:33:03 -0800472 } else {
473 prev_next = &md->bucket_next;
474 }
475 }
476 }
Craig Tiller8d8f9a82016-06-03 08:49:11 -0700477 gpr_atm_no_barrier_fetch_add(&shard->free_estimate, -num_freed);
Craig Tiller9d35a1f2015-11-02 14:16:12 -0800478 GPR_TIMER_END("gc_mdtab", 0);
Nicolas Nobleb7ebd3b2014-11-26 16:33:03 -0800479}
480
Craig Tillerb2b42612015-11-20 12:02:17 -0800481static void grow_mdtab(mdtab_shard *shard) {
482 size_t capacity = shard->capacity * 2;
Nicolas Nobleb7ebd3b2014-11-26 16:33:03 -0800483 size_t i;
Craig Tiller9d35a1f2015-11-02 14:16:12 -0800484 internal_metadata **mdtab;
Nicolas Nobleb7ebd3b2014-11-26 16:33:03 -0800485 internal_metadata *md, *next;
Craig Tiller7536af02015-12-22 13:49:30 -0800486 uint32_t hash;
Craig Tiller9d35a1f2015-11-02 14:16:12 -0800487
488 GPR_TIMER_BEGIN("grow_mdtab", 0);
489
490 mdtab = gpr_malloc(sizeof(internal_metadata *) * capacity);
Nicolas Nobleb7ebd3b2014-11-26 16:33:03 -0800491 memset(mdtab, 0, sizeof(internal_metadata *) * capacity);
492
Craig Tillerb2b42612015-11-20 12:02:17 -0800493 for (i = 0; i < shard->capacity; i++) {
494 for (md = shard->elems[i]; md; md = next) {
495 size_t idx;
ctillerfb93d192014-12-15 10:40:05 -0800496 hash = GRPC_MDSTR_KV_HASH(md->key->hash, md->value->hash);
Nicolas Nobleb7ebd3b2014-11-26 16:33:03 -0800497 next = md->bucket_next;
Craig Tillerb2b42612015-11-20 12:02:17 -0800498 idx = TABLE_IDX(hash, LOG2_MDTAB_SHARD_COUNT, capacity);
499 md->bucket_next = mdtab[idx];
500 mdtab[idx] = md;
Nicolas Nobleb7ebd3b2014-11-26 16:33:03 -0800501 }
502 }
503
Craig Tillerb2b42612015-11-20 12:02:17 -0800504 gpr_free(shard->elems);
505 shard->elems = mdtab;
506 shard->capacity = capacity;
Craig Tiller9d35a1f2015-11-02 14:16:12 -0800507
508 GPR_TIMER_END("grow_mdtab", 0);
Nicolas Nobleb7ebd3b2014-11-26 16:33:03 -0800509}
510
Craig Tillera59c16c2016-10-31 07:25:01 -0700511static void rehash_mdtab(grpc_exec_ctx *exec_ctx, mdtab_shard *shard) {
Craig Tiller139098c2016-06-06 08:10:08 -0700512 if (gpr_atm_no_barrier_load(&shard->free_estimate) >
513 (gpr_atm)(shard->capacity / 4)) {
Craig Tillera59c16c2016-10-31 07:25:01 -0700514 gc_mdtab(exec_ctx, shard);
Nicolas Nobleb7ebd3b2014-11-26 16:33:03 -0800515 } else {
Craig Tillerb2b42612015-11-20 12:02:17 -0800516 grow_mdtab(shard);
Nicolas Nobleb7ebd3b2014-11-26 16:33:03 -0800517 }
518}
519
Craig Tillera59c16c2016-10-31 07:25:01 -0700520grpc_mdelem *grpc_mdelem_from_metadata_strings(grpc_exec_ctx *exec_ctx,
521 grpc_mdstr *mkey,
Nicolas Nobleb7ebd3b2014-11-26 16:33:03 -0800522 grpc_mdstr *mvalue) {
523 internal_string *key = (internal_string *)mkey;
524 internal_string *value = (internal_string *)mvalue;
Craig Tiller7536af02015-12-22 13:49:30 -0800525 uint32_t hash = GRPC_MDSTR_KV_HASH(mkey->hash, mvalue->hash);
Nicolas Nobleb7ebd3b2014-11-26 16:33:03 -0800526 internal_metadata *md;
Craig Tillerb2b42612015-11-20 12:02:17 -0800527 mdtab_shard *shard = &g_mdtab_shard[SHARD_IDX(hash, LOG2_MDTAB_SHARD_COUNT)];
Craig Tiller0e72ede2015-11-19 07:48:53 -0800528 size_t i;
Craig Tillerb2b42612015-11-20 12:02:17 -0800529 size_t idx;
Nicolas Nobleb7ebd3b2014-11-26 16:33:03 -0800530
Craig Tiller9d35a1f2015-11-02 14:16:12 -0800531 GPR_TIMER_BEGIN("grpc_mdelem_from_metadata_strings", 0);
532
Craig Tiller0e72ede2015-11-19 07:48:53 -0800533 if (is_mdstr_static(mkey) && is_mdstr_static(mvalue)) {
Craig Tillerb2b42612015-11-20 12:02:17 -0800534 for (i = 0; i <= g_static_mdtab_maxprobe; i++) {
535 grpc_mdelem *smd;
536 idx = (hash + i) % GPR_ARRAY_SIZE(g_static_mdtab);
537 smd = g_static_mdtab[idx];
538 if (smd == NULL) break;
539 if (smd->key == mkey && smd->value == mvalue) {
Craig Tiller07718b82015-11-21 14:06:45 -0800540 GPR_TIMER_END("grpc_mdelem_from_metadata_strings", 0);
Craig Tillerb2b42612015-11-20 12:02:17 -0800541 return smd;
Craig Tiller0e72ede2015-11-19 07:48:53 -0800542 }
543 }
544 }
545
Craig Tillerb2b42612015-11-20 12:02:17 -0800546 gpr_mu_lock(&shard->mu);
Nicolas Nobleb7ebd3b2014-11-26 16:33:03 -0800547
Craig Tillerb2b42612015-11-20 12:02:17 -0800548 idx = TABLE_IDX(hash, LOG2_MDTAB_SHARD_COUNT, shard->capacity);
Nicolas Nobleb7ebd3b2014-11-26 16:33:03 -0800549 /* search for an existing pair */
Craig Tillerb2b42612015-11-20 12:02:17 -0800550 for (md = shard->elems[idx]; md; md = md->bucket_next) {
Nicolas Nobleb7ebd3b2014-11-26 16:33:03 -0800551 if (md->key == key && md->value == value) {
Craig Tillerb2b42612015-11-20 12:02:17 -0800552 REF_MD_LOCKED(shard, md);
Craig Tillera59c16c2016-10-31 07:25:01 -0700553 GRPC_MDSTR_UNREF(exec_ctx, (grpc_mdstr *)key);
554 GRPC_MDSTR_UNREF(exec_ctx, (grpc_mdstr *)value);
Craig Tillerb2b42612015-11-20 12:02:17 -0800555 gpr_mu_unlock(&shard->mu);
Craig Tiller9d35a1f2015-11-02 14:16:12 -0800556 GPR_TIMER_END("grpc_mdelem_from_metadata_strings", 0);
Nicolas Nobleb7ebd3b2014-11-26 16:33:03 -0800557 return (grpc_mdelem *)md;
558 }
559 }
560
561 /* not found: create a new pair */
562 md = gpr_malloc(sizeof(internal_metadata));
Craig Tiller8d8f9a82016-06-03 08:49:11 -0700563 gpr_atm_rel_store(&md->refcnt, 1);
Nicolas Nobleb7ebd3b2014-11-26 16:33:03 -0800564 md->key = key;
565 md->value = value;
Craig Tiller8344daa2015-10-09 18:10:57 -0700566 md->user_data = 0;
567 md->destroy_user_data = 0;
Craig Tillerb2b42612015-11-20 12:02:17 -0800568 md->bucket_next = shard->elems[idx];
569 shard->elems[idx] = md;
Craig Tiller83901532015-07-10 14:02:45 -0700570 gpr_mu_init(&md->mu_user_data);
Craig Tiller1a65a232015-07-06 10:22:32 -0700571#ifdef GRPC_METADATA_REFCOUNT_DEBUG
David Garcia Quintas331b9c02016-09-12 18:37:05 -0700572 gpr_log(GPR_DEBUG, "ELM NEW:%p:%zu: '%s' = '%s'", (void *)md,
Craig Tiller1a65a232015-07-06 10:22:32 -0700573 gpr_atm_no_barrier_load(&md->refcnt),
574 grpc_mdstr_as_c_string((grpc_mdstr *)md->key),
575 grpc_mdstr_as_c_string((grpc_mdstr *)md->value));
576#endif
Craig Tillerb2b42612015-11-20 12:02:17 -0800577 shard->count++;
Nicolas Nobleb7ebd3b2014-11-26 16:33:03 -0800578
Craig Tillerb2b42612015-11-20 12:02:17 -0800579 if (shard->count > shard->capacity * 2) {
Craig Tillera59c16c2016-10-31 07:25:01 -0700580 rehash_mdtab(exec_ctx, shard);
Nicolas Nobleb7ebd3b2014-11-26 16:33:03 -0800581 }
582
Craig Tillerb2b42612015-11-20 12:02:17 -0800583 gpr_mu_unlock(&shard->mu);
Nicolas Nobleb7ebd3b2014-11-26 16:33:03 -0800584
Craig Tiller9d35a1f2015-11-02 14:16:12 -0800585 GPR_TIMER_END("grpc_mdelem_from_metadata_strings", 0);
586
Nicolas Nobleb7ebd3b2014-11-26 16:33:03 -0800587 return (grpc_mdelem *)md;
588}
589
Craig Tillera59c16c2016-10-31 07:25:01 -0700590grpc_mdelem *grpc_mdelem_from_strings(grpc_exec_ctx *exec_ctx, const char *key,
591 const char *value) {
592 return grpc_mdelem_from_metadata_strings(
593 exec_ctx, grpc_mdstr_from_string(key), grpc_mdstr_from_string(value));
Nicolas Nobleb7ebd3b2014-11-26 16:33:03 -0800594}
595
Craig Tillera59c16c2016-10-31 07:25:01 -0700596grpc_mdelem *grpc_mdelem_from_slices(grpc_exec_ctx *exec_ctx, grpc_slice key,
597 grpc_slice value) {
598 return grpc_mdelem_from_metadata_strings(
599 exec_ctx, grpc_mdstr_from_slice(exec_ctx, key),
600 grpc_mdstr_from_slice(exec_ctx, value));
Nicolas Nobleb7ebd3b2014-11-26 16:33:03 -0800601}
602
Craig Tillera59c16c2016-10-31 07:25:01 -0700603grpc_mdelem *grpc_mdelem_from_string_and_buffer(grpc_exec_ctx *exec_ctx,
604 const char *key,
Craig Tiller7536af02015-12-22 13:49:30 -0800605 const uint8_t *value,
Craig Tiller4dbdd6a2015-09-25 15:12:16 -0700606 size_t value_length) {
Nicolas Nobleb7ebd3b2014-11-26 16:33:03 -0800607 return grpc_mdelem_from_metadata_strings(
Craig Tillera59c16c2016-10-31 07:25:01 -0700608 exec_ctx, grpc_mdstr_from_string(key),
609 grpc_mdstr_from_buffer(value, value_length));
Nicolas Nobleb7ebd3b2014-11-26 16:33:03 -0800610}
611
yang-g24ba7c12016-03-30 16:19:43 -0700612static size_t get_base64_encoded_size(size_t raw_length) {
613 static const uint8_t tail_xtra[3] = {0, 2, 3};
614 return raw_length / 3 * 4 + tail_xtra[raw_length % 3];
615}
616
yang-gcb7a8022016-03-30 14:58:53 -0700617size_t grpc_mdelem_get_size_in_hpack_table(grpc_mdelem *elem) {
Craig Tiller618e67d2016-10-26 21:08:10 -0700618 size_t overhead_and_key = 32 + GRPC_SLICE_LENGTH(elem->key->slice);
619 size_t value_len = GRPC_SLICE_LENGTH(elem->value->slice);
yang-gcb7a8022016-03-30 14:58:53 -0700620 if (is_mdstr_static(elem->value)) {
yang-g24ba7c12016-03-30 16:19:43 -0700621 if (grpc_is_binary_header(
Craig Tiller618e67d2016-10-26 21:08:10 -0700622 (const char *)GRPC_SLICE_START_PTR(elem->key->slice),
623 GRPC_SLICE_LENGTH(elem->key->slice))) {
yang-g24ba7c12016-03-30 16:19:43 -0700624 return overhead_and_key + get_base64_encoded_size(value_len);
625 } else {
626 return overhead_and_key + value_len;
627 }
yang-gcb7a8022016-03-30 14:58:53 -0700628 } else {
629 internal_string *is = (internal_string *)elem->value;
yang-g9cedd3f2016-04-01 00:24:59 -0700630 gpr_atm current_size = gpr_atm_acq_load(&is->size_in_decoder_table);
yang-g4a530b02016-03-31 11:44:44 -0700631 if (current_size == SIZE_IN_DECODER_TABLE_NOT_SET) {
yang-gcb7a8022016-03-30 14:58:53 -0700632 if (grpc_is_binary_header(
Craig Tiller618e67d2016-10-26 21:08:10 -0700633 (const char *)GRPC_SLICE_START_PTR(elem->key->slice),
634 GRPC_SLICE_LENGTH(elem->key->slice))) {
yang-g4a530b02016-03-31 11:44:44 -0700635 current_size = (gpr_atm)get_base64_encoded_size(value_len);
yang-gcb7a8022016-03-30 14:58:53 -0700636 } else {
yang-g4a530b02016-03-31 11:44:44 -0700637 current_size = (gpr_atm)value_len;
yang-gcb7a8022016-03-30 14:58:53 -0700638 }
yang-g9cedd3f2016-04-01 00:24:59 -0700639 gpr_atm_rel_store(&is->size_in_decoder_table, current_size);
yang-gcb7a8022016-03-30 14:58:53 -0700640 }
yang-g4a530b02016-03-31 11:44:44 -0700641 return overhead_and_key + (size_t)current_size;
yang-gcb7a8022016-03-30 14:58:53 -0700642 }
643}
644
Craig Tiller1a65a232015-07-06 10:22:32 -0700645grpc_mdelem *grpc_mdelem_ref(grpc_mdelem *gmd DEBUG_ARGS) {
Nicolas Nobleb7ebd3b2014-11-26 16:33:03 -0800646 internal_metadata *md = (internal_metadata *)gmd;
Craig Tiller0e72ede2015-11-19 07:48:53 -0800647 if (is_mdelem_static(gmd)) return gmd;
Craig Tiller1a65a232015-07-06 10:22:32 -0700648#ifdef GRPC_METADATA_REFCOUNT_DEBUG
649 gpr_log(file, line, GPR_LOG_SEVERITY_DEBUG,
David Garcia Quintas331b9c02016-09-12 18:37:05 -0700650 "ELM REF:%p:%zu->%zu: '%s' = '%s'", (void *)md,
Craig Tiller1a65a232015-07-06 10:22:32 -0700651 gpr_atm_no_barrier_load(&md->refcnt),
652 gpr_atm_no_barrier_load(&md->refcnt) + 1,
653 grpc_mdstr_as_c_string((grpc_mdstr *)md->key),
654 grpc_mdstr_as_c_string((grpc_mdstr *)md->value));
655#endif
Craig Tiller9fa41b92015-04-10 15:08:03 -0700656 /* we can assume the ref count is >= 1 as the application is calling
657 this function - meaning that no adjustment to mdtab_free is necessary,
658 simplifying the logic here to be just an atomic increment */
659 /* use C assert to have this removed in opt builds */
David Garcia Quintas331b9c02016-09-12 18:37:05 -0700660 GPR_ASSERT(gpr_atm_no_barrier_load(&md->refcnt) >= 1);
Craig Tiller9fa41b92015-04-10 15:08:03 -0700661 gpr_atm_no_barrier_fetch_add(&md->refcnt, 1);
Nicolas Nobleb7ebd3b2014-11-26 16:33:03 -0800662 return gmd;
663}
664
Craig Tillera59c16c2016-10-31 07:25:01 -0700665void grpc_mdelem_unref(grpc_exec_ctx *exec_ctx, grpc_mdelem *gmd DEBUG_ARGS) {
Nicolas Nobleb7ebd3b2014-11-26 16:33:03 -0800666 internal_metadata *md = (internal_metadata *)gmd;
Craig Tiller9d35a1f2015-11-02 14:16:12 -0800667 if (!md) return;
Craig Tiller0e72ede2015-11-19 07:48:53 -0800668 if (is_mdelem_static(gmd)) return;
Craig Tiller1a65a232015-07-06 10:22:32 -0700669#ifdef GRPC_METADATA_REFCOUNT_DEBUG
670 gpr_log(file, line, GPR_LOG_SEVERITY_DEBUG,
David Garcia Quintas331b9c02016-09-12 18:37:05 -0700671 "ELM UNREF:%p:%zu->%zu: '%s' = '%s'", (void *)md,
Craig Tiller1a65a232015-07-06 10:22:32 -0700672 gpr_atm_no_barrier_load(&md->refcnt),
673 gpr_atm_no_barrier_load(&md->refcnt) - 1,
674 grpc_mdstr_as_c_string((grpc_mdstr *)md->key),
675 grpc_mdstr_as_c_string((grpc_mdstr *)md->value));
676#endif
Craig Tiller8d8f9a82016-06-03 08:49:11 -0700677 uint32_t hash = GRPC_MDSTR_KV_HASH(md->key->hash, md->value->hash);
David Garcia Quintas331b9c02016-09-12 18:37:05 -0700678 const gpr_atm prev_refcount = gpr_atm_full_fetch_add(&md->refcnt, -1);
679 GPR_ASSERT(prev_refcount >= 1);
680 if (1 == prev_refcount) {
Craig Tiller8d8f9a82016-06-03 08:49:11 -0700681 /* once the refcount hits zero, some other thread can come along and
682 free md at any time: it's unsafe from this point on to access it */
Craig Tillerb2b42612015-11-20 12:02:17 -0800683 mdtab_shard *shard =
684 &g_mdtab_shard[SHARD_IDX(hash, LOG2_MDTAB_SHARD_COUNT)];
Craig Tiller8d8f9a82016-06-03 08:49:11 -0700685 gpr_atm_no_barrier_fetch_add(&shard->free_estimate, 1);
Nicolas Nobleb7ebd3b2014-11-26 16:33:03 -0800686 }
Nicolas Nobleb7ebd3b2014-11-26 16:33:03 -0800687}
688
David Garcia Quintas331b9c02016-09-12 18:37:05 -0700689const char *grpc_mdstr_as_c_string(const grpc_mdstr *s) {
Craig Tiller618e67d2016-10-26 21:08:10 -0700690 return (const char *)GRPC_SLICE_START_PTR(s->slice);
Nicolas Nobleb7ebd3b2014-11-26 16:33:03 -0800691}
692
David Garcia Quintas331b9c02016-09-12 18:37:05 -0700693size_t grpc_mdstr_length(const grpc_mdstr *s) { return GRPC_MDSTR_LENGTH(s); }
694
Craig Tiller1a65a232015-07-06 10:22:32 -0700695grpc_mdstr *grpc_mdstr_ref(grpc_mdstr *gs DEBUG_ARGS) {
Nicolas Nobleb7ebd3b2014-11-26 16:33:03 -0800696 internal_string *s = (internal_string *)gs;
Craig Tiller0e72ede2015-11-19 07:48:53 -0800697 if (is_mdstr_static(gs)) return gs;
Craig Tiller773d9902016-04-26 18:27:31 -0700698 GPR_ASSERT(gpr_atm_full_fetch_add(&s->refcnt, 1) > 0);
Nicolas Nobleb7ebd3b2014-11-26 16:33:03 -0800699 return gs;
700}
701
Craig Tillera59c16c2016-10-31 07:25:01 -0700702void grpc_mdstr_unref(grpc_exec_ctx *exec_ctx, grpc_mdstr *gs DEBUG_ARGS) {
Nicolas Nobleb7ebd3b2014-11-26 16:33:03 -0800703 internal_string *s = (internal_string *)gs;
Craig Tiller0e72ede2015-11-19 07:48:53 -0800704 if (is_mdstr_static(gs)) return;
Craig Tiller773d9902016-04-26 18:27:31 -0700705 if (1 == gpr_atm_full_fetch_add(&s->refcnt, -1)) {
Craig Tillerb2b42612015-11-20 12:02:17 -0800706 strtab_shard *shard =
707 &g_strtab_shard[SHARD_IDX(s->hash, LOG2_STRTAB_SHARD_COUNT)];
708 gpr_mu_lock(&shard->mu);
Craig Tiller773d9902016-04-26 18:27:31 -0700709 GPR_ASSERT(0 == gpr_atm_no_barrier_load(&s->refcnt));
Craig Tillera59c16c2016-10-31 07:25:01 -0700710 internal_destroy_string(exec_ctx, shard, s);
Craig Tillerb2b42612015-11-20 12:02:17 -0800711 gpr_mu_unlock(&shard->mu);
712 }
Nicolas Nobleb7ebd3b2014-11-26 16:33:03 -0800713}
714
Craig Tiller8344daa2015-10-09 18:10:57 -0700715void *grpc_mdelem_get_user_data(grpc_mdelem *md, void (*destroy_func)(void *)) {
Nicolas Nobleb7ebd3b2014-11-26 16:33:03 -0800716 internal_metadata *im = (internal_metadata *)md;
Craig Tiller83901532015-07-10 14:02:45 -0700717 void *result;
Craig Tillerb2b42612015-11-20 12:02:17 -0800718 if (is_mdelem_static(md)) {
719 return (void *)grpc_static_mdelem_user_data[md - grpc_static_mdelem_table];
720 }
Craig Tiller8344daa2015-10-09 18:10:57 -0700721 if (gpr_atm_acq_load(&im->destroy_user_data) == (gpr_atm)destroy_func) {
722 return (void *)gpr_atm_no_barrier_load(&im->user_data);
723 } else {
724 return NULL;
725 }
Craig Tiller83901532015-07-10 14:02:45 -0700726 return result;
Nicolas Nobleb7ebd3b2014-11-26 16:33:03 -0800727}
728
729void grpc_mdelem_set_user_data(grpc_mdelem *md, void (*destroy_func)(void *),
730 void *user_data) {
731 internal_metadata *im = (internal_metadata *)md;
Craig Tillerebdef9d2015-11-19 17:09:49 -0800732 GPR_ASSERT(!is_mdelem_static(md));
Nicolas Nobleb7ebd3b2014-11-26 16:33:03 -0800733 GPR_ASSERT((user_data == NULL) == (destroy_func == NULL));
Craig Tiller83901532015-07-10 14:02:45 -0700734 gpr_mu_lock(&im->mu_user_data);
Craig Tiller8344daa2015-10-09 18:10:57 -0700735 if (gpr_atm_no_barrier_load(&im->destroy_user_data)) {
Craig Tiller83901532015-07-10 14:02:45 -0700736 /* user data can only be set once */
737 gpr_mu_unlock(&im->mu_user_data);
738 if (destroy_func != NULL) {
739 destroy_func(user_data);
740 }
741 return;
Nicolas Nobleb7ebd3b2014-11-26 16:33:03 -0800742 }
Craig Tiller8344daa2015-10-09 18:10:57 -0700743 gpr_atm_no_barrier_store(&im->user_data, (gpr_atm)user_data);
744 gpr_atm_rel_store(&im->destroy_user_data, (gpr_atm)destroy_func);
Craig Tiller83901532015-07-10 14:02:45 -0700745 gpr_mu_unlock(&im->mu_user_data);
Nicolas Nobleb7ebd3b2014-11-26 16:33:03 -0800746}
ctiller430c4992014-12-11 09:15:41 -0800747
Craig Tillerd41a4a72016-10-26 16:16:06 -0700748grpc_slice grpc_mdstr_as_base64_encoded_and_huffman_compressed(grpc_mdstr *gs) {
ctiller430c4992014-12-11 09:15:41 -0800749 internal_string *s = (internal_string *)gs;
Craig Tillerd41a4a72016-10-26 16:16:06 -0700750 grpc_slice slice;
Craig Tillerb2b42612015-11-20 12:02:17 -0800751 strtab_shard *shard =
752 &g_strtab_shard[SHARD_IDX(s->hash, LOG2_STRTAB_SHARD_COUNT)];
753 gpr_mu_lock(&shard->mu);
ctiller430c4992014-12-11 09:15:41 -0800754 if (!s->has_base64_and_huffman_encoded) {
755 s->base64_and_huffman =
756 grpc_chttp2_base64_encode_and_huffman_compress(s->slice);
ctiller33023c42014-12-12 16:28:33 -0800757 s->has_base64_and_huffman_encoded = 1;
ctiller430c4992014-12-11 09:15:41 -0800758 }
759 slice = s->base64_and_huffman;
Craig Tillerb2b42612015-11-20 12:02:17 -0800760 gpr_mu_unlock(&shard->mu);
ctiller430c4992014-12-11 09:15:41 -0800761 return slice;
David Garcia Quintas2bf574f2016-01-14 15:27:08 -0800762}