blob: a0c295275f3d70140ac44d9327c2a73059351595 [file] [log] [blame]
Nicolas Nobleb7ebd3b2014-11-26 16:33:03 -08001/*
2 *
murgatroid9940809212016-01-13 17:45:30 -08003 * Copyright 2015-2016, 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 Tilleradcb92d2016-03-28 10:14:05 -070048#include "src/core/ext/transport/chttp2/transport/bin_encoder.h"
Craig Tiller9533d042016-03-25 17:11:06 -070049#include "src/core/lib/iomgr/iomgr_internal.h"
50#include "src/core/lib/profiling/timers.h"
51#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 Tiller70b080d2015-11-19 08:04:48 -080055/* There are two kinds of mdelem and mdstr instances.
56 * Static instances are declared in static_metadata.{h,c} and
57 * are initialized by grpc_mdctx_global_init().
58 * Dynamic instances are stored in hash tables on grpc_mdctx, and are backed
59 * by internal_string and internal_element structures.
60 * Internal helper functions here-in (is_mdstr_static, is_mdelem_static) are
61 * used to determine which kind of element a pointer refers to.
62 */
63
Nicolas Nobleb7ebd3b2014-11-26 16:33:03 -080064#define INITIAL_STRTAB_CAPACITY 4
65#define INITIAL_MDTAB_CAPACITY 4
66
Craig Tiller1a65a232015-07-06 10:22:32 -070067#ifdef GRPC_METADATA_REFCOUNT_DEBUG
68#define DEBUG_ARGS , const char *file, int line
69#define FWD_DEBUG_ARGS , file, line
Craig Tillerb2b42612015-11-20 12:02:17 -080070#define REF_MD_LOCKED(shard, s) ref_md_locked((shard), (s), __FILE__, __LINE__)
Craig Tiller1a65a232015-07-06 10:22:32 -070071#else
72#define DEBUG_ARGS
73#define FWD_DEBUG_ARGS
Craig Tillerb2b42612015-11-20 12:02:17 -080074#define REF_MD_LOCKED(shard, s) ref_md_locked((shard), (s))
Craig Tiller1a65a232015-07-06 10:22:32 -070075#endif
76
Craig Tillerb2b42612015-11-20 12:02:17 -080077#define TABLE_IDX(hash, log2_shards, capacity) \
78 (((hash) >> (log2_shards)) % (capacity))
79#define SHARD_IDX(hash, log2_shards) ((hash) & ((1 << (log2_shards)) - 1))
80
Craig Tiller8344daa2015-10-09 18:10:57 -070081typedef void (*destroy_user_data_func)(void *user_data);
82
Craig Tiller70b080d2015-11-19 08:04:48 -080083/* Shadow structure for grpc_mdstr for non-static values */
Nicolas Nobleb7ebd3b2014-11-26 16:33:03 -080084typedef struct internal_string {
85 /* must be byte compatible with grpc_mdstr */
86 gpr_slice slice;
Craig Tiller7536af02015-12-22 13:49:30 -080087 uint32_t hash;
Nicolas Nobleb7ebd3b2014-11-26 16:33:03 -080088
89 /* private only data */
Craig Tillerb2b42612015-11-20 12:02:17 -080090 gpr_atm refcnt;
91
Craig Tiller7536af02015-12-22 13:49:30 -080092 uint8_t has_base64_and_huffman_encoded;
Nicolas Nobleb7ebd3b2014-11-26 16:33:03 -080093 gpr_slice_refcount refcount;
94
ctiller430c4992014-12-11 09:15:41 -080095 gpr_slice base64_and_huffman;
96
yang-gcb7a8022016-03-30 14:58:53 -070097 uint8_t has_size_in_decoder_table;
98 size_t size_in_decoder_table;
99
Nicolas Nobleb7ebd3b2014-11-26 16:33:03 -0800100 struct internal_string *bucket_next;
101} internal_string;
102
Craig Tiller70b080d2015-11-19 08:04:48 -0800103/* Shadow structure for grpc_mdelem for non-static elements */
Nicolas Nobleb7ebd3b2014-11-26 16:33:03 -0800104typedef struct internal_metadata {
105 /* must be byte compatible with grpc_mdelem */
106 internal_string *key;
107 internal_string *value;
108
Craig Tillerb2b42612015-11-20 12:02:17 -0800109 /* private only data */
Craig Tiller9fa41b92015-04-10 15:08:03 -0700110 gpr_atm refcnt;
111
Craig Tiller83901532015-07-10 14:02:45 -0700112 gpr_mu mu_user_data;
Craig Tiller8344daa2015-10-09 18:10:57 -0700113 gpr_atm destroy_user_data;
114 gpr_atm user_data;
Nicolas Nobleb7ebd3b2014-11-26 16:33:03 -0800115
Nicolas Nobleb7ebd3b2014-11-26 16:33:03 -0800116 struct internal_metadata *bucket_next;
117} internal_metadata;
118
Craig Tillerb2b42612015-11-20 12:02:17 -0800119typedef struct strtab_shard {
Nicolas Nobleb7ebd3b2014-11-26 16:33:03 -0800120 gpr_mu mu;
Craig Tillerb2b42612015-11-20 12:02:17 -0800121 internal_string **strs;
122 size_t count;
123 size_t capacity;
124} strtab_shard;
Nicolas Nobleb7ebd3b2014-11-26 16:33:03 -0800125
Craig Tillerb2b42612015-11-20 12:02:17 -0800126typedef struct mdtab_shard {
127 gpr_mu mu;
128 internal_metadata **elems;
129 size_t count;
130 size_t capacity;
131 size_t free;
132} mdtab_shard;
Craig Tiller0e72ede2015-11-19 07:48:53 -0800133
Craig Tillerb2b42612015-11-20 12:02:17 -0800134#define LOG2_STRTAB_SHARD_COUNT 5
135#define LOG2_MDTAB_SHARD_COUNT 4
136#define STRTAB_SHARD_COUNT ((size_t)(1 << LOG2_STRTAB_SHARD_COUNT))
137#define MDTAB_SHARD_COUNT ((size_t)(1 << LOG2_MDTAB_SHARD_COUNT))
Nicolas Nobleb7ebd3b2014-11-26 16:33:03 -0800138
Craig Tillerb2b42612015-11-20 12:02:17 -0800139/* hash seed: decided at initialization time */
Craig Tiller7536af02015-12-22 13:49:30 -0800140static uint32_t g_hash_seed;
Craig Tillere62bf982015-12-02 17:11:49 -0800141static int g_forced_hash_seed = 0;
Craig Tillerebdef9d2015-11-19 17:09:49 -0800142
Craig Tillerb2b42612015-11-20 12:02:17 -0800143/* linearly probed hash tables for static element lookup */
144static grpc_mdstr *g_static_strtab[GRPC_STATIC_MDSTR_COUNT * 2];
145static grpc_mdelem *g_static_mdtab[GRPC_STATIC_MDELEM_COUNT * 2];
146static size_t g_static_strtab_maxprobe;
147static size_t g_static_mdtab_maxprobe;
Nicolas Nobleb7ebd3b2014-11-26 16:33:03 -0800148
Craig Tillerb2b42612015-11-20 12:02:17 -0800149static strtab_shard g_strtab_shard[STRTAB_SHARD_COUNT];
150static mdtab_shard g_mdtab_shard[MDTAB_SHARD_COUNT];
151
Craig Tillerb2b42612015-11-20 12:02:17 -0800152static void gc_mdtab(mdtab_shard *shard);
Nicolas Nobleb7ebd3b2014-11-26 16:33:03 -0800153
Craig Tiller7536af02015-12-22 13:49:30 -0800154void grpc_test_only_set_metadata_hash_seed(uint32_t seed) {
Craig Tillere62bf982015-12-02 17:11:49 -0800155 g_hash_seed = seed;
156 g_forced_hash_seed = 1;
157}
158
Craig Tiller0e72ede2015-11-19 07:48:53 -0800159void grpc_mdctx_global_init(void) {
Craig Tillerb2b42612015-11-20 12:02:17 -0800160 size_t i, j;
Craig Tillere62bf982015-12-02 17:11:49 -0800161 if (!g_forced_hash_seed) {
Craig Tiller7536af02015-12-22 13:49:30 -0800162 g_hash_seed = (uint32_t)gpr_now(GPR_CLOCK_REALTIME).tv_nsec;
Craig Tillere62bf982015-12-02 17:11:49 -0800163 }
Craig Tillerb2b42612015-11-20 12:02:17 -0800164 g_static_strtab_maxprobe = 0;
165 g_static_mdtab_maxprobe = 0;
166 /* build static tables */
167 memset(g_static_mdtab, 0, sizeof(g_static_mdtab));
168 memset(g_static_strtab, 0, sizeof(g_static_strtab));
Craig Tiller0e72ede2015-11-19 07:48:53 -0800169 for (i = 0; i < GRPC_STATIC_MDSTR_COUNT; i++) {
170 grpc_mdstr *elem = &grpc_static_mdstr_table[i];
171 const char *str = grpc_static_metadata_strings[i];
Craig Tiller7536af02015-12-22 13:49:30 -0800172 uint32_t hash = gpr_murmur_hash3(str, strlen(str), g_hash_seed);
Craig Tillerb774be42015-11-19 07:56:13 -0800173 *(gpr_slice *)&elem->slice = gpr_slice_from_static_string(str);
Craig Tiller7536af02015-12-22 13:49:30 -0800174 *(uint32_t *)&elem->hash = hash;
Craig Tillerb2b42612015-11-20 12:02:17 -0800175 for (j = 0;; j++) {
176 size_t idx = (hash + j) % GPR_ARRAY_SIZE(g_static_strtab);
177 if (g_static_strtab[idx] == NULL) {
178 g_static_strtab[idx] = &grpc_static_mdstr_table[i];
179 break;
180 }
181 }
182 if (j > g_static_strtab_maxprobe) {
183 g_static_strtab_maxprobe = j;
184 }
Craig Tiller0e72ede2015-11-19 07:48:53 -0800185 }
186 for (i = 0; i < GRPC_STATIC_MDELEM_COUNT; i++) {
187 grpc_mdelem *elem = &grpc_static_mdelem_table[i];
Craig Tillerebdef9d2015-11-19 17:09:49 -0800188 grpc_mdstr *key =
189 &grpc_static_mdstr_table[grpc_static_metadata_elem_indices[2 * i + 0]];
190 grpc_mdstr *value =
191 &grpc_static_mdstr_table[grpc_static_metadata_elem_indices[2 * i + 1]];
Craig Tiller7536af02015-12-22 13:49:30 -0800192 uint32_t hash = GRPC_MDSTR_KV_HASH(key->hash, value->hash);
Craig Tillerb774be42015-11-19 07:56:13 -0800193 *(grpc_mdstr **)&elem->key = key;
194 *(grpc_mdstr **)&elem->value = value;
Craig Tillerb2b42612015-11-20 12:02:17 -0800195 for (j = 0;; j++) {
196 size_t idx = (hash + j) % GPR_ARRAY_SIZE(g_static_mdtab);
197 if (g_static_mdtab[idx] == NULL) {
198 g_static_mdtab[idx] = elem;
199 break;
200 }
201 }
202 if (j > g_static_mdtab_maxprobe) {
203 g_static_mdtab_maxprobe = j;
204 }
205 }
206 /* initialize shards */
207 for (i = 0; i < STRTAB_SHARD_COUNT; i++) {
208 strtab_shard *shard = &g_strtab_shard[i];
209 gpr_mu_init(&shard->mu);
210 shard->count = 0;
211 shard->capacity = INITIAL_STRTAB_CAPACITY;
212 shard->strs = gpr_malloc(sizeof(*shard->strs) * shard->capacity);
213 memset(shard->strs, 0, sizeof(*shard->strs) * shard->capacity);
214 }
215 for (i = 0; i < MDTAB_SHARD_COUNT; i++) {
216 mdtab_shard *shard = &g_mdtab_shard[i];
217 gpr_mu_init(&shard->mu);
218 shard->count = 0;
219 shard->free = 0;
220 shard->capacity = INITIAL_MDTAB_CAPACITY;
221 shard->elems = gpr_malloc(sizeof(*shard->elems) * shard->capacity);
222 memset(shard->elems, 0, sizeof(*shard->elems) * shard->capacity);
Craig Tiller0e72ede2015-11-19 07:48:53 -0800223 }
224}
225
Craig Tillerb2b42612015-11-20 12:02:17 -0800226void grpc_mdctx_global_shutdown(void) {
227 size_t i;
228 for (i = 0; i < MDTAB_SHARD_COUNT; i++) {
229 mdtab_shard *shard = &g_mdtab_shard[i];
230 gpr_mu_destroy(&shard->mu);
Craig Tiller34075442015-11-23 16:16:54 -0800231 gc_mdtab(shard);
232 /* TODO(ctiller): GPR_ASSERT(shard->count == 0); */
233 if (shard->count != 0) {
yang-gd88e1d82015-12-02 13:23:33 -0800234 gpr_log(GPR_DEBUG, "WARNING: %d metadata elements were leaked",
235 shard->count);
Craig Tiller0cb803d2016-03-02 22:17:24 -0800236 if (grpc_iomgr_abort_on_leaks()) {
237 abort();
238 }
Craig Tiller34075442015-11-23 16:16:54 -0800239 }
Craig Tillerb2b42612015-11-20 12:02:17 -0800240 gpr_free(shard->elems);
241 }
242 for (i = 0; i < STRTAB_SHARD_COUNT; i++) {
243 strtab_shard *shard = &g_strtab_shard[i];
244 gpr_mu_destroy(&shard->mu);
Craig Tiller34075442015-11-23 16:16:54 -0800245 /* TODO(ctiller): GPR_ASSERT(shard->count == 0); */
246 if (shard->count != 0) {
yang-gd88e1d82015-12-02 13:23:33 -0800247 gpr_log(GPR_DEBUG, "WARNING: %d metadata strings were leaked",
248 shard->count);
Craig Tiller0cb803d2016-03-02 22:17:24 -0800249 if (grpc_iomgr_abort_on_leaks()) {
250 abort();
251 }
Craig Tiller34075442015-11-23 16:16:54 -0800252 }
Craig Tillerb2b42612015-11-20 12:02:17 -0800253 gpr_free(shard->strs);
254 }
255}
Craig Tiller0e72ede2015-11-19 07:48:53 -0800256
257static int is_mdstr_static(grpc_mdstr *s) {
Craig Tillerb774be42015-11-19 07:56:13 -0800258 return s >= &grpc_static_mdstr_table[0] &&
259 s < &grpc_static_mdstr_table[GRPC_STATIC_MDSTR_COUNT];
Craig Tiller0e72ede2015-11-19 07:48:53 -0800260}
261
262static int is_mdelem_static(grpc_mdelem *e) {
Craig Tillerb774be42015-11-19 07:56:13 -0800263 return e >= &grpc_static_mdelem_table[0] &&
264 e < &grpc_static_mdelem_table[GRPC_STATIC_MDELEM_COUNT];
Craig Tiller0e72ede2015-11-19 07:48:53 -0800265}
266
Craig Tillerb2b42612015-11-20 12:02:17 -0800267static void ref_md_locked(mdtab_shard *shard,
268 internal_metadata *md DEBUG_ARGS) {
Craig Tiller1a65a232015-07-06 10:22:32 -0700269#ifdef GRPC_METADATA_REFCOUNT_DEBUG
270 gpr_log(file, line, GPR_LOG_SEVERITY_DEBUG,
271 "ELM REF:%p:%d->%d: '%s' = '%s'", md,
272 gpr_atm_no_barrier_load(&md->refcnt),
273 gpr_atm_no_barrier_load(&md->refcnt) + 1,
274 grpc_mdstr_as_c_string((grpc_mdstr *)md->key),
275 grpc_mdstr_as_c_string((grpc_mdstr *)md->value));
276#endif
Craig Tillerb8e82672015-10-10 13:52:47 -0700277 if (0 == gpr_atm_no_barrier_fetch_add(&md->refcnt, 2)) {
Craig Tillerb2b42612015-11-20 12:02:17 -0800278 shard->free--;
Craig Tillerb8e82672015-10-10 13:52:47 -0700279 } else {
280 GPR_ASSERT(1 != gpr_atm_no_barrier_fetch_add(&md->refcnt, -1));
Nicolas Nobleb7ebd3b2014-11-26 16:33:03 -0800281 }
282}
283
Craig Tillerb2b42612015-11-20 12:02:17 -0800284static void grow_strtab(strtab_shard *shard) {
285 size_t capacity = shard->capacity * 2;
Nicolas Nobleb7ebd3b2014-11-26 16:33:03 -0800286 size_t i;
Craig Tiller9d35a1f2015-11-02 14:16:12 -0800287 internal_string **strtab;
Nicolas Nobleb7ebd3b2014-11-26 16:33:03 -0800288 internal_string *s, *next;
Craig Tiller9d35a1f2015-11-02 14:16:12 -0800289
290 GPR_TIMER_BEGIN("grow_strtab", 0);
291
292 strtab = gpr_malloc(sizeof(internal_string *) * capacity);
Nicolas Nobleb7ebd3b2014-11-26 16:33:03 -0800293 memset(strtab, 0, sizeof(internal_string *) * capacity);
294
Craig Tillerb2b42612015-11-20 12:02:17 -0800295 for (i = 0; i < shard->capacity; i++) {
296 for (s = shard->strs[i]; s; s = next) {
297 size_t idx = TABLE_IDX(s->hash, LOG2_STRTAB_SHARD_COUNT, capacity);
Nicolas Nobleb7ebd3b2014-11-26 16:33:03 -0800298 next = s->bucket_next;
Craig Tillerb2b42612015-11-20 12:02:17 -0800299 s->bucket_next = strtab[idx];
300 strtab[idx] = s;
Nicolas Nobleb7ebd3b2014-11-26 16:33:03 -0800301 }
302 }
303
Craig Tillerb2b42612015-11-20 12:02:17 -0800304 gpr_free(shard->strs);
305 shard->strs = strtab;
306 shard->capacity = capacity;
Craig Tiller9d35a1f2015-11-02 14:16:12 -0800307
308 GPR_TIMER_END("grow_strtab", 0);
Nicolas Nobleb7ebd3b2014-11-26 16:33:03 -0800309}
310
Craig Tillerb2b42612015-11-20 12:02:17 -0800311static void internal_destroy_string(strtab_shard *shard, internal_string *is) {
Nicolas Nobleb7ebd3b2014-11-26 16:33:03 -0800312 internal_string **prev_next;
313 internal_string *cur;
Craig Tiller9d35a1f2015-11-02 14:16:12 -0800314 GPR_TIMER_BEGIN("internal_destroy_string", 0);
ctiller430c4992014-12-11 09:15:41 -0800315 if (is->has_base64_and_huffman_encoded) {
316 gpr_slice_unref(is->base64_and_huffman);
317 }
Craig Tillerb2b42612015-11-20 12:02:17 -0800318 for (prev_next = &shard->strs[TABLE_IDX(is->hash, LOG2_STRTAB_SHARD_COUNT,
319 shard->capacity)],
Nicolas Nobleb7ebd3b2014-11-26 16:33:03 -0800320 cur = *prev_next;
321 cur != is; prev_next = &cur->bucket_next, cur = cur->bucket_next)
322 ;
323 *prev_next = cur->bucket_next;
Craig Tillerb2b42612015-11-20 12:02:17 -0800324 shard->count--;
Nicolas Nobleb7ebd3b2014-11-26 16:33:03 -0800325 gpr_free(is);
Craig Tiller9d35a1f2015-11-02 14:16:12 -0800326 GPR_TIMER_END("internal_destroy_string", 0);
Nicolas Nobleb7ebd3b2014-11-26 16:33:03 -0800327}
328
Nicolas Nobleb7ebd3b2014-11-26 16:33:03 -0800329static void slice_ref(void *p) {
330 internal_string *is =
331 (internal_string *)((char *)p - offsetof(internal_string, refcount));
Craig Tillerb2b42612015-11-20 12:02:17 -0800332 GRPC_MDSTR_REF((grpc_mdstr *)(is));
Nicolas Nobleb7ebd3b2014-11-26 16:33:03 -0800333}
334
335static void slice_unref(void *p) {
336 internal_string *is =
337 (internal_string *)((char *)p - offsetof(internal_string, refcount));
Craig Tillerb2b42612015-11-20 12:02:17 -0800338 GRPC_MDSTR_UNREF((grpc_mdstr *)(is));
Nicolas Nobleb7ebd3b2014-11-26 16:33:03 -0800339}
340
Craig Tillerb2b42612015-11-20 12:02:17 -0800341grpc_mdstr *grpc_mdstr_from_string(const char *str) {
Craig Tiller7536af02015-12-22 13:49:30 -0800342 return grpc_mdstr_from_buffer((const uint8_t *)str, strlen(str));
Nicolas Nobleb7ebd3b2014-11-26 16:33:03 -0800343}
344
Craig Tillerb2b42612015-11-20 12:02:17 -0800345grpc_mdstr *grpc_mdstr_from_slice(gpr_slice slice) {
346 grpc_mdstr *result = grpc_mdstr_from_buffer(GPR_SLICE_START_PTR(slice),
Nicolas Nobleb7ebd3b2014-11-26 16:33:03 -0800347 GPR_SLICE_LENGTH(slice));
348 gpr_slice_unref(slice);
349 return result;
350}
351
Craig Tiller7536af02015-12-22 13:49:30 -0800352grpc_mdstr *grpc_mdstr_from_buffer(const uint8_t *buf, size_t length) {
353 uint32_t hash = gpr_murmur_hash3(buf, length, g_hash_seed);
Nicolas Nobleb7ebd3b2014-11-26 16:33:03 -0800354 internal_string *s;
Craig Tillerb2b42612015-11-20 12:02:17 -0800355 strtab_shard *shard =
356 &g_strtab_shard[SHARD_IDX(hash, LOG2_STRTAB_SHARD_COUNT)];
Craig Tiller0e72ede2015-11-19 07:48:53 -0800357 size_t i;
Craig Tillerb2b42612015-11-20 12:02:17 -0800358 size_t idx;
Nicolas Nobleb7ebd3b2014-11-26 16:33:03 -0800359
Craig Tiller9d35a1f2015-11-02 14:16:12 -0800360 GPR_TIMER_BEGIN("grpc_mdstr_from_buffer", 0);
Craig Tiller0e72ede2015-11-19 07:48:53 -0800361
362 /* search for a static string */
Craig Tillerb2b42612015-11-20 12:02:17 -0800363 for (i = 0; i <= g_static_strtab_maxprobe; i++) {
364 grpc_mdstr *ss;
365 idx = (hash + i) % GPR_ARRAY_SIZE(g_static_strtab);
366 ss = g_static_strtab[idx];
367 if (ss == NULL) break;
368 if (ss->hash == hash && GPR_SLICE_LENGTH(ss->slice) == length &&
369 0 == memcmp(buf, GPR_SLICE_START_PTR(ss->slice), length)) {
Craig Tiller07718b82015-11-21 14:06:45 -0800370 GPR_TIMER_END("grpc_mdstr_from_buffer", 0);
Craig Tillerb2b42612015-11-20 12:02:17 -0800371 return ss;
Craig Tiller0e72ede2015-11-19 07:48:53 -0800372 }
373 }
374
Craig Tillerb2b42612015-11-20 12:02:17 -0800375 gpr_mu_lock(&shard->mu);
Nicolas Nobleb7ebd3b2014-11-26 16:33:03 -0800376
377 /* search for an existing string */
Craig Tillerb2b42612015-11-20 12:02:17 -0800378 idx = TABLE_IDX(hash, LOG2_STRTAB_SHARD_COUNT, shard->capacity);
379 for (s = shard->strs[idx]; s; s = s->bucket_next) {
Nicolas Nobleb7ebd3b2014-11-26 16:33:03 -0800380 if (s->hash == hash && GPR_SLICE_LENGTH(s->slice) == length &&
381 0 == memcmp(buf, GPR_SLICE_START_PTR(s->slice), length)) {
Craig Tillerb2b42612015-11-20 12:02:17 -0800382 GRPC_MDSTR_REF((grpc_mdstr *)s);
383 gpr_mu_unlock(&shard->mu);
Craig Tiller9d35a1f2015-11-02 14:16:12 -0800384 GPR_TIMER_END("grpc_mdstr_from_buffer", 0);
Nicolas Nobleb7ebd3b2014-11-26 16:33:03 -0800385 return (grpc_mdstr *)s;
386 }
387 }
388
389 /* not found: create a new string */
390 if (length + 1 < GPR_SLICE_INLINED_SIZE) {
391 /* string data goes directly into the slice */
392 s = gpr_malloc(sizeof(internal_string));
Craig Tillerb2b42612015-11-20 12:02:17 -0800393 gpr_atm_rel_store(&s->refcnt, 2);
Nicolas Nobleb7ebd3b2014-11-26 16:33:03 -0800394 s->slice.refcount = NULL;
395 memcpy(s->slice.data.inlined.bytes, buf, length);
396 s->slice.data.inlined.bytes[length] = 0;
Craig Tiller7536af02015-12-22 13:49:30 -0800397 s->slice.data.inlined.length = (uint8_t)length;
Nicolas Nobleb7ebd3b2014-11-26 16:33:03 -0800398 } else {
399 /* string data goes after the internal_string header, and we +1 for null
400 terminator */
401 s = gpr_malloc(sizeof(internal_string) + length + 1);
Craig Tillerb2b42612015-11-20 12:02:17 -0800402 gpr_atm_rel_store(&s->refcnt, 2);
Nicolas Nobleb7ebd3b2014-11-26 16:33:03 -0800403 s->refcount.ref = slice_ref;
404 s->refcount.unref = slice_unref;
405 s->slice.refcount = &s->refcount;
Craig Tiller7536af02015-12-22 13:49:30 -0800406 s->slice.data.refcounted.bytes = (uint8_t *)(s + 1);
Nicolas Nobleb7ebd3b2014-11-26 16:33:03 -0800407 s->slice.data.refcounted.length = length;
408 memcpy(s->slice.data.refcounted.bytes, buf, length);
409 /* add a null terminator for cheap c string conversion when desired */
410 s->slice.data.refcounted.bytes[length] = 0;
411 }
ctiller430c4992014-12-11 09:15:41 -0800412 s->has_base64_and_huffman_encoded = 0;
Nicolas Nobleb7ebd3b2014-11-26 16:33:03 -0800413 s->hash = hash;
yang-gcb7a8022016-03-30 14:58:53 -0700414 s->has_size_in_decoder_table = 0;
415 s->size_in_decoder_table = 0;
Craig Tillerb2b42612015-11-20 12:02:17 -0800416 s->bucket_next = shard->strs[idx];
417 shard->strs[idx] = s;
Nicolas Nobleb7ebd3b2014-11-26 16:33:03 -0800418
Craig Tillerb2b42612015-11-20 12:02:17 -0800419 shard->count++;
Nicolas Nobleb7ebd3b2014-11-26 16:33:03 -0800420
Craig Tillerb2b42612015-11-20 12:02:17 -0800421 if (shard->count > shard->capacity * 2) {
422 grow_strtab(shard);
Nicolas Nobleb7ebd3b2014-11-26 16:33:03 -0800423 }
424
Craig Tillerb2b42612015-11-20 12:02:17 -0800425 gpr_mu_unlock(&shard->mu);
Craig Tiller9d35a1f2015-11-02 14:16:12 -0800426 GPR_TIMER_END("grpc_mdstr_from_buffer", 0);
Nicolas Nobleb7ebd3b2014-11-26 16:33:03 -0800427
428 return (grpc_mdstr *)s;
429}
430
Craig Tillerb2b42612015-11-20 12:02:17 -0800431static void gc_mdtab(mdtab_shard *shard) {
Nicolas Nobleb7ebd3b2014-11-26 16:33:03 -0800432 size_t i;
433 internal_metadata **prev_next;
434 internal_metadata *md, *next;
435
Craig Tiller9d35a1f2015-11-02 14:16:12 -0800436 GPR_TIMER_BEGIN("gc_mdtab", 0);
Craig Tillerb2b42612015-11-20 12:02:17 -0800437 for (i = 0; i < shard->capacity; i++) {
438 prev_next = &shard->elems[i];
439 for (md = shard->elems[i]; md; md = next) {
Craig Tiller8344daa2015-10-09 18:10:57 -0700440 void *user_data = (void *)gpr_atm_no_barrier_load(&md->user_data);
Nicolas Nobleb7ebd3b2014-11-26 16:33:03 -0800441 next = md->bucket_next;
Craig Tiller9fa41b92015-04-10 15:08:03 -0700442 if (gpr_atm_acq_load(&md->refcnt) == 0) {
Craig Tillerb2b42612015-11-20 12:02:17 -0800443 GRPC_MDSTR_UNREF((grpc_mdstr *)md->key);
444 GRPC_MDSTR_UNREF((grpc_mdstr *)md->value);
Nicolas Nobleb7ebd3b2014-11-26 16:33:03 -0800445 if (md->user_data) {
Craig Tiller8344daa2015-10-09 18:10:57 -0700446 ((destroy_user_data_func)gpr_atm_no_barrier_load(
447 &md->destroy_user_data))(user_data);
Nicolas Nobleb7ebd3b2014-11-26 16:33:03 -0800448 }
449 gpr_free(md);
450 *prev_next = next;
Craig Tillerb2b42612015-11-20 12:02:17 -0800451 shard->free--;
452 shard->count--;
Nicolas Nobleb7ebd3b2014-11-26 16:33:03 -0800453 } else {
454 prev_next = &md->bucket_next;
455 }
456 }
457 }
Craig Tiller9d35a1f2015-11-02 14:16:12 -0800458 GPR_TIMER_END("gc_mdtab", 0);
Nicolas Nobleb7ebd3b2014-11-26 16:33:03 -0800459}
460
Craig Tillerb2b42612015-11-20 12:02:17 -0800461static void grow_mdtab(mdtab_shard *shard) {
462 size_t capacity = shard->capacity * 2;
Nicolas Nobleb7ebd3b2014-11-26 16:33:03 -0800463 size_t i;
Craig Tiller9d35a1f2015-11-02 14:16:12 -0800464 internal_metadata **mdtab;
Nicolas Nobleb7ebd3b2014-11-26 16:33:03 -0800465 internal_metadata *md, *next;
Craig Tiller7536af02015-12-22 13:49:30 -0800466 uint32_t hash;
Craig Tiller9d35a1f2015-11-02 14:16:12 -0800467
468 GPR_TIMER_BEGIN("grow_mdtab", 0);
469
470 mdtab = gpr_malloc(sizeof(internal_metadata *) * capacity);
Nicolas Nobleb7ebd3b2014-11-26 16:33:03 -0800471 memset(mdtab, 0, sizeof(internal_metadata *) * capacity);
472
Craig Tillerb2b42612015-11-20 12:02:17 -0800473 for (i = 0; i < shard->capacity; i++) {
474 for (md = shard->elems[i]; md; md = next) {
475 size_t idx;
ctillerfb93d192014-12-15 10:40:05 -0800476 hash = GRPC_MDSTR_KV_HASH(md->key->hash, md->value->hash);
Nicolas Nobleb7ebd3b2014-11-26 16:33:03 -0800477 next = md->bucket_next;
Craig Tillerb2b42612015-11-20 12:02:17 -0800478 idx = TABLE_IDX(hash, LOG2_MDTAB_SHARD_COUNT, capacity);
479 md->bucket_next = mdtab[idx];
480 mdtab[idx] = md;
Nicolas Nobleb7ebd3b2014-11-26 16:33:03 -0800481 }
482 }
483
Craig Tillerb2b42612015-11-20 12:02:17 -0800484 gpr_free(shard->elems);
485 shard->elems = mdtab;
486 shard->capacity = capacity;
Craig Tiller9d35a1f2015-11-02 14:16:12 -0800487
488 GPR_TIMER_END("grow_mdtab", 0);
Nicolas Nobleb7ebd3b2014-11-26 16:33:03 -0800489}
490
Craig Tillerb2b42612015-11-20 12:02:17 -0800491static void rehash_mdtab(mdtab_shard *shard) {
492 if (shard->free > shard->capacity / 4) {
493 gc_mdtab(shard);
Nicolas Nobleb7ebd3b2014-11-26 16:33:03 -0800494 } else {
Craig Tillerb2b42612015-11-20 12:02:17 -0800495 grow_mdtab(shard);
Nicolas Nobleb7ebd3b2014-11-26 16:33:03 -0800496 }
497}
498
Craig Tillerb2b42612015-11-20 12:02:17 -0800499grpc_mdelem *grpc_mdelem_from_metadata_strings(grpc_mdstr *mkey,
Nicolas Nobleb7ebd3b2014-11-26 16:33:03 -0800500 grpc_mdstr *mvalue) {
501 internal_string *key = (internal_string *)mkey;
502 internal_string *value = (internal_string *)mvalue;
Craig Tiller7536af02015-12-22 13:49:30 -0800503 uint32_t hash = GRPC_MDSTR_KV_HASH(mkey->hash, mvalue->hash);
Nicolas Nobleb7ebd3b2014-11-26 16:33:03 -0800504 internal_metadata *md;
Craig Tillerb2b42612015-11-20 12:02:17 -0800505 mdtab_shard *shard = &g_mdtab_shard[SHARD_IDX(hash, LOG2_MDTAB_SHARD_COUNT)];
Craig Tiller0e72ede2015-11-19 07:48:53 -0800506 size_t i;
Craig Tillerb2b42612015-11-20 12:02:17 -0800507 size_t idx;
Nicolas Nobleb7ebd3b2014-11-26 16:33:03 -0800508
Craig Tiller9d35a1f2015-11-02 14:16:12 -0800509 GPR_TIMER_BEGIN("grpc_mdelem_from_metadata_strings", 0);
510
Craig Tiller0e72ede2015-11-19 07:48:53 -0800511 if (is_mdstr_static(mkey) && is_mdstr_static(mvalue)) {
Craig Tillerb2b42612015-11-20 12:02:17 -0800512 for (i = 0; i <= g_static_mdtab_maxprobe; i++) {
513 grpc_mdelem *smd;
514 idx = (hash + i) % GPR_ARRAY_SIZE(g_static_mdtab);
515 smd = g_static_mdtab[idx];
516 if (smd == NULL) break;
517 if (smd->key == mkey && smd->value == mvalue) {
Craig Tiller07718b82015-11-21 14:06:45 -0800518 GPR_TIMER_END("grpc_mdelem_from_metadata_strings", 0);
Craig Tillerb2b42612015-11-20 12:02:17 -0800519 return smd;
Craig Tiller0e72ede2015-11-19 07:48:53 -0800520 }
521 }
522 }
523
Craig Tillerb2b42612015-11-20 12:02:17 -0800524 gpr_mu_lock(&shard->mu);
Nicolas Nobleb7ebd3b2014-11-26 16:33:03 -0800525
Craig Tillerb2b42612015-11-20 12:02:17 -0800526 idx = TABLE_IDX(hash, LOG2_MDTAB_SHARD_COUNT, shard->capacity);
Nicolas Nobleb7ebd3b2014-11-26 16:33:03 -0800527 /* search for an existing pair */
Craig Tillerb2b42612015-11-20 12:02:17 -0800528 for (md = shard->elems[idx]; md; md = md->bucket_next) {
Nicolas Nobleb7ebd3b2014-11-26 16:33:03 -0800529 if (md->key == key && md->value == value) {
Craig Tillerb2b42612015-11-20 12:02:17 -0800530 REF_MD_LOCKED(shard, md);
531 GRPC_MDSTR_UNREF((grpc_mdstr *)key);
532 GRPC_MDSTR_UNREF((grpc_mdstr *)value);
533 gpr_mu_unlock(&shard->mu);
Craig Tiller9d35a1f2015-11-02 14:16:12 -0800534 GPR_TIMER_END("grpc_mdelem_from_metadata_strings", 0);
Nicolas Nobleb7ebd3b2014-11-26 16:33:03 -0800535 return (grpc_mdelem *)md;
536 }
537 }
538
539 /* not found: create a new pair */
540 md = gpr_malloc(sizeof(internal_metadata));
Craig Tiller63bda562015-10-09 17:40:19 -0700541 gpr_atm_rel_store(&md->refcnt, 2);
Nicolas Nobleb7ebd3b2014-11-26 16:33:03 -0800542 md->key = key;
543 md->value = value;
Craig Tiller8344daa2015-10-09 18:10:57 -0700544 md->user_data = 0;
545 md->destroy_user_data = 0;
Craig Tillerb2b42612015-11-20 12:02:17 -0800546 md->bucket_next = shard->elems[idx];
547 shard->elems[idx] = md;
Craig Tiller83901532015-07-10 14:02:45 -0700548 gpr_mu_init(&md->mu_user_data);
Craig Tiller1a65a232015-07-06 10:22:32 -0700549#ifdef GRPC_METADATA_REFCOUNT_DEBUG
550 gpr_log(GPR_DEBUG, "ELM NEW:%p:%d: '%s' = '%s'", md,
551 gpr_atm_no_barrier_load(&md->refcnt),
552 grpc_mdstr_as_c_string((grpc_mdstr *)md->key),
553 grpc_mdstr_as_c_string((grpc_mdstr *)md->value));
554#endif
Craig Tillerb2b42612015-11-20 12:02:17 -0800555 shard->count++;
Nicolas Nobleb7ebd3b2014-11-26 16:33:03 -0800556
Craig Tillerb2b42612015-11-20 12:02:17 -0800557 if (shard->count > shard->capacity * 2) {
558 rehash_mdtab(shard);
Nicolas Nobleb7ebd3b2014-11-26 16:33:03 -0800559 }
560
Craig Tillerb2b42612015-11-20 12:02:17 -0800561 gpr_mu_unlock(&shard->mu);
Nicolas Nobleb7ebd3b2014-11-26 16:33:03 -0800562
Craig Tiller9d35a1f2015-11-02 14:16:12 -0800563 GPR_TIMER_END("grpc_mdelem_from_metadata_strings", 0);
564
Nicolas Nobleb7ebd3b2014-11-26 16:33:03 -0800565 return (grpc_mdelem *)md;
566}
567
Craig Tillerb2b42612015-11-20 12:02:17 -0800568grpc_mdelem *grpc_mdelem_from_strings(const char *key, const char *value) {
569 return grpc_mdelem_from_metadata_strings(grpc_mdstr_from_string(key),
570 grpc_mdstr_from_string(value));
Nicolas Nobleb7ebd3b2014-11-26 16:33:03 -0800571}
572
Craig Tillerb2b42612015-11-20 12:02:17 -0800573grpc_mdelem *grpc_mdelem_from_slices(gpr_slice key, gpr_slice value) {
574 return grpc_mdelem_from_metadata_strings(grpc_mdstr_from_slice(key),
575 grpc_mdstr_from_slice(value));
Nicolas Nobleb7ebd3b2014-11-26 16:33:03 -0800576}
577
Craig Tillerb2b42612015-11-20 12:02:17 -0800578grpc_mdelem *grpc_mdelem_from_string_and_buffer(const char *key,
Craig Tiller7536af02015-12-22 13:49:30 -0800579 const uint8_t *value,
Craig Tiller4dbdd6a2015-09-25 15:12:16 -0700580 size_t value_length) {
Nicolas Nobleb7ebd3b2014-11-26 16:33:03 -0800581 return grpc_mdelem_from_metadata_strings(
Craig Tillerb2b42612015-11-20 12:02:17 -0800582 grpc_mdstr_from_string(key), grpc_mdstr_from_buffer(value, value_length));
Nicolas Nobleb7ebd3b2014-11-26 16:33:03 -0800583}
584
yang-g24ba7c12016-03-30 16:19:43 -0700585static size_t get_base64_encoded_size(size_t raw_length) {
586 static const uint8_t tail_xtra[3] = {0, 2, 3};
587 return raw_length / 3 * 4 + tail_xtra[raw_length % 3];
588}
589
yang-gcb7a8022016-03-30 14:58:53 -0700590size_t grpc_mdelem_get_size_in_hpack_table(grpc_mdelem *elem) {
591 size_t overhead_and_key = 32 + GPR_SLICE_LENGTH(elem->key->slice);
yang-g24ba7c12016-03-30 16:19:43 -0700592 size_t value_len = GPR_SLICE_LENGTH(elem->value->slice);
yang-gcb7a8022016-03-30 14:58:53 -0700593 if (is_mdstr_static(elem->value)) {
yang-g24ba7c12016-03-30 16:19:43 -0700594 if (grpc_is_binary_header(
595 (const char *)GPR_SLICE_START_PTR(elem->key->slice),
596 GPR_SLICE_LENGTH(elem->key->slice))) {
597 return overhead_and_key + get_base64_encoded_size(value_len);
598 } else {
599 return overhead_and_key + value_len;
600 }
yang-gcb7a8022016-03-30 14:58:53 -0700601 } else {
602 internal_string *is = (internal_string *)elem->value;
yang-gcb7a8022016-03-30 14:58:53 -0700603 if (is->has_size_in_decoder_table == 0) {
604 is->has_size_in_decoder_table = 1;
605 if (grpc_is_binary_header(
606 (const char *)GPR_SLICE_START_PTR(elem->key->slice),
607 GPR_SLICE_LENGTH(elem->key->slice))) {
yang-g24ba7c12016-03-30 16:19:43 -0700608 is->size_in_decoder_table = get_base64_encoded_size(value_len);
yang-gcb7a8022016-03-30 14:58:53 -0700609 } else {
610 is->size_in_decoder_table = value_len;
611 }
612 }
613 return overhead_and_key + is->size_in_decoder_table;
614 }
615}
616
Craig Tiller1a65a232015-07-06 10:22:32 -0700617grpc_mdelem *grpc_mdelem_ref(grpc_mdelem *gmd DEBUG_ARGS) {
Nicolas Nobleb7ebd3b2014-11-26 16:33:03 -0800618 internal_metadata *md = (internal_metadata *)gmd;
Craig Tiller0e72ede2015-11-19 07:48:53 -0800619 if (is_mdelem_static(gmd)) return gmd;
Craig Tiller1a65a232015-07-06 10:22:32 -0700620#ifdef GRPC_METADATA_REFCOUNT_DEBUG
621 gpr_log(file, line, GPR_LOG_SEVERITY_DEBUG,
622 "ELM REF:%p:%d->%d: '%s' = '%s'", md,
623 gpr_atm_no_barrier_load(&md->refcnt),
624 gpr_atm_no_barrier_load(&md->refcnt) + 1,
625 grpc_mdstr_as_c_string((grpc_mdstr *)md->key),
626 grpc_mdstr_as_c_string((grpc_mdstr *)md->value));
627#endif
Craig Tiller9fa41b92015-04-10 15:08:03 -0700628 /* we can assume the ref count is >= 1 as the application is calling
629 this function - meaning that no adjustment to mdtab_free is necessary,
630 simplifying the logic here to be just an atomic increment */
631 /* use C assert to have this removed in opt builds */
Craig Tillerb8e82672015-10-10 13:52:47 -0700632 assert(gpr_atm_no_barrier_load(&md->refcnt) >= 2);
Craig Tiller9fa41b92015-04-10 15:08:03 -0700633 gpr_atm_no_barrier_fetch_add(&md->refcnt, 1);
Nicolas Nobleb7ebd3b2014-11-26 16:33:03 -0800634 return gmd;
635}
636
Craig Tiller1a65a232015-07-06 10:22:32 -0700637void grpc_mdelem_unref(grpc_mdelem *gmd DEBUG_ARGS) {
Nicolas Nobleb7ebd3b2014-11-26 16:33:03 -0800638 internal_metadata *md = (internal_metadata *)gmd;
Craig Tiller9d35a1f2015-11-02 14:16:12 -0800639 if (!md) return;
Craig Tiller0e72ede2015-11-19 07:48:53 -0800640 if (is_mdelem_static(gmd)) return;
Craig Tiller1a65a232015-07-06 10:22:32 -0700641#ifdef GRPC_METADATA_REFCOUNT_DEBUG
642 gpr_log(file, line, GPR_LOG_SEVERITY_DEBUG,
643 "ELM UNREF:%p:%d->%d: '%s' = '%s'", md,
644 gpr_atm_no_barrier_load(&md->refcnt),
645 gpr_atm_no_barrier_load(&md->refcnt) - 1,
646 grpc_mdstr_as_c_string((grpc_mdstr *)md->key),
647 grpc_mdstr_as_c_string((grpc_mdstr *)md->value));
648#endif
Craig Tiller63bda562015-10-09 17:40:19 -0700649 if (2 == gpr_atm_full_fetch_add(&md->refcnt, -1)) {
Craig Tiller7536af02015-12-22 13:49:30 -0800650 uint32_t hash = GRPC_MDSTR_KV_HASH(md->key->hash, md->value->hash);
Craig Tillerb2b42612015-11-20 12:02:17 -0800651 mdtab_shard *shard =
652 &g_mdtab_shard[SHARD_IDX(hash, LOG2_MDTAB_SHARD_COUNT)];
Craig Tiller9d35a1f2015-11-02 14:16:12 -0800653 GPR_TIMER_BEGIN("grpc_mdelem_unref.to_zero", 0);
Craig Tillerb2b42612015-11-20 12:02:17 -0800654 gpr_mu_lock(&shard->mu);
Craig Tillerb8e82672015-10-10 13:52:47 -0700655 if (1 == gpr_atm_no_barrier_load(&md->refcnt)) {
Craig Tillerb2b42612015-11-20 12:02:17 -0800656 shard->free++;
Craig Tillerb8e82672015-10-10 13:52:47 -0700657 gpr_atm_no_barrier_store(&md->refcnt, 0);
658 }
Craig Tillerb2b42612015-11-20 12:02:17 -0800659 gpr_mu_unlock(&shard->mu);
Craig Tiller9d35a1f2015-11-02 14:16:12 -0800660 GPR_TIMER_END("grpc_mdelem_unref.to_zero", 0);
Nicolas Nobleb7ebd3b2014-11-26 16:33:03 -0800661 }
Nicolas Nobleb7ebd3b2014-11-26 16:33:03 -0800662}
663
664const char *grpc_mdstr_as_c_string(grpc_mdstr *s) {
665 return (const char *)GPR_SLICE_START_PTR(s->slice);
666}
667
Craig Tiller1a65a232015-07-06 10:22:32 -0700668grpc_mdstr *grpc_mdstr_ref(grpc_mdstr *gs DEBUG_ARGS) {
Nicolas Nobleb7ebd3b2014-11-26 16:33:03 -0800669 internal_string *s = (internal_string *)gs;
Craig Tiller0e72ede2015-11-19 07:48:53 -0800670 if (is_mdstr_static(gs)) return gs;
Craig Tillerb2b42612015-11-20 12:02:17 -0800671 GPR_ASSERT(gpr_atm_full_fetch_add(&s->refcnt, 1) != 0);
Nicolas Nobleb7ebd3b2014-11-26 16:33:03 -0800672 return gs;
673}
674
Craig Tiller1a65a232015-07-06 10:22:32 -0700675void grpc_mdstr_unref(grpc_mdstr *gs DEBUG_ARGS) {
Nicolas Nobleb7ebd3b2014-11-26 16:33:03 -0800676 internal_string *s = (internal_string *)gs;
Craig Tiller0e72ede2015-11-19 07:48:53 -0800677 if (is_mdstr_static(gs)) return;
Craig Tillerb2b42612015-11-20 12:02:17 -0800678 if (2 == gpr_atm_full_fetch_add(&s->refcnt, -1)) {
679 strtab_shard *shard =
680 &g_strtab_shard[SHARD_IDX(s->hash, LOG2_STRTAB_SHARD_COUNT)];
681 gpr_mu_lock(&shard->mu);
682 if (1 == gpr_atm_no_barrier_load(&s->refcnt)) {
683 internal_destroy_string(shard, s);
684 }
685 gpr_mu_unlock(&shard->mu);
686 }
Nicolas Nobleb7ebd3b2014-11-26 16:33:03 -0800687}
688
Craig Tiller8344daa2015-10-09 18:10:57 -0700689void *grpc_mdelem_get_user_data(grpc_mdelem *md, void (*destroy_func)(void *)) {
Nicolas Nobleb7ebd3b2014-11-26 16:33:03 -0800690 internal_metadata *im = (internal_metadata *)md;
Craig Tiller83901532015-07-10 14:02:45 -0700691 void *result;
Craig Tillerb2b42612015-11-20 12:02:17 -0800692 if (is_mdelem_static(md)) {
693 return (void *)grpc_static_mdelem_user_data[md - grpc_static_mdelem_table];
694 }
Craig Tiller8344daa2015-10-09 18:10:57 -0700695 if (gpr_atm_acq_load(&im->destroy_user_data) == (gpr_atm)destroy_func) {
696 return (void *)gpr_atm_no_barrier_load(&im->user_data);
697 } else {
698 return NULL;
699 }
Craig Tiller83901532015-07-10 14:02:45 -0700700 return result;
Nicolas Nobleb7ebd3b2014-11-26 16:33:03 -0800701}
702
703void grpc_mdelem_set_user_data(grpc_mdelem *md, void (*destroy_func)(void *),
704 void *user_data) {
705 internal_metadata *im = (internal_metadata *)md;
Craig Tillerebdef9d2015-11-19 17:09:49 -0800706 GPR_ASSERT(!is_mdelem_static(md));
Nicolas Nobleb7ebd3b2014-11-26 16:33:03 -0800707 GPR_ASSERT((user_data == NULL) == (destroy_func == NULL));
Craig Tiller83901532015-07-10 14:02:45 -0700708 gpr_mu_lock(&im->mu_user_data);
Craig Tiller8344daa2015-10-09 18:10:57 -0700709 if (gpr_atm_no_barrier_load(&im->destroy_user_data)) {
Craig Tiller83901532015-07-10 14:02:45 -0700710 /* user data can only be set once */
711 gpr_mu_unlock(&im->mu_user_data);
712 if (destroy_func != NULL) {
713 destroy_func(user_data);
714 }
715 return;
Nicolas Nobleb7ebd3b2014-11-26 16:33:03 -0800716 }
Craig Tiller8344daa2015-10-09 18:10:57 -0700717 gpr_atm_no_barrier_store(&im->user_data, (gpr_atm)user_data);
718 gpr_atm_rel_store(&im->destroy_user_data, (gpr_atm)destroy_func);
Craig Tiller83901532015-07-10 14:02:45 -0700719 gpr_mu_unlock(&im->mu_user_data);
Nicolas Nobleb7ebd3b2014-11-26 16:33:03 -0800720}
ctiller430c4992014-12-11 09:15:41 -0800721
722gpr_slice grpc_mdstr_as_base64_encoded_and_huffman_compressed(grpc_mdstr *gs) {
723 internal_string *s = (internal_string *)gs;
724 gpr_slice slice;
Craig Tillerb2b42612015-11-20 12:02:17 -0800725 strtab_shard *shard =
726 &g_strtab_shard[SHARD_IDX(s->hash, LOG2_STRTAB_SHARD_COUNT)];
727 gpr_mu_lock(&shard->mu);
ctiller430c4992014-12-11 09:15:41 -0800728 if (!s->has_base64_and_huffman_encoded) {
729 s->base64_and_huffman =
730 grpc_chttp2_base64_encode_and_huffman_compress(s->slice);
ctiller33023c42014-12-12 16:28:33 -0800731 s->has_base64_and_huffman_encoded = 1;
ctiller430c4992014-12-11 09:15:41 -0800732 }
733 slice = s->base64_and_huffman;
Craig Tillerb2b42612015-11-20 12:02:17 -0800734 gpr_mu_unlock(&shard->mu);
ctiller430c4992014-12-11 09:15:41 -0800735 return slice;
David Garcia Quintas2bf574f2016-01-14 15:27:08 -0800736}