LCOV - code coverage report
Current view: top level - src/core/transport - metadata.c (source / functions) Hit Total Coverage
Test: tmp.zDYK9MVh93 Lines: 316 320 98.8 %
Date: 2015-10-10 Functions: 43 43 100.0 %

          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/iomgr/sockaddr.h"
      35             : #include "src/core/transport/metadata.h"
      36             : 
      37             : #include <assert.h>
      38             : #include <stddef.h>
      39             : #include <string.h>
      40             : 
      41             : #include <grpc/support/alloc.h>
      42             : #include <grpc/support/atm.h>
      43             : #include <grpc/support/log.h>
      44             : #include "src/core/support/murmur_hash.h"
      45             : #include "src/core/transport/chttp2/bin_encoder.h"
      46             : #include <grpc/support/time.h>
      47             : 
      48             : #define INITIAL_STRTAB_CAPACITY 4
      49             : #define INITIAL_MDTAB_CAPACITY 4
      50             : 
      51             : #ifdef GRPC_METADATA_REFCOUNT_DEBUG
      52             : #define DEBUG_ARGS , const char *file, int line
      53             : #define FWD_DEBUG_ARGS , file, line
      54             : #define INTERNAL_STRING_REF(s) internal_string_ref((s), __FILE__, __LINE__)
      55             : #define INTERNAL_STRING_UNREF(s) internal_string_unref((s), __FILE__, __LINE__)
      56             : #define REF_MD_LOCKED(s) ref_md_locked((s), __FILE__, __LINE__)
      57             : #else
      58             : #define DEBUG_ARGS
      59             : #define FWD_DEBUG_ARGS
      60             : #define INTERNAL_STRING_REF(s) internal_string_ref((s))
      61             : #define INTERNAL_STRING_UNREF(s) internal_string_unref((s))
      62             : #define REF_MD_LOCKED(s) ref_md_locked((s))
      63             : #endif
      64             : 
      65             : typedef struct internal_string {
      66             :   /* must be byte compatible with grpc_mdstr */
      67             :   gpr_slice slice;
      68             :   gpr_uint32 hash;
      69             : 
      70             :   /* private only data */
      71             :   gpr_uint32 refs;
      72             :   gpr_uint8 has_base64_and_huffman_encoded;
      73             :   gpr_slice_refcount refcount;
      74             : 
      75             :   gpr_slice base64_and_huffman;
      76             : 
      77             :   grpc_mdctx *context;
      78             : 
      79             :   struct internal_string *bucket_next;
      80             : } internal_string;
      81             : 
      82             : typedef struct internal_metadata {
      83             :   /* must be byte compatible with grpc_mdelem */
      84             :   internal_string *key;
      85             :   internal_string *value;
      86             : 
      87             :   gpr_atm refcnt;
      88             : 
      89             :   /* private only data */
      90             :   gpr_mu mu_user_data;
      91             :   void *user_data;
      92             :   void (*destroy_user_data)(void *user_data);
      93             : 
      94             :   grpc_mdctx *context;
      95             :   struct internal_metadata *bucket_next;
      96             : } internal_metadata;
      97             : 
      98             : struct grpc_mdctx {
      99             :   gpr_uint32 hash_seed;
     100             :   int refs;
     101             : 
     102             :   gpr_mu mu;
     103             : 
     104             :   internal_string **strtab;
     105             :   size_t strtab_count;
     106             :   size_t strtab_capacity;
     107             : 
     108             :   internal_metadata **mdtab;
     109             :   size_t mdtab_count;
     110             :   size_t mdtab_free;
     111             :   size_t mdtab_capacity;
     112             : };
     113             : 
     114             : static void internal_string_ref(internal_string *s DEBUG_ARGS);
     115             : static void internal_string_unref(internal_string *s DEBUG_ARGS);
     116             : static void discard_metadata(grpc_mdctx *ctx);
     117             : static void gc_mdtab(grpc_mdctx *ctx);
     118             : static void metadata_context_destroy_locked(grpc_mdctx *ctx);
     119             : 
     120    23593136 : static void lock(grpc_mdctx *ctx) { gpr_mu_lock(&ctx->mu); }
     121             : 
     122    23654471 : static void unlock(grpc_mdctx *ctx) {
     123             :   /* If the context has been orphaned we'd like to delete it soon. We check
     124             :      conditions in unlock as it signals the end of mutations on a context.
     125             : 
     126             :      We need to ensure all grpc_mdelem and grpc_mdstr elements have been deleted
     127             :      first. This is equivalent to saying that both tables have zero counts,
     128             :      which is equivalent to saying that strtab_count is zero (as mdelem's MUST
     129             :      reference an mdstr for their key and value slots).
     130             : 
     131             :      To encourage that to happen, we start discarding zero reference count
     132             :      mdelems on every unlock (instead of the usual 'I'm too loaded' trigger
     133             :      case), since otherwise we can be stuck waiting for a garbage collection
     134             :      that will never happen. */
     135    23654471 :   if (ctx->refs == 0) {
     136             : /* uncomment if you're having trouble diagnosing an mdelem leak to make
     137             :    things clearer (slows down destruction a lot, however) */
     138             : #ifdef GRPC_METADATA_REFCOUNT_DEBUG
     139             :     gc_mdtab(ctx);
     140             : #endif
     141        4476 :     if (ctx->mdtab_count && ctx->mdtab_count == ctx->mdtab_free) {
     142        4251 :       discard_metadata(ctx);
     143             :     }
     144        4476 :     if (ctx->strtab_count == 0) {
     145        4258 :       metadata_context_destroy_locked(ctx);
     146    23674751 :       return;
     147             :     }
     148             :   }
     149    23650213 :   gpr_mu_unlock(&ctx->mu);
     150             : }
     151             : 
     152      667228 : static void ref_md_locked(internal_metadata *md DEBUG_ARGS) {
     153             : #ifdef GRPC_METADATA_REFCOUNT_DEBUG
     154             :   gpr_log(file, line, GPR_LOG_SEVERITY_DEBUG,
     155             :           "ELM   REF:%p:%d->%d: '%s' = '%s'", md,
     156             :           gpr_atm_no_barrier_load(&md->refcnt),
     157             :           gpr_atm_no_barrier_load(&md->refcnt) + 1,
     158             :           grpc_mdstr_as_c_string((grpc_mdstr *)md->key),
     159             :           grpc_mdstr_as_c_string((grpc_mdstr *)md->value));
     160             : #endif
     161      667228 :   if (0 == gpr_atm_no_barrier_fetch_add(&md->refcnt, 1)) {
     162      108993 :     md->context->mdtab_free--;
     163             :   }
     164      667228 : }
     165             : 
     166        4258 : grpc_mdctx *grpc_mdctx_create_with_seed(gpr_uint32 seed) {
     167        4258 :   grpc_mdctx *ctx = gpr_malloc(sizeof(grpc_mdctx));
     168             : 
     169        4258 :   ctx->refs = 1;
     170        4258 :   ctx->hash_seed = seed;
     171        4258 :   gpr_mu_init(&ctx->mu);
     172        4258 :   ctx->strtab = gpr_malloc(sizeof(internal_string *) * INITIAL_STRTAB_CAPACITY);
     173        4258 :   memset(ctx->strtab, 0, sizeof(grpc_mdstr *) * INITIAL_STRTAB_CAPACITY);
     174        4258 :   ctx->strtab_count = 0;
     175        4258 :   ctx->strtab_capacity = INITIAL_STRTAB_CAPACITY;
     176        4258 :   ctx->mdtab = gpr_malloc(sizeof(internal_metadata *) * INITIAL_MDTAB_CAPACITY);
     177        4258 :   memset(ctx->mdtab, 0, sizeof(grpc_mdelem *) * INITIAL_MDTAB_CAPACITY);
     178        4258 :   ctx->mdtab_count = 0;
     179        4258 :   ctx->mdtab_capacity = INITIAL_MDTAB_CAPACITY;
     180        4258 :   ctx->mdtab_free = 0;
     181             : 
     182        4258 :   return ctx;
     183             : }
     184             : 
     185        4244 : grpc_mdctx *grpc_mdctx_create(void) {
     186             :   /* This seed is used to prevent remote connections from controlling hash table
     187             :    * collisions. It needs to be somewhat unpredictable to a remote connection.
     188             :    */
     189        4244 :   return grpc_mdctx_create_with_seed(
     190        4244 :       (gpr_uint32)gpr_now(GPR_CLOCK_REALTIME).tv_nsec);
     191             : }
     192             : 
     193        4251 : static void discard_metadata(grpc_mdctx *ctx) {
     194             :   size_t i;
     195             :   internal_metadata *next, *cur;
     196             : 
     197      263403 :   for (i = 0; i < ctx->mdtab_capacity; i++) {
     198      259152 :     cur = ctx->mdtab[i];
     199      828426 :     while (cur) {
     200      310122 :       GPR_ASSERT(gpr_atm_acq_load(&cur->refcnt) == 0);
     201      310121 :       next = cur->bucket_next;
     202      310121 :       INTERNAL_STRING_UNREF(cur->key);
     203      310118 :       INTERNAL_STRING_UNREF(cur->value);
     204      310118 :       if (cur->user_data) {
     205        8487 :         cur->destroy_user_data(cur->user_data);
     206             :       }
     207      310118 :       gpr_mu_destroy(&cur->mu_user_data);
     208      310119 :       gpr_free(cur);
     209      310122 :       cur = next;
     210      310122 :       ctx->mdtab_free--;
     211      310122 :       ctx->mdtab_count--;
     212             :     }
     213      259152 :     ctx->mdtab[i] = NULL;
     214             :   }
     215        4251 : }
     216             : 
     217        4258 : static void metadata_context_destroy_locked(grpc_mdctx *ctx) {
     218        4258 :   GPR_ASSERT(ctx->strtab_count == 0);
     219        4258 :   GPR_ASSERT(ctx->mdtab_count == 0);
     220        4258 :   GPR_ASSERT(ctx->mdtab_free == 0);
     221        4258 :   gpr_free(ctx->strtab);
     222        4258 :   gpr_free(ctx->mdtab);
     223        4258 :   gpr_mu_unlock(&ctx->mu);
     224        4258 :   gpr_mu_destroy(&ctx->mu);
     225        4258 :   gpr_free(ctx);
     226        4258 : }
     227             : 
     228        8715 : void grpc_mdctx_ref(grpc_mdctx *ctx) {
     229        8715 :   lock(ctx);
     230        8715 :   GPR_ASSERT(ctx->refs > 0);
     231        8715 :   ctx->refs++;
     232        8715 :   unlock(ctx);
     233        8715 : }
     234             : 
     235       12973 : void grpc_mdctx_unref(grpc_mdctx *ctx) {
     236       12973 :   lock(ctx);
     237       12973 :   GPR_ASSERT(ctx->refs > 0);
     238       12973 :   ctx->refs--;
     239       12973 :   unlock(ctx);
     240       12973 : }
     241             : 
     242       16148 : static void grow_strtab(grpc_mdctx *ctx) {
     243       16148 :   size_t capacity = ctx->strtab_capacity * 2;
     244             :   size_t i;
     245       16148 :   internal_string **strtab = gpr_malloc(sizeof(internal_string *) * capacity);
     246             :   internal_string *s, *next;
     247       16146 :   memset(strtab, 0, sizeof(internal_string *) * capacity);
     248             : 
     249      266304 :   for (i = 0; i < ctx->strtab_capacity; i++) {
     250      766229 :     for (s = ctx->strtab[i]; s; s = next) {
     251      516071 :       next = s->bucket_next;
     252      516071 :       s->bucket_next = strtab[s->hash % capacity];
     253      516071 :       strtab[s->hash % capacity] = s;
     254             :     }
     255             :   }
     256             : 
     257       16146 :   gpr_free(ctx->strtab);
     258       16147 :   ctx->strtab = strtab;
     259       16147 :   ctx->strtab_capacity = capacity;
     260       16147 : }
     261             : 
     262     2549240 : static void internal_destroy_string(internal_string *is) {
     263             :   internal_string **prev_next;
     264             :   internal_string *cur;
     265     2549240 :   grpc_mdctx *ctx = is->context;
     266     2549240 :   if (is->has_base64_and_huffman_encoded) {
     267         111 :     gpr_slice_unref(is->base64_and_huffman);
     268             :   }
     269     9486150 :   for (prev_next = &ctx->strtab[is->hash % ctx->strtab_capacity],
     270     2549245 :       cur = *prev_next;
     271     1838415 :        cur != is; prev_next = &cur->bucket_next, cur = cur->bucket_next)
     272             :     ;
     273     2549245 :   *prev_next = cur->bucket_next;
     274     2549245 :   ctx->strtab_count--;
     275     2549245 :   gpr_free(is);
     276     2549250 : }
     277             : 
     278     5313097 : static void internal_string_ref(internal_string *s DEBUG_ARGS) {
     279             : #ifdef GRPC_METADATA_REFCOUNT_DEBUG
     280             :   gpr_log(file, line, GPR_LOG_SEVERITY_DEBUG, "STR   REF:%p:%d->%d: '%s'", s,
     281             :           s->refs, s->refs + 1, grpc_mdstr_as_c_string((grpc_mdstr *)s));
     282             : #endif
     283     5313097 :   ++s->refs;
     284     5313097 : }
     285             : 
     286     7861825 : static void internal_string_unref(internal_string *s DEBUG_ARGS) {
     287             : #ifdef GRPC_METADATA_REFCOUNT_DEBUG
     288             :   gpr_log(file, line, GPR_LOG_SEVERITY_DEBUG, "STR UNREF:%p:%d->%d: '%s'", s,
     289             :           s->refs, s->refs - 1, grpc_mdstr_as_c_string((grpc_mdstr *)s));
     290             : #endif
     291     7861825 :   GPR_ASSERT(s->refs > 0);
     292     7861825 :   if (0 == --s->refs) {
     293     2549240 :     internal_destroy_string(s);
     294             :   }
     295     7861833 : }
     296             : 
     297       81468 : static void slice_ref(void *p) {
     298       81468 :   internal_string *is =
     299             :       (internal_string *)((char *)p - offsetof(internal_string, refcount));
     300       81468 :   grpc_mdctx *ctx = is->context;
     301       81468 :   lock(ctx);
     302       81468 :   INTERNAL_STRING_REF(is);
     303       81468 :   unlock(ctx);
     304       81468 : }
     305             : 
     306       81468 : static void slice_unref(void *p) {
     307       81468 :   internal_string *is =
     308             :       (internal_string *)((char *)p - offsetof(internal_string, refcount));
     309       81468 :   grpc_mdctx *ctx = is->context;
     310       81468 :   lock(ctx);
     311       81468 :   INTERNAL_STRING_UNREF(is);
     312       81468 :   unlock(ctx);
     313       81468 : }
     314             : 
     315     4510064 : grpc_mdstr *grpc_mdstr_from_string(grpc_mdctx *ctx, const char *str) {
     316     4510064 :   return grpc_mdstr_from_buffer(ctx, (const gpr_uint8 *)str, strlen(str));
     317             : }
     318             : 
     319         292 : grpc_mdstr *grpc_mdstr_from_slice(grpc_mdctx *ctx, gpr_slice slice) {
     320         428 :   grpc_mdstr *result = grpc_mdstr_from_buffer(ctx, GPR_SLICE_START_PTR(slice),
     321         428 :                                               GPR_SLICE_LENGTH(slice));
     322         292 :   gpr_slice_unref(slice);
     323         292 :   return result;
     324             : }
     325             : 
     326     4768397 : grpc_mdstr *grpc_mdstr_from_buffer(grpc_mdctx *ctx, const gpr_uint8 *buf,
     327             :                                    size_t length) {
     328     4768397 :   gpr_uint32 hash = gpr_murmur_hash3(buf, length, ctx->hash_seed);
     329             :   internal_string *s;
     330             : 
     331     4768535 :   lock(ctx);
     332             : 
     333             :   /* search for an existing string */
     334     9175412 :   for (s = ctx->strtab[hash % ctx->strtab_capacity]; s; s = s->bucket_next) {
     335     8846204 :     if (s->hash == hash && GPR_SLICE_LENGTH(s->slice) == length &&
     336     2220044 :         0 == memcmp(buf, GPR_SLICE_START_PTR(s->slice), length)) {
     337     2219967 :       INTERNAL_STRING_REF(s);
     338     2220012 :       unlock(ctx);
     339     2220040 :       return (grpc_mdstr *)s;
     340             :     }
     341             :   }
     342             : 
     343             :   /* not found: create a new string */
     344     2549252 :   if (length + 1 < GPR_SLICE_INLINED_SIZE) {
     345             :     /* string data goes directly into the slice */
     346     2392874 :     s = gpr_malloc(sizeof(internal_string));
     347     2392795 :     s->refs = 1;
     348     2392795 :     s->slice.refcount = NULL;
     349     2392795 :     memcpy(s->slice.data.inlined.bytes, buf, length);
     350     2392795 :     s->slice.data.inlined.bytes[length] = 0;
     351     2392795 :     s->slice.data.inlined.length = (gpr_uint8)length;
     352             :   } else {
     353             :     /* string data goes after the internal_string header, and we +1 for null
     354             :        terminator */
     355      156378 :     s = gpr_malloc(sizeof(internal_string) + length + 1);
     356      156372 :     s->refs = 1;
     357      156372 :     s->refcount.ref = slice_ref;
     358      156372 :     s->refcount.unref = slice_unref;
     359      156372 :     s->slice.refcount = &s->refcount;
     360      156372 :     s->slice.data.refcounted.bytes = (gpr_uint8 *)(s + 1);
     361      156372 :     s->slice.data.refcounted.length = length;
     362      156372 :     memcpy(s->slice.data.refcounted.bytes, buf, length);
     363             :     /* add a null terminator for cheap c string conversion when desired */
     364      156372 :     s->slice.data.refcounted.bytes[length] = 0;
     365             :   }
     366     2549167 :   s->has_base64_and_huffman_encoded = 0;
     367     2549167 :   s->hash = hash;
     368     2549167 :   s->context = ctx;
     369     2549167 :   s->bucket_next = ctx->strtab[hash % ctx->strtab_capacity];
     370     2549167 :   ctx->strtab[hash % ctx->strtab_capacity] = s;
     371             : 
     372     2549167 :   ctx->strtab_count++;
     373             : 
     374     2549167 :   if (ctx->strtab_count > ctx->strtab_capacity * 2) {
     375       16148 :     grow_strtab(ctx);
     376             :   }
     377             : 
     378     2549166 :   unlock(ctx);
     379             : 
     380     2549234 :   return (grpc_mdstr *)s;
     381             : }
     382             : 
     383       10440 : static void gc_mdtab(grpc_mdctx *ctx) {
     384             :   size_t i;
     385             :   internal_metadata **prev_next;
     386             :   internal_metadata *md, *next;
     387             : 
     388     1257292 :   for (i = 0; i < ctx->mdtab_capacity; i++) {
     389     1246852 :     prev_next = &ctx->mdtab[i];
     390     3750996 :     for (md = ctx->mdtab[i]; md; md = next) {
     391     2504144 :       next = md->bucket_next;
     392     2504144 :       if (gpr_atm_acq_load(&md->refcnt) == 0) {
     393     1120471 :         INTERNAL_STRING_UNREF(md->key);
     394     1120471 :         INTERNAL_STRING_UNREF(md->value);
     395     1120471 :         if (md->user_data) {
     396           0 :           md->destroy_user_data(md->user_data);
     397             :         }
     398     1120471 :         gpr_free(md);
     399     1120471 :         *prev_next = next;
     400     1120471 :         ctx->mdtab_free--;
     401     1120471 :         ctx->mdtab_count--;
     402             :       } else {
     403     1383673 :         prev_next = &md->bucket_next;
     404             :       }
     405             :     }
     406             :   }
     407             : 
     408       10440 :   GPR_ASSERT(ctx->mdtab_free == 0);
     409       10440 : }
     410             : 
     411       15721 : static void grow_mdtab(grpc_mdctx *ctx) {
     412       15721 :   size_t capacity = ctx->mdtab_capacity * 2;
     413             :   size_t i;
     414       15721 :   internal_metadata **mdtab =
     415       15721 :       gpr_malloc(sizeof(internal_metadata *) * capacity);
     416             :   internal_metadata *md, *next;
     417             :   gpr_uint32 hash;
     418       15721 :   memset(mdtab, 0, sizeof(internal_metadata *) * capacity);
     419             : 
     420      257652 :   for (i = 0; i < ctx->mdtab_capacity; i++) {
     421      741202 :     for (md = ctx->mdtab[i]; md; md = next) {
     422      499271 :       hash = GRPC_MDSTR_KV_HASH(md->key->hash, md->value->hash);
     423      499271 :       next = md->bucket_next;
     424      499271 :       md->bucket_next = mdtab[hash % capacity];
     425      499271 :       mdtab[hash % capacity] = md;
     426             :     }
     427             :   }
     428             : 
     429       15721 :   gpr_free(ctx->mdtab);
     430       15721 :   ctx->mdtab = mdtab;
     431       15721 :   ctx->mdtab_capacity = capacity;
     432       15721 : }
     433             : 
     434       26161 : static void rehash_mdtab(grpc_mdctx *ctx) {
     435       26161 :   if (ctx->mdtab_free > ctx->mdtab_capacity / 4) {
     436       10440 :     gc_mdtab(ctx);
     437             :   } else {
     438       15721 :     grow_mdtab(ctx);
     439             :   }
     440       26161 : }
     441             : 
     442     2097770 : grpc_mdelem *grpc_mdelem_from_metadata_strings(grpc_mdctx *ctx,
     443             :                                                grpc_mdstr *mkey,
     444             :                                                grpc_mdstr *mvalue) {
     445     2097770 :   internal_string *key = (internal_string *)mkey;
     446     2097770 :   internal_string *value = (internal_string *)mvalue;
     447     2097770 :   gpr_uint32 hash = GRPC_MDSTR_KV_HASH(mkey->hash, mvalue->hash);
     448             :   internal_metadata *md;
     449             : 
     450     2097770 :   GPR_ASSERT(key->context == ctx);
     451     2097770 :   GPR_ASSERT(value->context == ctx);
     452             : 
     453     2097770 :   lock(ctx);
     454             : 
     455             :   /* search for an existing pair */
     456     4657977 :   for (md = ctx->mdtab[hash % ctx->mdtab_capacity]; md; md = md->bucket_next) {
     457     3227407 :     if (md->key == key && md->value == value) {
     458      667225 :       REF_MD_LOCKED(md);
     459      667228 :       INTERNAL_STRING_UNREF(key);
     460      667228 :       INTERNAL_STRING_UNREF(value);
     461      667228 :       unlock(ctx);
     462      667227 :       return (grpc_mdelem *)md;
     463             :     }
     464             :   }
     465             : 
     466             :   /* not found: create a new pair */
     467     1430570 :   md = gpr_malloc(sizeof(internal_metadata));
     468     1430437 :   gpr_atm_rel_store(&md->refcnt, 1);
     469     1430437 :   md->context = ctx;
     470     1430437 :   md->key = key;
     471     1430437 :   md->value = value;
     472     1430437 :   md->user_data = NULL;
     473     1430437 :   md->destroy_user_data = NULL;
     474     1430437 :   md->bucket_next = ctx->mdtab[hash % ctx->mdtab_capacity];
     475     1430437 :   gpr_mu_init(&md->mu_user_data);
     476             : #ifdef GRPC_METADATA_REFCOUNT_DEBUG
     477             :   gpr_log(GPR_DEBUG, "ELM   NEW:%p:%d: '%s' = '%s'", md,
     478             :           gpr_atm_no_barrier_load(&md->refcnt),
     479             :           grpc_mdstr_as_c_string((grpc_mdstr *)md->key),
     480             :           grpc_mdstr_as_c_string((grpc_mdstr *)md->value));
     481             : #endif
     482     1430419 :   ctx->mdtab[hash % ctx->mdtab_capacity] = md;
     483     1430419 :   ctx->mdtab_count++;
     484             : 
     485     1430419 :   if (ctx->mdtab_count > ctx->mdtab_capacity * 2) {
     486       26161 :     rehash_mdtab(ctx);
     487             :   }
     488             : 
     489     1430419 :   unlock(ctx);
     490             : 
     491     1430531 :   return (grpc_mdelem *)md;
     492             : }
     493             : 
     494     1710904 : grpc_mdelem *grpc_mdelem_from_strings(grpc_mdctx *ctx, const char *key,
     495             :                                       const char *value) {
     496     1710904 :   return grpc_mdelem_from_metadata_strings(ctx,
     497             :                                            grpc_mdstr_from_string(ctx, key),
     498             :                                            grpc_mdstr_from_string(ctx, value));
     499             : }
     500             : 
     501         146 : grpc_mdelem *grpc_mdelem_from_slices(grpc_mdctx *ctx, gpr_slice key,
     502             :                                      gpr_slice value) {
     503         146 :   return grpc_mdelem_from_metadata_strings(ctx, grpc_mdstr_from_slice(ctx, key),
     504             :                                            grpc_mdstr_from_slice(ctx, value));
     505             : }
     506             : 
     507        1193 : grpc_mdelem *grpc_mdelem_from_string_and_buffer(grpc_mdctx *ctx,
     508             :                                                 const char *key,
     509             :                                                 const gpr_uint8 *value,
     510             :                                                 size_t value_length) {
     511        1193 :   return grpc_mdelem_from_metadata_strings(
     512             :       ctx, grpc_mdstr_from_string(ctx, key),
     513             :       grpc_mdstr_from_buffer(ctx, value, value_length));
     514             : }
     515             : 
     516    37522670 : grpc_mdelem *grpc_mdelem_ref(grpc_mdelem *gmd DEBUG_ARGS) {
     517    37522670 :   internal_metadata *md = (internal_metadata *)gmd;
     518             : #ifdef GRPC_METADATA_REFCOUNT_DEBUG
     519             :   gpr_log(file, line, GPR_LOG_SEVERITY_DEBUG,
     520             :           "ELM   REF:%p:%d->%d: '%s' = '%s'", md,
     521             :           gpr_atm_no_barrier_load(&md->refcnt),
     522             :           gpr_atm_no_barrier_load(&md->refcnt) + 1,
     523             :           grpc_mdstr_as_c_string((grpc_mdstr *)md->key),
     524             :           grpc_mdstr_as_c_string((grpc_mdstr *)md->value));
     525             : #endif
     526             :   /* we can assume the ref count is >= 1 as the application is calling
     527             :      this function - meaning that no adjustment to mdtab_free is necessary,
     528             :      simplifying the logic here to be just an atomic increment */
     529             :   /* use C assert to have this removed in opt builds */
     530    37522670 :   assert(gpr_atm_no_barrier_load(&md->refcnt) >= 1);
     531    37522670 :   gpr_atm_no_barrier_fetch_add(&md->refcnt, 1);
     532    37522670 :   return gmd;
     533             : }
     534             : 
     535     3105108 : void grpc_mdelem_unref(grpc_mdelem *gmd DEBUG_ARGS) {
     536     3105108 :   internal_metadata *md = (internal_metadata *)gmd;
     537     3105108 :   grpc_mdctx *ctx = md->context;
     538     3105108 :   lock(ctx);
     539             : #ifdef GRPC_METADATA_REFCOUNT_DEBUG
     540             :   gpr_log(file, line, GPR_LOG_SEVERITY_DEBUG,
     541             :           "ELM UNREF:%p:%d->%d: '%s' = '%s'", md,
     542             :           gpr_atm_no_barrier_load(&md->refcnt),
     543             :           gpr_atm_no_barrier_load(&md->refcnt) - 1,
     544             :           grpc_mdstr_as_c_string((grpc_mdstr *)md->key),
     545             :           grpc_mdstr_as_c_string((grpc_mdstr *)md->value));
     546             : #endif
     547     3105705 :   assert(gpr_atm_no_barrier_load(&md->refcnt) >= 1);
     548     3105705 :   if (1 == gpr_atm_full_fetch_add(&md->refcnt, -1)) {
     549     1435829 :     ctx->mdtab_free++;
     550             :   }
     551     3105705 :   unlock(ctx);
     552     3105735 : }
     553             : 
     554     2628793 : const char *grpc_mdstr_as_c_string(grpc_mdstr *s) {
     555     2628793 :   return (const char *)GPR_SLICE_START_PTR(s->slice);
     556             : }
     557             : 
     558     3011145 : grpc_mdstr *grpc_mdstr_ref(grpc_mdstr *gs DEBUG_ARGS) {
     559     3011145 :   internal_string *s = (internal_string *)gs;
     560     3011145 :   grpc_mdctx *ctx = s->context;
     561     3011145 :   lock(ctx);
     562     3011944 :   internal_string_ref(s FWD_DEBUG_ARGS);
     563     3011810 :   unlock(ctx);
     564     3011955 :   return gs;
     565             : }
     566             : 
     567     3583029 : void grpc_mdstr_unref(grpc_mdstr *gs DEBUG_ARGS) {
     568     3583029 :   internal_string *s = (internal_string *)gs;
     569     3583029 :   grpc_mdctx *ctx = s->context;
     570     3583029 :   lock(ctx);
     571     3585393 :   internal_string_unref(s FWD_DEBUG_ARGS);
     572     3585387 :   unlock(ctx);
     573     3585434 : }
     574             : 
     575           2 : size_t grpc_mdctx_get_mdtab_capacity_test_only(grpc_mdctx *ctx) {
     576           2 :   return ctx->mdtab_capacity;
     577             : }
     578             : 
     579           4 : size_t grpc_mdctx_get_mdtab_count_test_only(grpc_mdctx *ctx) {
     580           4 :   return ctx->mdtab_count;
     581             : }
     582             : 
     583           4 : size_t grpc_mdctx_get_mdtab_free_test_only(grpc_mdctx *ctx) {
     584           4 :   return ctx->mdtab_free;
     585             : }
     586             : 
     587     4120129 : void *grpc_mdelem_get_user_data(grpc_mdelem *md,
     588             :                                 void (*if_destroy_func)(void *)) {
     589     4120129 :   internal_metadata *im = (internal_metadata *)md;
     590             :   void *result;
     591     4120129 :   gpr_mu_lock(&im->mu_user_data);
     592     4126131 :   result = im->destroy_user_data == if_destroy_func ? im->user_data : NULL;
     593     4126131 :   gpr_mu_unlock(&im->mu_user_data);
     594     4125457 :   return result;
     595             : }
     596             : 
     597        8487 : void grpc_mdelem_set_user_data(grpc_mdelem *md, void (*destroy_func)(void *),
     598             :                                void *user_data) {
     599        8487 :   internal_metadata *im = (internal_metadata *)md;
     600        8487 :   GPR_ASSERT((user_data == NULL) == (destroy_func == NULL));
     601        8487 :   gpr_mu_lock(&im->mu_user_data);
     602        8487 :   if (im->destroy_user_data) {
     603             :     /* user data can only be set once */
     604           0 :     gpr_mu_unlock(&im->mu_user_data);
     605           0 :     if (destroy_func != NULL) {
     606           0 :       destroy_func(user_data);
     607             :     }
     608        8487 :     return;
     609             :   }
     610        8487 :   im->destroy_user_data = destroy_func;
     611        8487 :   im->user_data = user_data;
     612        8487 :   gpr_mu_unlock(&im->mu_user_data);
     613             : }
     614             : 
     615         111 : gpr_slice grpc_mdstr_as_base64_encoded_and_huffman_compressed(grpc_mdstr *gs) {
     616         111 :   internal_string *s = (internal_string *)gs;
     617             :   gpr_slice slice;
     618         111 :   grpc_mdctx *ctx = s->context;
     619         111 :   lock(ctx);
     620         111 :   if (!s->has_base64_and_huffman_encoded) {
     621         111 :     s->base64_and_huffman =
     622             :         grpc_chttp2_base64_encode_and_huffman_compress(s->slice);
     623         111 :     s->has_base64_and_huffman_encoded = 1;
     624             :   }
     625         111 :   slice = s->base64_and_huffman;
     626         111 :   unlock(ctx);
     627         111 :   return slice;
     628             : }
     629             : 
     630     6916392 : void grpc_mdctx_lock(grpc_mdctx *ctx) { lock(ctx); }
     631             : 
     632    36644842 : void grpc_mdctx_locked_mdelem_unref(grpc_mdctx *ctx,
     633             :                                     grpc_mdelem *gmd DEBUG_ARGS) {
     634    36644842 :   internal_metadata *md = (internal_metadata *)gmd;
     635    36644842 :   grpc_mdctx *elem_ctx = md->context;
     636    36644842 :   GPR_ASSERT(ctx == elem_ctx);
     637             : #ifdef GRPC_METADATA_REFCOUNT_DEBUG
     638             :   gpr_log(file, line, GPR_LOG_SEVERITY_DEBUG,
     639             :           "ELM UNREF:%p:%d->%d: '%s' = '%s'", md,
     640             :           gpr_atm_no_barrier_load(&md->refcnt),
     641             :           gpr_atm_no_barrier_load(&md->refcnt) - 1,
     642             :           grpc_mdstr_as_c_string((grpc_mdstr *)md->key),
     643             :           grpc_mdstr_as_c_string((grpc_mdstr *)md->value));
     644             : #endif
     645    36644842 :   assert(gpr_atm_no_barrier_load(&md->refcnt) >= 1);
     646    36644842 :   if (1 == gpr_atm_full_fetch_add(&md->refcnt, -1)) {
     647      103751 :     ctx->mdtab_free++;
     648             :   }
     649    36644842 : }
     650             : 
     651     6927909 : void grpc_mdctx_unlock(grpc_mdctx *ctx) { unlock(ctx); }
     652             : 
     653        2276 : static int conforms_to(grpc_mdstr *s, const gpr_uint8 *legal_bits) {
     654        2276 :   const gpr_uint8 *p = GPR_SLICE_START_PTR(s->slice);
     655        2276 :   const gpr_uint8 *e = GPR_SLICE_END_PTR(s->slice);
     656     1735672 :   for (; p != e; p++) {
     657     1733396 :     int idx = *p;
     658     1733396 :     int byte = idx / 8;
     659     1733396 :     int bit = idx % 8;
     660     1733396 :     if ((legal_bits[byte] & (1 << bit)) == 0) return 0;
     661             :   }
     662        2276 :   return 1;
     663             : }
     664             : 
     665        1193 : int grpc_mdstr_is_legal_header(grpc_mdstr *s) {
     666             :   static const gpr_uint8 legal_header_bits[256 / 8] = {
     667             :       0x00, 0x00, 0x00, 0x00, 0x00, 0x20, 0xff, 0x03, 0x00, 0x00, 0x00,
     668             :       0x80, 0xfe, 0xff, 0xff, 0x07, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
     669             :       0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00};
     670        1193 :   return conforms_to(s, legal_header_bits);
     671             : }
     672             : 
     673        1083 : int grpc_mdstr_is_legal_nonbin_header(grpc_mdstr *s) {
     674             :   static const gpr_uint8 legal_header_bits[256 / 8] = {
     675             :       0x00, 0x00, 0x00, 0x00, 0xff, 0xef, 0xff, 0xff, 0xff, 0xff, 0xff,
     676             :       0xff, 0xff, 0xff, 0xff, 0x7f, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
     677             :       0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00};
     678        1083 :   return conforms_to(s, legal_header_bits);
     679             : }
     680             : 
     681        1193 : int grpc_mdstr_is_bin_suffixed(grpc_mdstr *s) {
     682             :   /* TODO(ctiller): consider caching this */
     683        1905 :   return grpc_is_binary_header((const char *)GPR_SLICE_START_PTR(s->slice),
     684        1905 :                                GPR_SLICE_LENGTH(s->slice));
     685             : }

Generated by: LCOV version 1.10