|
|
@ -50,10 +50,6 @@ typedef struct slice_shard { |
|
|
|
size_t capacity; |
|
|
|
size_t capacity; |
|
|
|
} slice_shard; |
|
|
|
} slice_shard; |
|
|
|
|
|
|
|
|
|
|
|
/* hash seed: decided at initialization time */ |
|
|
|
|
|
|
|
uint32_t g_hash_seed; |
|
|
|
|
|
|
|
static int g_forced_hash_seed = 0; |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
static slice_shard g_shards[SHARD_COUNT]; |
|
|
|
static slice_shard g_shards[SHARD_COUNT]; |
|
|
|
|
|
|
|
|
|
|
|
typedef struct { |
|
|
|
typedef struct { |
|
|
@ -68,6 +64,10 @@ uint32_t grpc_static_metadata_hash_values[GRPC_STATIC_MDSTR_COUNT]; |
|
|
|
|
|
|
|
|
|
|
|
namespace grpc_core { |
|
|
|
namespace grpc_core { |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
/* hash seed: decided at initialization time */ |
|
|
|
|
|
|
|
uint32_t g_hash_seed; |
|
|
|
|
|
|
|
static bool g_forced_hash_seed = false; |
|
|
|
|
|
|
|
|
|
|
|
InternedSliceRefcount::~InternedSliceRefcount() { |
|
|
|
InternedSliceRefcount::~InternedSliceRefcount() { |
|
|
|
slice_shard* shard = &g_shards[SHARD_IDX(this->hash)]; |
|
|
|
slice_shard* shard = &g_shards[SHARD_IDX(this->hash)]; |
|
|
|
MutexLock lock(&shard->mu); |
|
|
|
MutexLock lock(&shard->mu); |
|
|
@ -115,7 +115,7 @@ grpc_core::InternedSlice::InternedSlice(InternedSliceRefcount* s) { |
|
|
|
|
|
|
|
|
|
|
|
uint32_t grpc_slice_default_hash_impl(grpc_slice s) { |
|
|
|
uint32_t grpc_slice_default_hash_impl(grpc_slice s) { |
|
|
|
return gpr_murmur_hash3(GRPC_SLICE_START_PTR(s), GRPC_SLICE_LENGTH(s), |
|
|
|
return gpr_murmur_hash3(GRPC_SLICE_START_PTR(s), GRPC_SLICE_LENGTH(s), |
|
|
|
g_hash_seed); |
|
|
|
grpc_core::g_hash_seed); |
|
|
|
} |
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
uint32_t grpc_static_slice_hash(grpc_slice s) { |
|
|
|
uint32_t grpc_static_slice_hash(grpc_slice s) { |
|
|
@ -159,20 +159,20 @@ grpc_slice grpc_slice_intern(grpc_slice slice) { |
|
|
|
} |
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
// Attempt to see if the provided slice or string matches a static slice.
|
|
|
|
// Attempt to see if the provided slice or string matches a static slice.
|
|
|
|
// SliceArgs... is either a const grpc_slice& or a string and length. In either
|
|
|
|
// SliceArgs is either a const grpc_slice& or const pair<const char*, size_t>&.
|
|
|
|
// case, hash is the pre-computed hash value.
|
|
|
|
// In either case, hash is the pre-computed hash value.
|
|
|
|
//
|
|
|
|
//
|
|
|
|
// Returns: a matching static slice, or null.
|
|
|
|
// Returns: a matching static slice, or null.
|
|
|
|
template <class... SliceArgs> |
|
|
|
template <typename SliceArgs> |
|
|
|
static const grpc_core::StaticMetadataSlice* MatchStaticSlice( |
|
|
|
static const grpc_core::StaticMetadataSlice* MatchStaticSlice( |
|
|
|
uint32_t hash, SliceArgs&&... args) { |
|
|
|
uint32_t hash, const SliceArgs& args) { |
|
|
|
for (uint32_t i = 0; i <= max_static_metadata_hash_probe; i++) { |
|
|
|
for (uint32_t i = 0; i <= max_static_metadata_hash_probe; i++) { |
|
|
|
static_metadata_hash_ent ent = |
|
|
|
static_metadata_hash_ent ent = |
|
|
|
static_metadata_hash[(hash + i) % GPR_ARRAY_SIZE(static_metadata_hash)]; |
|
|
|
static_metadata_hash[(hash + i) % GPR_ARRAY_SIZE(static_metadata_hash)]; |
|
|
|
const grpc_core::StaticMetadataSlice* static_slice_table = |
|
|
|
const grpc_core::StaticMetadataSlice* static_slice_table = |
|
|
|
grpc_static_slice_table(); |
|
|
|
grpc_static_slice_table(); |
|
|
|
if (ent.hash == hash && ent.idx < GRPC_STATIC_MDSTR_COUNT && |
|
|
|
if (ent.hash == hash && ent.idx < GRPC_STATIC_MDSTR_COUNT && |
|
|
|
static_slice_table[ent.idx].Equals(std::forward<SliceArgs>(args)...)) { |
|
|
|
static_slice_table[ent.idx] == args) { |
|
|
|
return &static_slice_table[ent.idx]; |
|
|
|
return &static_slice_table[ent.idx]; |
|
|
|
} |
|
|
|
} |
|
|
|
} |
|
|
|
} |
|
|
@ -182,8 +182,12 @@ static const grpc_core::StaticMetadataSlice* MatchStaticSlice( |
|
|
|
// Helper methods to enable us to select appropriately overloaded slice methods
|
|
|
|
// Helper methods to enable us to select appropriately overloaded slice methods
|
|
|
|
// whether we're dealing with a slice, or a buffer with length, when interning
|
|
|
|
// whether we're dealing with a slice, or a buffer with length, when interning
|
|
|
|
// strings. Helpers for FindOrCreateInternedSlice().
|
|
|
|
// strings. Helpers for FindOrCreateInternedSlice().
|
|
|
|
static const void* GetBuffer(const void* buf, size_t len) { return buf; } |
|
|
|
static const char* GetBuffer(const std::pair<const char*, size_t>& buflen) { |
|
|
|
static size_t GetLength(const void* buf, size_t len) { return len; } |
|
|
|
return buflen.first; |
|
|
|
|
|
|
|
} |
|
|
|
|
|
|
|
static size_t GetLength(const std::pair<const char*, size_t>& buflen) { |
|
|
|
|
|
|
|
return buflen.second; |
|
|
|
|
|
|
|
} |
|
|
|
static const void* GetBuffer(const grpc_slice& slice) { |
|
|
|
static const void* GetBuffer(const grpc_slice& slice) { |
|
|
|
return GRPC_SLICE_START_PTR(slice); |
|
|
|
return GRPC_SLICE_START_PTR(slice); |
|
|
|
} |
|
|
|
} |
|
|
@ -192,19 +196,19 @@ static size_t GetLength(const grpc_slice& slice) { |
|
|
|
} |
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
// Creates an interned slice for a string that does not currently exist in the
|
|
|
|
// Creates an interned slice for a string that does not currently exist in the
|
|
|
|
// intern table. SliceArgs... is either a const grpc_slice& or a string and
|
|
|
|
// intern table. SliceArgs is either a const grpc_slice& or a const
|
|
|
|
// length. In either case, hash is the pre-computed hash value. We must already
|
|
|
|
// pair<const char*, size_t>&. Hash is the pre-computed hash value. We must
|
|
|
|
// hold the shard lock. Helper for FindOrCreateInternedSlice().
|
|
|
|
// already hold the shard lock. Helper for FindOrCreateInternedSlice().
|
|
|
|
//
|
|
|
|
//
|
|
|
|
// Returns: a newly interned slice.
|
|
|
|
// Returns: a newly interned slice.
|
|
|
|
template <class... SliceArgs> |
|
|
|
template <typename SliceArgs> |
|
|
|
static InternedSliceRefcount* InternNewStringLocked(slice_shard* shard, |
|
|
|
static InternedSliceRefcount* InternNewStringLocked(slice_shard* shard, |
|
|
|
size_t shard_idx, |
|
|
|
size_t shard_idx, |
|
|
|
uint32_t hash, |
|
|
|
uint32_t hash, |
|
|
|
SliceArgs&&... args) { |
|
|
|
const SliceArgs& args) { |
|
|
|
/* string data goes after the internal_string header */ |
|
|
|
/* string data goes after the internal_string header */ |
|
|
|
size_t len = GetLength(std::forward<SliceArgs>(args)...); |
|
|
|
size_t len = GetLength(args); |
|
|
|
const void* buffer = GetBuffer(std::forward<SliceArgs>(args)...); |
|
|
|
const void* buffer = GetBuffer(args); |
|
|
|
InternedSliceRefcount* s = |
|
|
|
InternedSliceRefcount* s = |
|
|
|
static_cast<InternedSliceRefcount*>(gpr_malloc(sizeof(*s) + len)); |
|
|
|
static_cast<InternedSliceRefcount*>(gpr_malloc(sizeof(*s) + len)); |
|
|
|
new (s) grpc_core::InternedSliceRefcount(len, hash, shard->strs[shard_idx]); |
|
|
|
new (s) grpc_core::InternedSliceRefcount(len, hash, shard->strs[shard_idx]); |
|
|
@ -227,16 +231,15 @@ static InternedSliceRefcount* InternNewStringLocked(slice_shard* shard, |
|
|
|
// shard lock. Helper for FindOrCreateInternedSlice().
|
|
|
|
// shard lock. Helper for FindOrCreateInternedSlice().
|
|
|
|
//
|
|
|
|
//
|
|
|
|
// Returns: a pre-existing matching static slice, or null.
|
|
|
|
// Returns: a pre-existing matching static slice, or null.
|
|
|
|
template <class... SliceArgs> |
|
|
|
template <typename SliceArgs> |
|
|
|
static InternedSliceRefcount* MatchInternedSliceLocked(uint32_t hash, |
|
|
|
static InternedSliceRefcount* MatchInternedSliceLocked(uint32_t hash, |
|
|
|
size_t idx, |
|
|
|
size_t idx, |
|
|
|
SliceArgs&&... args) { |
|
|
|
const SliceArgs& args) { |
|
|
|
InternedSliceRefcount* s; |
|
|
|
InternedSliceRefcount* s; |
|
|
|
slice_shard* shard = &g_shards[SHARD_IDX(hash)]; |
|
|
|
slice_shard* shard = &g_shards[SHARD_IDX(hash)]; |
|
|
|
/* search for an existing string */ |
|
|
|
/* search for an existing string */ |
|
|
|
for (s = shard->strs[idx]; s; s = s->bucket_next) { |
|
|
|
for (s = shard->strs[idx]; s; s = s->bucket_next) { |
|
|
|
if (s->hash == hash && |
|
|
|
if (s->hash == hash && grpc_core::InternedSlice(s) == args) { |
|
|
|
grpc_core::InternedSlice(s).Equals(std::forward<SliceArgs>(args)...)) { |
|
|
|
|
|
|
|
if (s->refcnt.RefIfNonZero()) { |
|
|
|
if (s->refcnt.RefIfNonZero()) { |
|
|
|
return s; |
|
|
|
return s; |
|
|
|
} |
|
|
|
} |
|
|
@ -248,22 +251,20 @@ static InternedSliceRefcount* MatchInternedSliceLocked(uint32_t hash, |
|
|
|
// Attempt to see if the provided slice or string matches an existing interned
|
|
|
|
// Attempt to see if the provided slice or string matches an existing interned
|
|
|
|
// slice, and failing that, create an interned slice with its contents. Returns
|
|
|
|
// slice, and failing that, create an interned slice with its contents. Returns
|
|
|
|
// either the existing matching interned slice or the newly created one.
|
|
|
|
// either the existing matching interned slice or the newly created one.
|
|
|
|
// SliceArgs... is either a const grpc_slice& or a string and length. In either
|
|
|
|
// SliceArgs is either a const grpc_slice& or const pair<const char*, size_t>&.
|
|
|
|
// case, hash is the pre-computed hash value. We do not hold the shard lock
|
|
|
|
// In either case, hash is the pre-computed hash value. We do not hold the
|
|
|
|
// here, but do take it.
|
|
|
|
// shard lock here, but do take it.
|
|
|
|
//
|
|
|
|
//
|
|
|
|
// Returns: an interned slice, either pre-existing/matched or newly created.
|
|
|
|
// Returns: an interned slice, either pre-existing/matched or newly created.
|
|
|
|
template <class... SliceArgs> |
|
|
|
template <typename SliceArgs> |
|
|
|
static InternedSliceRefcount* FindOrCreateInternedSlice(uint32_t hash, |
|
|
|
static InternedSliceRefcount* FindOrCreateInternedSlice(uint32_t hash, |
|
|
|
SliceArgs&&... args) { |
|
|
|
const SliceArgs& args) { |
|
|
|
slice_shard* shard = &g_shards[SHARD_IDX(hash)]; |
|
|
|
slice_shard* shard = &g_shards[SHARD_IDX(hash)]; |
|
|
|
gpr_mu_lock(&shard->mu); |
|
|
|
gpr_mu_lock(&shard->mu); |
|
|
|
const size_t idx = TABLE_IDX(hash, shard->capacity); |
|
|
|
const size_t idx = TABLE_IDX(hash, shard->capacity); |
|
|
|
InternedSliceRefcount* s = |
|
|
|
InternedSliceRefcount* s = MatchInternedSliceLocked(hash, idx, args); |
|
|
|
MatchInternedSliceLocked(hash, idx, std::forward<SliceArgs>(args)...); |
|
|
|
|
|
|
|
if (s == nullptr) { |
|
|
|
if (s == nullptr) { |
|
|
|
s = InternNewStringLocked(shard, idx, hash, |
|
|
|
s = InternNewStringLocked(shard, idx, hash, args); |
|
|
|
std::forward<SliceArgs>(args)...); |
|
|
|
|
|
|
|
} |
|
|
|
} |
|
|
|
gpr_mu_unlock(&shard->mu); |
|
|
|
gpr_mu_unlock(&shard->mu); |
|
|
|
return s; |
|
|
|
return s; |
|
|
@ -277,12 +278,13 @@ grpc_core::ManagedMemorySlice::ManagedMemorySlice(const char* string, |
|
|
|
size_t len) { |
|
|
|
size_t len) { |
|
|
|
GPR_TIMER_SCOPE("grpc_slice_intern", 0); |
|
|
|
GPR_TIMER_SCOPE("grpc_slice_intern", 0); |
|
|
|
const uint32_t hash = gpr_murmur_hash3(string, len, g_hash_seed); |
|
|
|
const uint32_t hash = gpr_murmur_hash3(string, len, g_hash_seed); |
|
|
|
const StaticMetadataSlice* static_slice = MatchStaticSlice(hash, string, len); |
|
|
|
const StaticMetadataSlice* static_slice = |
|
|
|
|
|
|
|
MatchStaticSlice(hash, std::pair<const char*, size_t>(string, len)); |
|
|
|
if (static_slice) { |
|
|
|
if (static_slice) { |
|
|
|
*this = *static_slice; |
|
|
|
*this = *static_slice; |
|
|
|
} else { |
|
|
|
} else { |
|
|
|
*this = |
|
|
|
*this = grpc_core::InternedSlice(FindOrCreateInternedSlice( |
|
|
|
grpc_core::InternedSlice(FindOrCreateInternedSlice(hash, string, len)); |
|
|
|
hash, std::pair<const char*, size_t>(string, len))); |
|
|
|
} |
|
|
|
} |
|
|
|
} |
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
@ -303,13 +305,14 @@ grpc_core::ManagedMemorySlice::ManagedMemorySlice(const grpc_slice* slice_ptr) { |
|
|
|
} |
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
void grpc_test_only_set_slice_hash_seed(uint32_t seed) { |
|
|
|
void grpc_test_only_set_slice_hash_seed(uint32_t seed) { |
|
|
|
g_hash_seed = seed; |
|
|
|
grpc_core::g_hash_seed = seed; |
|
|
|
g_forced_hash_seed = 1; |
|
|
|
grpc_core::g_forced_hash_seed = true; |
|
|
|
} |
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
void grpc_slice_intern_init(void) { |
|
|
|
void grpc_slice_intern_init(void) { |
|
|
|
if (!g_forced_hash_seed) { |
|
|
|
if (!grpc_core::g_forced_hash_seed) { |
|
|
|
g_hash_seed = static_cast<uint32_t>(gpr_now(GPR_CLOCK_REALTIME).tv_nsec); |
|
|
|
grpc_core::g_hash_seed = |
|
|
|
|
|
|
|
static_cast<uint32_t>(gpr_now(GPR_CLOCK_REALTIME).tv_nsec); |
|
|
|
} |
|
|
|
} |
|
|
|
for (size_t i = 0; i < SHARD_COUNT; i++) { |
|
|
|
for (size_t i = 0; i < SHARD_COUNT; i++) { |
|
|
|
slice_shard* shard = &g_shards[i]; |
|
|
|
slice_shard* shard = &g_shards[i]; |
|
|
|