LCOV - code coverage report
Current view: top level - core/transport - metadata.c (source / functions) Hit Total Coverage
Test: tmp.CaZ6RjdVn2 Lines: 326 326 100.0 %
Date: 2015-12-10 22:15:08 Functions: 34 35 97.1 %

          Line data    Source code
       1             : /*
       2             :  *
       3             :  * Copyright 2015, Google Inc.
       4             :  * 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             : 
      34             : #include "src/core/transport/metadata.h"
      35             : 
      36             : #include <assert.h>
      37             : #include <stddef.h>
      38             : #include <string.h>
      39             : 
      40             : #include <grpc/compression.h>
      41             : #include <grpc/support/alloc.h>
      42             : #include <grpc/support/atm.h>
      43             : #include <grpc/support/log.h>
      44             : #include <grpc/support/string_util.h>
      45             : #include <grpc/support/time.h>
      46             : #include "src/core/profiling/timers.h"
      47             : #include "src/core/support/murmur_hash.h"
      48             : #include "src/core/support/string.h"
      49             : #include "src/core/transport/chttp2/bin_encoder.h"
      50             : #include "src/core/transport/static_metadata.h"
      51             : 
      52             : /* There are two kinds of mdelem and mdstr instances.
      53             :  * Static instances are declared in static_metadata.{h,c} and
      54             :  * are initialized by grpc_mdctx_global_init().
      55             :  * Dynamic instances are stored in hash tables on grpc_mdctx, and are backed
      56             :  * by internal_string and internal_element structures.
      57             :  * Internal helper functions here-in (is_mdstr_static, is_mdelem_static) are
      58             :  * used to determine which kind of element a pointer refers to.
      59             :  */
      60             : 
      61             : #define INITIAL_STRTAB_CAPACITY 4
      62             : #define INITIAL_MDTAB_CAPACITY 4
      63             : 
      64             : #ifdef GRPC_METADATA_REFCOUNT_DEBUG
      65             : #define DEBUG_ARGS , const char *file, int line
      66             : #define FWD_DEBUG_ARGS , file, line
      67             : #define REF_MD_LOCKED(shard, s) ref_md_locked((shard), (s), __FILE__, __LINE__)
      68             : #else
      69             : #define DEBUG_ARGS
      70             : #define FWD_DEBUG_ARGS
      71             : #define REF_MD_LOCKED(shard, s) ref_md_locked((shard), (s))
      72             : #endif
      73             : 
      74             : #define TABLE_IDX(hash, log2_shards, capacity) \
      75             :   (((hash) >> (log2_shards)) % (capacity))
      76             : #define SHARD_IDX(hash, log2_shards) ((hash) & ((1 << (log2_shards)) - 1))
      77             : 
      78             : typedef void (*destroy_user_data_func)(void *user_data);
      79             : 
      80             : /* Shadow structure for grpc_mdstr for non-static values */
      81             : typedef struct internal_string {
      82             :   /* must be byte compatible with grpc_mdstr */
      83             :   gpr_slice slice;
      84             :   gpr_uint32 hash;
      85             : 
      86             :   /* private only data */
      87             :   gpr_atm refcnt;
      88             : 
      89             :   gpr_uint8 has_base64_and_huffman_encoded;
      90             :   gpr_slice_refcount refcount;
      91             : 
      92             :   gpr_slice base64_and_huffman;
      93             : 
      94             :   struct internal_string *bucket_next;
      95             : } internal_string;
      96             : 
      97             : /* Shadow structure for grpc_mdelem for non-static elements */
      98             : typedef struct internal_metadata {
      99             :   /* must be byte compatible with grpc_mdelem */
     100             :   internal_string *key;
     101             :   internal_string *value;
     102             : 
     103             :   /* private only data */
     104             :   gpr_atm refcnt;
     105             : 
     106             :   gpr_mu mu_user_data;
     107             :   gpr_atm destroy_user_data;
     108             :   gpr_atm user_data;
     109             : 
     110             :   struct internal_metadata *bucket_next;
     111             : } internal_metadata;
     112             : 
     113             : typedef struct strtab_shard {
     114             :   gpr_mu mu;
     115             :   internal_string **strs;
     116             :   size_t count;
     117             :   size_t capacity;
     118             : } strtab_shard;
     119             : 
     120             : typedef struct mdtab_shard {
     121             :   gpr_mu mu;
     122             :   internal_metadata **elems;
     123             :   size_t count;
     124             :   size_t capacity;
     125             :   size_t free;
     126             : } mdtab_shard;
     127             : 
     128             : #define LOG2_STRTAB_SHARD_COUNT 5
     129             : #define LOG2_MDTAB_SHARD_COUNT 4
     130             : #define STRTAB_SHARD_COUNT ((size_t)(1 << LOG2_STRTAB_SHARD_COUNT))
     131             : #define MDTAB_SHARD_COUNT ((size_t)(1 << LOG2_MDTAB_SHARD_COUNT))
     132             : 
     133             : /* hash seed: decided at initialization time */
     134             : static gpr_uint32 g_hash_seed;
     135             : static int g_forced_hash_seed = 0;
     136             : 
     137             : /* linearly probed hash tables for static element lookup */
     138             : static grpc_mdstr *g_static_strtab[GRPC_STATIC_MDSTR_COUNT * 2];
     139             : static grpc_mdelem *g_static_mdtab[GRPC_STATIC_MDELEM_COUNT * 2];
     140             : static size_t g_static_strtab_maxprobe;
     141             : static size_t g_static_mdtab_maxprobe;
     142             : 
     143             : static strtab_shard g_strtab_shard[STRTAB_SHARD_COUNT];
     144             : static mdtab_shard g_mdtab_shard[MDTAB_SHARD_COUNT];
     145             : 
     146             : static void gc_mdtab(mdtab_shard *shard);
     147             : 
     148           1 : void grpc_test_only_set_metadata_hash_seed(gpr_uint32 seed) {
     149           1 :   g_hash_seed = seed;
     150           1 :   g_forced_hash_seed = 1;
     151           1 : }
     152             : 
     153        3452 : void grpc_mdctx_global_init(void) {
     154             :   size_t i, j;
     155        3452 :   if (!g_forced_hash_seed) {
     156        3451 :     g_hash_seed = (gpr_uint32)gpr_now(GPR_CLOCK_REALTIME).tv_nsec;
     157             :   }
     158        3452 :   g_static_strtab_maxprobe = 0;
     159        3452 :   g_static_mdtab_maxprobe = 0;
     160             :   /* build static tables */
     161        3452 :   memset(g_static_mdtab, 0, sizeof(g_static_mdtab));
     162        3452 :   memset(g_static_strtab, 0, sizeof(g_static_strtab));
     163      303776 :   for (i = 0; i < GRPC_STATIC_MDSTR_COUNT; i++) {
     164      300237 :     grpc_mdstr *elem = &grpc_static_mdstr_table[i];
     165      300324 :     const char *str = grpc_static_metadata_strings[i];
     166      300324 :     gpr_uint32 hash = gpr_murmur_hash3(str, strlen(str), g_hash_seed);
     167      300324 :     *(gpr_slice *)&elem->slice = gpr_slice_from_static_string(str);
     168      300324 :     *(gpr_uint32 *)&elem->hash = hash;
     169      443242 :     for (j = 0;; j++) {
     170      443329 :       size_t idx = (hash + j) % GPR_ARRAY_SIZE(g_static_strtab);
     171      443329 :       if (g_static_strtab[idx] == NULL) {
     172      300324 :         g_static_strtab[idx] = &grpc_static_mdstr_table[i];
     173      300237 :         break;
     174             :       }
     175      143005 :     }
     176      300324 :     if (j > g_static_strtab_maxprobe) {
     177       13079 :       g_static_strtab_maxprobe = j;
     178             :     }
     179             :   }
     180      272707 :   for (i = 0; i < GRPC_STATIC_MDELEM_COUNT; i++) {
     181      269256 :     grpc_mdelem *elem = &grpc_static_mdelem_table[i];
     182      269256 :     grpc_mdstr *key =
     183      269256 :         &grpc_static_mdstr_table[grpc_static_metadata_elem_indices[2 * i + 0]];
     184      269256 :     grpc_mdstr *value =
     185      269256 :         &grpc_static_mdstr_table[grpc_static_metadata_elem_indices[2 * i + 1]];
     186      269256 :     gpr_uint32 hash = GRPC_MDSTR_KV_HASH(key->hash, value->hash);
     187      269256 :     *(grpc_mdstr **)&elem->key = key;
     188      269256 :     *(grpc_mdstr **)&elem->value = value;
     189      397711 :     for (j = 0;; j++) {
     190      397789 :       size_t idx = (hash + j) % GPR_ARRAY_SIZE(g_static_mdtab);
     191      397789 :       if (g_static_mdtab[idx] == NULL) {
     192      269256 :         g_static_mdtab[idx] = elem;
     193      269178 :         break;
     194             :       }
     195      128533 :     }
     196      269256 :     if (j > g_static_mdtab_maxprobe) {
     197       12649 :       g_static_mdtab_maxprobe = j;
     198             :     }
     199             :   }
     200             :   /* initialize shards */
     201      113915 :   for (i = 0; i < STRTAB_SHARD_COUNT; i++) {
     202      110432 :     strtab_shard *shard = &g_strtab_shard[i];
     203      110464 :     gpr_mu_init(&shard->mu);
     204      110464 :     shard->count = 0;
     205      110464 :     shard->capacity = INITIAL_STRTAB_CAPACITY;
     206      110464 :     shard->strs = gpr_malloc(sizeof(*shard->strs) * shard->capacity);
     207      110464 :     memset(shard->strs, 0, sizeof(*shard->strs) * shard->capacity);
     208             :   }
     209       58683 :   for (i = 0; i < MDTAB_SHARD_COUNT; i++) {
     210       55216 :     mdtab_shard *shard = &g_mdtab_shard[i];
     211       55232 :     gpr_mu_init(&shard->mu);
     212       55232 :     shard->count = 0;
     213       55232 :     shard->free = 0;
     214       55232 :     shard->capacity = INITIAL_MDTAB_CAPACITY;
     215       55232 :     shard->elems = gpr_malloc(sizeof(*shard->elems) * shard->capacity);
     216       55232 :     memset(shard->elems, 0, sizeof(*shard->elems) * shard->capacity);
     217             :   }
     218        3452 : }
     219             : 
     220        3450 : void grpc_mdctx_global_shutdown(void) {
     221             :   size_t i;
     222       58650 :   for (i = 0; i < MDTAB_SHARD_COUNT; i++) {
     223       55200 :     mdtab_shard *shard = &g_mdtab_shard[i];
     224       55200 :     gpr_mu_destroy(&shard->mu);
     225       55200 :     gc_mdtab(shard);
     226             :     /* TODO(ctiller): GPR_ASSERT(shard->count == 0); */
     227       55200 :     if (shard->count != 0) {
     228          40 :       gpr_log(GPR_DEBUG, "WARNING: %d metadata elements were leaked",
     229             :               shard->count);
     230             :     }
     231       55200 :     gpr_free(shard->elems);
     232             :   }
     233      113850 :   for (i = 0; i < STRTAB_SHARD_COUNT; i++) {
     234      110400 :     strtab_shard *shard = &g_strtab_shard[i];
     235      110400 :     gpr_mu_destroy(&shard->mu);
     236             :     /* TODO(ctiller): GPR_ASSERT(shard->count == 0); */
     237      110400 :     if (shard->count != 0) {
     238          46 :       gpr_log(GPR_DEBUG, "WARNING: %d metadata strings were leaked",
     239             :               shard->count);
     240             :     }
     241      110400 :     gpr_free(shard->strs);
     242             :   }
     243        3450 : }
     244             : 
     245    58900763 : static int is_mdstr_static(grpc_mdstr *s) {
     246    58915824 :   return s >= &grpc_static_mdstr_table[0] &&
     247             :          s < &grpc_static_mdstr_table[GRPC_STATIC_MDSTR_COUNT];
     248             : }
     249             : 
     250   129403276 : static int is_mdelem_static(grpc_mdelem *e) {
     251   129410320 :   return e >= &grpc_static_mdelem_table[0] &&
     252             :          e < &grpc_static_mdelem_table[GRPC_STATIC_MDELEM_COUNT];
     253             : }
     254             : 
     255     6882595 : static void ref_md_locked(mdtab_shard *shard,
     256             :                           internal_metadata *md DEBUG_ARGS) {
     257             : #ifdef GRPC_METADATA_REFCOUNT_DEBUG
     258             :   gpr_log(file, line, GPR_LOG_SEVERITY_DEBUG,
     259             :           "ELM   REF:%p:%d->%d: '%s' = '%s'", md,
     260             :           gpr_atm_no_barrier_load(&md->refcnt),
     261             :           gpr_atm_no_barrier_load(&md->refcnt) + 1,
     262             :           grpc_mdstr_as_c_string((grpc_mdstr *)md->key),
     263             :           grpc_mdstr_as_c_string((grpc_mdstr *)md->value));
     264             : #endif
     265     6882595 :   if (0 == gpr_atm_no_barrier_fetch_add(&md->refcnt, 2)) {
     266      613449 :     shard->free--;
     267             :   } else {
     268     6269146 :     GPR_ASSERT(1 != gpr_atm_no_barrier_fetch_add(&md->refcnt, -1));
     269             :   }
     270     6882595 : }
     271             : 
     272         433 : static void grow_strtab(strtab_shard *shard) {
     273         433 :   size_t capacity = shard->capacity * 2;
     274             :   size_t i;
     275             :   internal_string **strtab;
     276             :   internal_string *s, *next;
     277             : 
     278             :   GPR_TIMER_BEGIN("grow_strtab", 0);
     279             : 
     280         433 :   strtab = gpr_malloc(sizeof(internal_string *) * capacity);
     281         433 :   memset(strtab, 0, sizeof(internal_string *) * capacity);
     282             : 
     283       10281 :   for (i = 0; i < shard->capacity; i++) {
     284       29977 :     for (s = shard->strs[i]; s; s = next) {
     285       20129 :       size_t idx = TABLE_IDX(s->hash, LOG2_STRTAB_SHARD_COUNT, capacity);
     286       20129 :       next = s->bucket_next;
     287       20129 :       s->bucket_next = strtab[idx];
     288       20129 :       strtab[idx] = s;
     289             :     }
     290             :   }
     291             : 
     292         433 :   gpr_free(shard->strs);
     293         433 :   shard->strs = strtab;
     294         433 :   shard->capacity = capacity;
     295             : 
     296             :   GPR_TIMER_END("grow_strtab", 0);
     297         433 : }
     298             : 
     299     2488764 : static void internal_destroy_string(strtab_shard *shard, internal_string *is) {
     300             :   internal_string **prev_next;
     301             :   internal_string *cur;
     302             :   GPR_TIMER_BEGIN("internal_destroy_string", 0);
     303     2488764 :   if (is->has_base64_and_huffman_encoded) {
     304         108 :     gpr_slice_unref(is->base64_and_huffman);
     305             :   }
     306     8436895 :   for (prev_next = &shard->strs[TABLE_IDX(is->hash, LOG2_STRTAB_SHARD_COUNT,
     307             :                                           shard->capacity)],
     308     2488764 :       cur = *prev_next;
     309      970603 :        cur != is; prev_next = &cur->bucket_next, cur = cur->bucket_next)
     310             :     ;
     311     2488764 :   *prev_next = cur->bucket_next;
     312     2488764 :   shard->count--;
     313     2488764 :   gpr_free(is);
     314             :   GPR_TIMER_END("internal_destroy_string", 0);
     315     2488764 : }
     316             : 
     317     1285421 : static void slice_ref(void *p) {
     318     1285421 :   internal_string *is =
     319             :       (internal_string *)((char *)p - offsetof(internal_string, refcount));
     320     1285421 :   GRPC_MDSTR_REF((grpc_mdstr *)(is));
     321     1285421 : }
     322             : 
     323     1285421 : static void slice_unref(void *p) {
     324     1285421 :   internal_string *is =
     325             :       (internal_string *)((char *)p - offsetof(internal_string, refcount));
     326     1285421 :   GRPC_MDSTR_UNREF((grpc_mdstr *)(is));
     327     1285421 : }
     328             : 
     329     8245962 : grpc_mdstr *grpc_mdstr_from_string(const char *str) {
     330     8245962 :   return grpc_mdstr_from_buffer((const gpr_uint8 *)str, strlen(str));
     331             : }
     332             : 
     333       52522 : grpc_mdstr *grpc_mdstr_from_slice(gpr_slice slice) {
     334       78710 :   grpc_mdstr *result = grpc_mdstr_from_buffer(GPR_SLICE_START_PTR(slice),
     335       78710 :                                               GPR_SLICE_LENGTH(slice));
     336       52522 :   gpr_slice_unref(slice);
     337       52522 :   return result;
     338             : }
     339             : 
     340    17902017 : grpc_mdstr *grpc_mdstr_from_buffer(const gpr_uint8 *buf, size_t length) {
     341    17902017 :   gpr_uint32 hash = gpr_murmur_hash3(buf, length, g_hash_seed);
     342             :   internal_string *s;
     343    17903211 :   strtab_shard *shard =
     344    17903211 :       &g_strtab_shard[SHARD_IDX(hash, LOG2_STRTAB_SHARD_COUNT)];
     345             :   size_t i;
     346             :   size_t idx;
     347             : 
     348             :   GPR_TIMER_BEGIN("grpc_mdstr_from_buffer", 0);
     349             : 
     350             :   /* search for a static string */
     351    36467907 :   for (i = 0; i <= g_static_strtab_maxprobe; i++) {
     352             :     grpc_mdstr *ss;
     353    35707699 :     idx = (hash + i) % GPR_ARRAY_SIZE(g_static_strtab);
     354    35707699 :     ss = g_static_strtab[idx];
     355    35707699 :     if (ss == NULL) break;
     356    29567453 :     if (ss->hash == hash && GPR_SLICE_LENGTH(ss->slice) == length &&
     357     5501264 :         0 == memcmp(buf, GPR_SLICE_START_PTR(ss->slice), length)) {
     358             :       GPR_TIMER_END("grpc_mdstr_from_buffer", 0);
     359     5501493 :       return ss;
     360             :     }
     361             :   }
     362             : 
     363    12401718 :   gpr_mu_lock(&shard->mu);
     364             : 
     365             :   /* search for an existing string */
     366    12402214 :   idx = TABLE_IDX(hash, LOG2_STRTAB_SHARD_COUNT, shard->capacity);
     367    19077010 :   for (s = shard->strs[idx]; s; s = s->bucket_next) {
     368    26501238 :     if (s->hash == hash && GPR_SLICE_LENGTH(s->slice) == length &&
     369     9913221 :         0 == memcmp(buf, GPR_SLICE_START_PTR(s->slice), length)) {
     370     9913221 :       GRPC_MDSTR_REF((grpc_mdstr *)s);
     371     9913221 :       gpr_mu_unlock(&shard->mu);
     372             :       GPR_TIMER_END("grpc_mdstr_from_buffer", 0);
     373     9913221 :       return (grpc_mdstr *)s;
     374             :     }
     375             :   }
     376             : 
     377             :   /* not found: create a new string */
     378     2488993 :   if (length + 1 < GPR_SLICE_INLINED_SIZE) {
     379             :     /* string data goes directly into the slice */
     380     2478268 :     s = gpr_malloc(sizeof(internal_string));
     381     2478268 :     gpr_atm_rel_store(&s->refcnt, 2);
     382     2478268 :     s->slice.refcount = NULL;
     383     2478268 :     memcpy(s->slice.data.inlined.bytes, buf, length);
     384     2478268 :     s->slice.data.inlined.bytes[length] = 0;
     385     2478268 :     s->slice.data.inlined.length = (gpr_uint8)length;
     386             :   } else {
     387             :     /* string data goes after the internal_string header, and we +1 for null
     388             :        terminator */
     389       10725 :     s = gpr_malloc(sizeof(internal_string) + length + 1);
     390       10725 :     gpr_atm_rel_store(&s->refcnt, 2);
     391       10725 :     s->refcount.ref = slice_ref;
     392       10725 :     s->refcount.unref = slice_unref;
     393       10725 :     s->slice.refcount = &s->refcount;
     394       10725 :     s->slice.data.refcounted.bytes = (gpr_uint8 *)(s + 1);
     395       10725 :     s->slice.data.refcounted.length = length;
     396       10725 :     memcpy(s->slice.data.refcounted.bytes, buf, length);
     397             :     /* add a null terminator for cheap c string conversion when desired */
     398       10725 :     s->slice.data.refcounted.bytes[length] = 0;
     399             :   }
     400     2488993 :   s->has_base64_and_huffman_encoded = 0;
     401     2488993 :   s->hash = hash;
     402     2488993 :   s->bucket_next = shard->strs[idx];
     403     2488993 :   shard->strs[idx] = s;
     404             : 
     405     2488993 :   shard->count++;
     406             : 
     407     2488993 :   if (shard->count > shard->capacity * 2) {
     408         433 :     grow_strtab(shard);
     409             :   }
     410             : 
     411     2488993 :   gpr_mu_unlock(&shard->mu);
     412             :   GPR_TIMER_END("grpc_mdstr_from_buffer", 0);
     413             : 
     414     2488993 :   return (grpc_mdstr *)s;
     415             : }
     416             : 
     417      180863 : static void gc_mdtab(mdtab_shard *shard) {
     418             :   size_t i;
     419             :   internal_metadata **prev_next;
     420             :   internal_metadata *md, *next;
     421             : 
     422             :   GPR_TIMER_BEGIN("gc_mdtab", 0);
     423     1364531 :   for (i = 0; i < shard->capacity; i++) {
     424     1183668 :     prev_next = &shard->elems[i];
     425     3237940 :     for (md = shard->elems[i]; md; md = next) {
     426     2054272 :       void *user_data = (void *)gpr_atm_no_barrier_load(&md->user_data);
     427     2054272 :       next = md->bucket_next;
     428     2054272 :       if (gpr_atm_acq_load(&md->refcnt) == 0) {
     429     1485648 :         GRPC_MDSTR_UNREF((grpc_mdstr *)md->key);
     430     1485648 :         GRPC_MDSTR_UNREF((grpc_mdstr *)md->value);
     431     1485648 :         if (md->user_data) {
     432        1621 :           ((destroy_user_data_func)gpr_atm_no_barrier_load(
     433             :               &md->destroy_user_data))(user_data);
     434             :         }
     435     1485648 :         gpr_free(md);
     436     1485648 :         *prev_next = next;
     437     1485648 :         shard->free--;
     438     1485648 :         shard->count--;
     439             :       } else {
     440      568624 :         prev_next = &md->bucket_next;
     441             :       }
     442             :     }
     443             :   }
     444             :   GPR_TIMER_END("gc_mdtab", 0);
     445      180863 : }
     446             : 
     447         182 : static void grow_mdtab(mdtab_shard *shard) {
     448         182 :   size_t capacity = shard->capacity * 2;
     449             :   size_t i;
     450             :   internal_metadata **mdtab;
     451             :   internal_metadata *md, *next;
     452             :   gpr_uint32 hash;
     453             : 
     454             :   GPR_TIMER_BEGIN("grow_mdtab", 0);
     455             : 
     456         182 :   mdtab = gpr_malloc(sizeof(internal_metadata *) * capacity);
     457         182 :   memset(mdtab, 0, sizeof(internal_metadata *) * capacity);
     458             : 
     459        8652 :   for (i = 0; i < shard->capacity; i++) {
     460       25606 :     for (md = shard->elems[i]; md; md = next) {
     461             :       size_t idx;
     462       17126 :       hash = GRPC_MDSTR_KV_HASH(md->key->hash, md->value->hash);
     463       17126 :       next = md->bucket_next;
     464       17126 :       idx = TABLE_IDX(hash, LOG2_MDTAB_SHARD_COUNT, capacity);
     465       17126 :       md->bucket_next = mdtab[idx];
     466       17126 :       mdtab[idx] = md;
     467             :     }
     468             :   }
     469             : 
     470         182 :   gpr_free(shard->elems);
     471         182 :   shard->elems = mdtab;
     472         182 :   shard->capacity = capacity;
     473             : 
     474             :   GPR_TIMER_END("grow_mdtab", 0);
     475         182 : }
     476             : 
     477      125845 : static void rehash_mdtab(mdtab_shard *shard) {
     478      125845 :   if (shard->free > shard->capacity / 4) {
     479      125663 :     gc_mdtab(shard);
     480             :   } else {
     481         182 :     grow_mdtab(shard);
     482             :   }
     483      125845 : }
     484             : 
     485    10522552 : grpc_mdelem *grpc_mdelem_from_metadata_strings(grpc_mdstr *mkey,
     486             :                                                grpc_mdstr *mvalue) {
     487    10516601 :   internal_string *key = (internal_string *)mkey;
     488    10516601 :   internal_string *value = (internal_string *)mvalue;
     489    10522552 :   gpr_uint32 hash = GRPC_MDSTR_KV_HASH(mkey->hash, mvalue->hash);
     490             :   internal_metadata *md;
     491    10522552 :   mdtab_shard *shard = &g_mdtab_shard[SHARD_IDX(hash, LOG2_MDTAB_SHARD_COUNT)];
     492             :   size_t i;
     493             :   size_t idx;
     494             : 
     495             :   GPR_TIMER_BEGIN("grpc_mdelem_from_metadata_strings", 0);
     496             : 
     497    10528414 :   if (is_mdstr_static(mkey) && is_mdstr_static(mvalue)) {
     498     2919343 :     for (i = 0; i <= g_static_mdtab_maxprobe; i++) {
     499             :       grpc_mdelem *smd;
     500     2924462 :       idx = (hash + i) % GPR_ARRAY_SIZE(g_static_mdtab);
     501     2924462 :       smd = g_static_mdtab[idx];
     502     2924462 :       if (smd == NULL) break;
     503     2924056 :       if (smd->key == mkey && smd->value == mvalue) {
     504             :         GPR_TIMER_END("grpc_mdelem_from_metadata_strings", 0);
     505     2153988 :         return smd;
     506             :       }
     507             :     }
     508             :   }
     509             : 
     510     8368500 :   gpr_mu_lock(&shard->mu);
     511             : 
     512     8368456 :   idx = TABLE_IDX(hash, LOG2_MDTAB_SHARD_COUNT, shard->capacity);
     513             :   /* search for an existing pair */
     514    17615126 :   for (md = shard->elems[idx]; md; md = md->bucket_next) {
     515    16129265 :     if (md->key == key && md->value == value) {
     516     6882595 :       REF_MD_LOCKED(shard, md);
     517     6882595 :       GRPC_MDSTR_UNREF((grpc_mdstr *)key);
     518     6882595 :       GRPC_MDSTR_UNREF((grpc_mdstr *)value);
     519     6882595 :       gpr_mu_unlock(&shard->mu);
     520             :       GPR_TIMER_END("grpc_mdelem_from_metadata_strings", 0);
     521     6882595 :       return (grpc_mdelem *)md;
     522             :     }
     523             :   }
     524             : 
     525             :   /* not found: create a new pair */
     526     1485861 :   md = gpr_malloc(sizeof(internal_metadata));
     527     1485861 :   gpr_atm_rel_store(&md->refcnt, 2);
     528     1485861 :   md->key = key;
     529     1485861 :   md->value = value;
     530     1485861 :   md->user_data = 0;
     531     1485861 :   md->destroy_user_data = 0;
     532     1485861 :   md->bucket_next = shard->elems[idx];
     533     1485861 :   shard->elems[idx] = md;
     534     1485861 :   gpr_mu_init(&md->mu_user_data);
     535             : #ifdef GRPC_METADATA_REFCOUNT_DEBUG
     536             :   gpr_log(GPR_DEBUG, "ELM   NEW:%p:%d: '%s' = '%s'", md,
     537             :           gpr_atm_no_barrier_load(&md->refcnt),
     538             :           grpc_mdstr_as_c_string((grpc_mdstr *)md->key),
     539             :           grpc_mdstr_as_c_string((grpc_mdstr *)md->value));
     540             : #endif
     541     1485861 :   shard->count++;
     542             : 
     543     1485861 :   if (shard->count > shard->capacity * 2) {
     544      125845 :     rehash_mdtab(shard);
     545             :   }
     546             : 
     547     1485861 :   gpr_mu_unlock(&shard->mu);
     548             : 
     549             :   GPR_TIMER_END("grpc_mdelem_from_metadata_strings", 0);
     550             : 
     551     1485861 :   return (grpc_mdelem *)md;
     552             : }
     553             : 
     554     1413878 : grpc_mdelem *grpc_mdelem_from_strings(const char *key, const char *value) {
     555     1413878 :   return grpc_mdelem_from_metadata_strings(grpc_mdstr_from_string(key),
     556             :                                            grpc_mdstr_from_string(value));
     557             : }
     558             : 
     559       26185 : grpc_mdelem *grpc_mdelem_from_slices(gpr_slice key, gpr_slice value) {
     560       26185 :   return grpc_mdelem_from_metadata_strings(grpc_mdstr_from_slice(key),
     561             :                                            grpc_mdstr_from_slice(value));
     562             : }
     563             : 
     564     1565144 : grpc_mdelem *grpc_mdelem_from_string_and_buffer(const char *key,
     565             :                                                 const gpr_uint8 *value,
     566             :                                                 size_t value_length) {
     567     1565144 :   return grpc_mdelem_from_metadata_strings(
     568             :       grpc_mdstr_from_string(key), grpc_mdstr_from_buffer(value, value_length));
     569             : }
     570             : 
     571    45044945 : grpc_mdelem *grpc_mdelem_ref(grpc_mdelem *gmd DEBUG_ARGS) {
     572    45042517 :   internal_metadata *md = (internal_metadata *)gmd;
     573    45044945 :   if (is_mdelem_static(gmd)) return gmd;
     574             : #ifdef GRPC_METADATA_REFCOUNT_DEBUG
     575             :   gpr_log(file, line, GPR_LOG_SEVERITY_DEBUG,
     576             :           "ELM   REF:%p:%d->%d: '%s' = '%s'", md,
     577             :           gpr_atm_no_barrier_load(&md->refcnt),
     578             :           gpr_atm_no_barrier_load(&md->refcnt) + 1,
     579             :           grpc_mdstr_as_c_string((grpc_mdstr *)md->key),
     580             :           grpc_mdstr_as_c_string((grpc_mdstr *)md->value));
     581             : #endif
     582             :   /* we can assume the ref count is >= 1 as the application is calling
     583             :      this function - meaning that no adjustment to mdtab_free is necessary,
     584             :      simplifying the logic here to be just an atomic increment */
     585             :   /* use C assert to have this removed in opt builds */
     586    20919629 :   assert(gpr_atm_no_barrier_load(&md->refcnt) >= 2);
     587    20919629 :   gpr_atm_no_barrier_fetch_add(&md->refcnt, 1);
     588    20919629 :   return gmd;
     589             : }
     590             : 
     591    79110995 : void grpc_mdelem_unref(grpc_mdelem *gmd DEBUG_ARGS) {
     592    79106573 :   internal_metadata *md = (internal_metadata *)gmd;
     593    79110995 :   if (!md) return;
     594    79110995 :   if (is_mdelem_static(gmd)) return;
     595             : #ifdef GRPC_METADATA_REFCOUNT_DEBUG
     596             :   gpr_log(file, line, GPR_LOG_SEVERITY_DEBUG,
     597             :           "ELM UNREF:%p:%d->%d: '%s' = '%s'", md,
     598             :           gpr_atm_no_barrier_load(&md->refcnt),
     599             :           gpr_atm_no_barrier_load(&md->refcnt) - 1,
     600             :           grpc_mdstr_as_c_string((grpc_mdstr *)md->key),
     601             :           grpc_mdstr_as_c_string((grpc_mdstr *)md->value));
     602             : #endif
     603    29279824 :   if (2 == gpr_atm_full_fetch_add(&md->refcnt, -1)) {
     604     2099219 :     gpr_uint32 hash = GRPC_MDSTR_KV_HASH(md->key->hash, md->value->hash);
     605     2099188 :     mdtab_shard *shard =
     606     2099219 :         &g_mdtab_shard[SHARD_IDX(hash, LOG2_MDTAB_SHARD_COUNT)];
     607             :     GPR_TIMER_BEGIN("grpc_mdelem_unref.to_zero", 0);
     608     2099219 :     gpr_mu_lock(&shard->mu);
     609     2099219 :     if (1 == gpr_atm_no_barrier_load(&md->refcnt)) {
     610     2099219 :       shard->free++;
     611     2099219 :       gpr_atm_no_barrier_store(&md->refcnt, 0);
     612             :     }
     613     2099219 :     gpr_mu_unlock(&shard->mu);
     614             :     GPR_TIMER_END("grpc_mdelem_unref.to_zero", 0);
     615             :   }
     616             : }
     617             : 
     618     9204428 : const char *grpc_mdstr_as_c_string(grpc_mdstr *s) {
     619     9204428 :   return (const char *)GPR_SLICE_START_PTR(s->slice);
     620             : }
     621             : 
     622    17331855 : grpc_mdstr *grpc_mdstr_ref(grpc_mdstr *gs DEBUG_ARGS) {
     623    17330090 :   internal_string *s = (internal_string *)gs;
     624    17331855 :   if (is_mdstr_static(gs)) return gs;
     625    17187844 :   GPR_ASSERT(gpr_atm_full_fetch_add(&s->refcnt, 1) != 0);
     626    17186609 :   return gs;
     627             : }
     628             : 
     629    24365450 : void grpc_mdstr_unref(grpc_mdstr *gs DEBUG_ARGS) {
     630    24363967 :   internal_string *s = (internal_string *)gs;
     631    48730886 :   if (is_mdstr_static(gs)) return;
     632    19675450 :   if (2 == gpr_atm_full_fetch_add(&s->refcnt, -1)) {
     633     2488764 :     strtab_shard *shard =
     634     2488764 :         &g_strtab_shard[SHARD_IDX(s->hash, LOG2_STRTAB_SHARD_COUNT)];
     635     2488764 :     gpr_mu_lock(&shard->mu);
     636     2488764 :     if (1 == gpr_atm_no_barrier_load(&s->refcnt)) {
     637     2488764 :       internal_destroy_string(shard, s);
     638             :     }
     639     2488764 :     gpr_mu_unlock(&shard->mu);
     640             :   }
     641             : }
     642             : 
     643     5907854 : void *grpc_mdelem_get_user_data(grpc_mdelem *md, void (*destroy_func)(void *)) {
     644     5907667 :   internal_metadata *im = (internal_metadata *)md;
     645             :   void *result;
     646     5907854 :   if (is_mdelem_static(md)) {
     647     4335573 :     return (void *)grpc_static_mdelem_user_data[md - grpc_static_mdelem_table];
     648             :   }
     649     1571726 :   if (gpr_atm_acq_load(&im->destroy_user_data) == (gpr_atm)destroy_func) {
     650     1570081 :     return (void *)gpr_atm_no_barrier_load(&im->user_data);
     651             :   } else {
     652        1638 :     return NULL;
     653             :   }
     654             :   return result;
     655             : }
     656             : 
     657        1647 : void grpc_mdelem_set_user_data(grpc_mdelem *md, void (*destroy_func)(void *),
     658             :                                void *user_data) {
     659        1640 :   internal_metadata *im = (internal_metadata *)md;
     660        1647 :   GPR_ASSERT(!is_mdelem_static(md));
     661        1647 :   GPR_ASSERT((user_data == NULL) == (destroy_func == NULL));
     662        1647 :   gpr_mu_lock(&im->mu_user_data);
     663        1647 :   if (gpr_atm_no_barrier_load(&im->destroy_user_data)) {
     664             :     /* user data can only be set once */
     665           1 :     gpr_mu_unlock(&im->mu_user_data);
     666           1 :     if (destroy_func != NULL) {
     667           1 :       destroy_func(user_data);
     668             :     }
     669        1648 :     return;
     670             :   }
     671        1646 :   gpr_atm_no_barrier_store(&im->user_data, (gpr_atm)user_data);
     672        1646 :   gpr_atm_rel_store(&im->destroy_user_data, (gpr_atm)destroy_func);
     673        1646 :   gpr_mu_unlock(&im->mu_user_data);
     674             : }
     675             : 
     676         127 : gpr_slice grpc_mdstr_as_base64_encoded_and_huffman_compressed(grpc_mdstr *gs) {
     677         123 :   internal_string *s = (internal_string *)gs;
     678             :   gpr_slice slice;
     679         123 :   strtab_shard *shard =
     680         127 :       &g_strtab_shard[SHARD_IDX(s->hash, LOG2_STRTAB_SHARD_COUNT)];
     681         127 :   gpr_mu_lock(&shard->mu);
     682         127 :   if (!s->has_base64_and_huffman_encoded) {
     683         112 :     s->base64_and_huffman =
     684             :         grpc_chttp2_base64_encode_and_huffman_compress(s->slice);
     685         112 :     s->has_base64_and_huffman_encoded = 1;
     686             :   }
     687         127 :   slice = s->base64_and_huffman;
     688         127 :   gpr_mu_unlock(&shard->mu);
     689         127 :   return slice;
     690             : }
     691             : 
     692     3130158 : static int conforms_to(grpc_mdstr *s, const gpr_uint8 *legal_bits) {
     693     3130158 :   const gpr_uint8 *p = GPR_SLICE_START_PTR(s->slice);
     694     3130158 :   const gpr_uint8 *e = GPR_SLICE_END_PTR(s->slice);
     695    39159932 :   for (; p != e; p++) {
     696    36029774 :     int idx = *p;
     697    36029774 :     int byte = idx / 8;
     698    36029774 :     int bit = idx % 8;
     699    36029774 :     if ((legal_bits[byte] & (1 << bit)) == 0) return 0;
     700             :   }
     701     3130016 :   return 1;
     702             : }
     703             : 
     704     1565144 : int grpc_mdstr_is_legal_header(grpc_mdstr *s) {
     705             :   static const gpr_uint8 legal_header_bits[256 / 8] = {
     706             :       0x00, 0x00, 0x00, 0x00, 0x00, 0x20, 0xff, 0x03, 0x00, 0x00, 0x00,
     707             :       0x80, 0xfe, 0xff, 0xff, 0x07, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
     708             :       0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00};
     709     1565144 :   return conforms_to(s, legal_header_bits);
     710             : }
     711             : 
     712     1565014 : int grpc_mdstr_is_legal_nonbin_header(grpc_mdstr *s) {
     713             :   static const gpr_uint8 legal_header_bits[256 / 8] = {
     714             :       0x00, 0x00, 0x00, 0x00, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
     715             :       0xff, 0xff, 0xff, 0xff, 0x7f, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
     716             :       0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00};
     717     1565014 :   return conforms_to(s, legal_header_bits);
     718             : }
     719             : 
     720     1565144 : int grpc_mdstr_is_bin_suffixed(grpc_mdstr *s) {
     721             :   /* TODO(ctiller): consider caching this */
     722     2086918 :   return grpc_is_binary_header((const char *)GPR_SLICE_START_PTR(s->slice),
     723     2086918 :                                GPR_SLICE_LENGTH(s->slice));
     724             : }

Generated by: LCOV version 1.11