mirror of https://github.com/grpc/grpc.git
reviewable/pr8239/r2
commit
5a2a9eaa34
159 changed files with 6101 additions and 2067 deletions
@ -0,0 +1,296 @@ |
||||
//
|
||||
// Copyright 2015, Google Inc.
|
||||
// All rights reserved.
|
||||
//
|
||||
// Redistribution and use in source and binary forms, with or without
|
||||
// modification, are permitted provided that the following conditions are
|
||||
// met:
|
||||
//
|
||||
// * Redistributions of source code must retain the above copyright
|
||||
// notice, this list of conditions and the following disclaimer.
|
||||
// * Redistributions in binary form must reproduce the above
|
||||
// copyright notice, this list of conditions and the following disclaimer
|
||||
// in the documentation and/or other materials provided with the
|
||||
// distribution.
|
||||
// * Neither the name of Google Inc. nor the names of its
|
||||
// contributors may be used to endorse or promote products derived from
|
||||
// this software without specific prior written permission.
|
||||
//
|
||||
// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
|
||||
// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
|
||||
// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
|
||||
// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
|
||||
// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
|
||||
// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
|
||||
// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
|
||||
// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
|
||||
// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
|
||||
// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
|
||||
// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
//
|
||||
|
||||
#include "src/core/ext/client_config/method_config.h" |
||||
|
||||
#include <string.h> |
||||
|
||||
#include <grpc/impl/codegen/grpc_types.h> |
||||
#include <grpc/support/alloc.h> |
||||
#include <grpc/support/log.h> |
||||
#include <grpc/support/string_util.h> |
||||
#include <grpc/support/time.h> |
||||
|
||||
#include "src/core/lib/transport/mdstr_hash_table.h" |
||||
#include "src/core/lib/transport/metadata.h" |
||||
|
||||
//
|
||||
// grpc_method_config
|
||||
//
|
||||
|
||||
// bool vtable
|
||||
|
||||
static void* bool_copy(void* valuep) { |
||||
bool value = *(bool*)valuep; |
||||
bool* new_value = gpr_malloc(sizeof(bool)); |
||||
*new_value = value; |
||||
return new_value; |
||||
} |
||||
|
||||
static int bool_cmp(void* v1, void* v2) { |
||||
bool b1 = *(bool*)v1; |
||||
bool b2 = *(bool*)v2; |
||||
if (!b1 && b2) return -1; |
||||
if (b1 && !b2) return 1; |
||||
return 0; |
||||
} |
||||
|
||||
static grpc_mdstr_hash_table_vtable bool_vtable = {gpr_free, bool_copy, |
||||
bool_cmp}; |
||||
|
||||
// timespec vtable
|
||||
|
||||
static void* timespec_copy(void* valuep) { |
||||
gpr_timespec value = *(gpr_timespec*)valuep; |
||||
gpr_timespec* new_value = gpr_malloc(sizeof(gpr_timespec)); |
||||
*new_value = value; |
||||
return new_value; |
||||
} |
||||
|
||||
static int timespec_cmp(void* v1, void* v2) { |
||||
return gpr_time_cmp(*(gpr_timespec*)v1, *(gpr_timespec*)v2); |
||||
} |
||||
|
||||
static grpc_mdstr_hash_table_vtable timespec_vtable = {gpr_free, timespec_copy, |
||||
timespec_cmp}; |
||||
|
||||
// int32 vtable
|
||||
|
||||
static void* int32_copy(void* valuep) { |
||||
int32_t value = *(int32_t*)valuep; |
||||
int32_t* new_value = gpr_malloc(sizeof(int32_t)); |
||||
*new_value = value; |
||||
return new_value; |
||||
} |
||||
|
||||
static int int32_cmp(void* v1, void* v2) { |
||||
int32_t i1 = *(int32_t*)v1; |
||||
int32_t i2 = *(int32_t*)v2; |
||||
if (i1 < i2) return -1; |
||||
if (i1 > i2) return 1; |
||||
return 0; |
||||
} |
||||
|
||||
static grpc_mdstr_hash_table_vtable int32_vtable = {gpr_free, int32_copy, |
||||
int32_cmp}; |
||||
|
||||
// Hash table keys.
|
||||
#define GRPC_METHOD_CONFIG_WAIT_FOR_READY "grpc.wait_for_ready" // bool
|
||||
#define GRPC_METHOD_CONFIG_TIMEOUT "grpc.timeout" // gpr_timespec
|
||||
#define GRPC_METHOD_CONFIG_MAX_REQUEST_MESSAGE_BYTES \ |
||||
"grpc.max_request_message_bytes" // int32
|
||||
#define GRPC_METHOD_CONFIG_MAX_RESPONSE_MESSAGE_BYTES \ |
||||
"grpc.max_response_message_bytes" // int32
|
||||
|
||||
struct grpc_method_config { |
||||
grpc_mdstr_hash_table* table; |
||||
grpc_mdstr* wait_for_ready_key; |
||||
grpc_mdstr* timeout_key; |
||||
grpc_mdstr* max_request_message_bytes_key; |
||||
grpc_mdstr* max_response_message_bytes_key; |
||||
}; |
||||
|
||||
grpc_method_config* grpc_method_config_create( |
||||
bool* wait_for_ready, gpr_timespec* timeout, |
||||
int32_t* max_request_message_bytes, int32_t* max_response_message_bytes) { |
||||
grpc_method_config* method_config = gpr_malloc(sizeof(grpc_method_config)); |
||||
memset(method_config, 0, sizeof(grpc_method_config)); |
||||
method_config->wait_for_ready_key = |
||||
grpc_mdstr_from_string(GRPC_METHOD_CONFIG_WAIT_FOR_READY); |
||||
method_config->timeout_key = |
||||
grpc_mdstr_from_string(GRPC_METHOD_CONFIG_TIMEOUT); |
||||
method_config->max_request_message_bytes_key = |
||||
grpc_mdstr_from_string(GRPC_METHOD_CONFIG_MAX_REQUEST_MESSAGE_BYTES); |
||||
method_config->max_response_message_bytes_key = |
||||
grpc_mdstr_from_string(GRPC_METHOD_CONFIG_MAX_RESPONSE_MESSAGE_BYTES); |
||||
grpc_mdstr_hash_table_entry entries[4]; |
||||
size_t num_entries = 0; |
||||
if (wait_for_ready != NULL) { |
||||
entries[num_entries].key = method_config->wait_for_ready_key; |
||||
entries[num_entries].value = wait_for_ready; |
||||
entries[num_entries].vtable = &bool_vtable; |
||||
++num_entries; |
||||
} |
||||
if (timeout != NULL) { |
||||
entries[num_entries].key = method_config->timeout_key; |
||||
entries[num_entries].value = timeout; |
||||
entries[num_entries].vtable = ×pec_vtable; |
||||
++num_entries; |
||||
} |
||||
if (max_request_message_bytes != NULL) { |
||||
entries[num_entries].key = method_config->max_request_message_bytes_key; |
||||
entries[num_entries].value = max_request_message_bytes; |
||||
entries[num_entries].vtable = &int32_vtable; |
||||
++num_entries; |
||||
} |
||||
if (max_response_message_bytes != NULL) { |
||||
entries[num_entries].key = method_config->max_response_message_bytes_key; |
||||
entries[num_entries].value = max_response_message_bytes; |
||||
entries[num_entries].vtable = &int32_vtable; |
||||
++num_entries; |
||||
} |
||||
method_config->table = grpc_mdstr_hash_table_create(num_entries, entries); |
||||
return method_config; |
||||
} |
||||
|
||||
grpc_method_config* grpc_method_config_ref(grpc_method_config* method_config) { |
||||
grpc_mdstr_hash_table_ref(method_config->table); |
||||
return method_config; |
||||
} |
||||
|
||||
void grpc_method_config_unref(grpc_method_config* method_config) { |
||||
if (grpc_mdstr_hash_table_unref(method_config->table)) { |
||||
GRPC_MDSTR_UNREF(method_config->wait_for_ready_key); |
||||
GRPC_MDSTR_UNREF(method_config->timeout_key); |
||||
GRPC_MDSTR_UNREF(method_config->max_request_message_bytes_key); |
||||
GRPC_MDSTR_UNREF(method_config->max_response_message_bytes_key); |
||||
gpr_free(method_config); |
||||
} |
||||
} |
||||
|
||||
int grpc_method_config_cmp(const grpc_method_config* method_config1, |
||||
const grpc_method_config* method_config2) { |
||||
return grpc_mdstr_hash_table_cmp(method_config1->table, |
||||
method_config2->table); |
||||
} |
||||
|
||||
const bool* grpc_method_config_get_wait_for_ready( |
||||
const grpc_method_config* method_config) { |
||||
return grpc_mdstr_hash_table_get(method_config->table, |
||||
method_config->wait_for_ready_key); |
||||
} |
||||
|
||||
const gpr_timespec* grpc_method_config_get_timeout( |
||||
const grpc_method_config* method_config) { |
||||
return grpc_mdstr_hash_table_get(method_config->table, |
||||
method_config->timeout_key); |
||||
} |
||||
|
||||
const int32_t* grpc_method_config_get_max_request_message_bytes( |
||||
const grpc_method_config* method_config) { |
||||
return grpc_mdstr_hash_table_get( |
||||
method_config->table, method_config->max_request_message_bytes_key); |
||||
} |
||||
|
||||
const int32_t* grpc_method_config_get_max_response_message_bytes( |
||||
const grpc_method_config* method_config) { |
||||
return grpc_mdstr_hash_table_get( |
||||
method_config->table, method_config->max_response_message_bytes_key); |
||||
} |
||||
|
||||
//
|
||||
// grpc_method_config_table
|
||||
//
|
||||
|
||||
static void method_config_unref(void* valuep) { |
||||
grpc_method_config_unref(valuep); |
||||
} |
||||
|
||||
static void* method_config_ref(void* valuep) { |
||||
return grpc_method_config_ref(valuep); |
||||
} |
||||
|
||||
static int method_config_cmp(void* valuep1, void* valuep2) { |
||||
return grpc_method_config_cmp(valuep1, valuep2); |
||||
} |
||||
|
||||
static const grpc_mdstr_hash_table_vtable method_config_table_vtable = { |
||||
method_config_unref, method_config_ref, method_config_cmp}; |
||||
|
||||
grpc_method_config_table* grpc_method_config_table_create( |
||||
size_t num_entries, grpc_method_config_table_entry* entries) { |
||||
grpc_mdstr_hash_table_entry* hash_table_entries = |
||||
gpr_malloc(sizeof(grpc_mdstr_hash_table_entry) * num_entries); |
||||
for (size_t i = 0; i < num_entries; ++i) { |
||||
hash_table_entries[i].key = entries[i].method_name; |
||||
hash_table_entries[i].value = entries[i].method_config; |
||||
hash_table_entries[i].vtable = &method_config_table_vtable; |
||||
} |
||||
grpc_method_config_table* method_config_table = |
||||
grpc_mdstr_hash_table_create(num_entries, hash_table_entries); |
||||
gpr_free(hash_table_entries); |
||||
return method_config_table; |
||||
} |
||||
|
||||
grpc_method_config_table* grpc_method_config_table_ref( |
||||
grpc_method_config_table* table) { |
||||
return grpc_mdstr_hash_table_ref(table); |
||||
} |
||||
|
||||
void grpc_method_config_table_unref(grpc_method_config_table* table) { |
||||
grpc_mdstr_hash_table_unref(table); |
||||
} |
||||
|
||||
int grpc_method_config_table_cmp(const grpc_method_config_table* table1, |
||||
const grpc_method_config_table* table2) { |
||||
return grpc_mdstr_hash_table_cmp(table1, table2); |
||||
} |
||||
|
||||
grpc_method_config* grpc_method_config_table_get_method_config( |
||||
const grpc_method_config_table* table, const grpc_mdstr* path) { |
||||
grpc_method_config* method_config = grpc_mdstr_hash_table_get(table, path); |
||||
// If we didn't find a match for the path, try looking for a wildcard
|
||||
// entry (i.e., change "/service/method" to "/service/*").
|
||||
if (method_config == NULL) { |
||||
const char* path_str = grpc_mdstr_as_c_string(path); |
||||
const char* sep = strrchr(path_str, '/') + 1; |
||||
const size_t len = (size_t)(sep - path_str); |
||||
char* buf = gpr_malloc(len + 2); // '*' and NUL
|
||||
memcpy(buf, path_str, len); |
||||
buf[len] = '*'; |
||||
buf[len + 1] = '\0'; |
||||
grpc_mdstr* wildcard_path = grpc_mdstr_from_string(buf); |
||||
gpr_free(buf); |
||||
method_config = grpc_mdstr_hash_table_get(table, wildcard_path); |
||||
GRPC_MDSTR_UNREF(wildcard_path); |
||||
} |
||||
return method_config; |
||||
} |
||||
|
||||
static void* copy_arg(void* p) { return grpc_method_config_table_ref(p); } |
||||
|
||||
static void destroy_arg(void* p) { grpc_method_config_table_unref(p); } |
||||
|
||||
static int cmp_arg(void* p1, void* p2) { |
||||
return grpc_method_config_table_cmp(p1, p2); |
||||
} |
||||
|
||||
static grpc_arg_pointer_vtable arg_vtable = {copy_arg, destroy_arg, cmp_arg}; |
||||
|
||||
grpc_arg grpc_method_config_table_create_channel_arg( |
||||
grpc_method_config_table* table) { |
||||
grpc_arg arg; |
||||
arg.type = GRPC_ARG_POINTER; |
||||
arg.key = GRPC_ARG_SERVICE_CONFIG; |
||||
arg.value.pointer.p = table; |
||||
arg.value.pointer.vtable = &arg_vtable; |
||||
return arg; |
||||
} |
@ -0,0 +1,116 @@ |
||||
//
|
||||
// Copyright 2016, Google Inc.
|
||||
// All rights reserved.
|
||||
//
|
||||
// Redistribution and use in source and binary forms, with or without
|
||||
// modification, are permitted provided that the following conditions are
|
||||
// met:
|
||||
//
|
||||
// * Redistributions of source code must retain the above copyright
|
||||
// notice, this list of conditions and the following disclaimer.
|
||||
// * Redistributions in binary form must reproduce the above
|
||||
// copyright notice, this list of conditions and the following disclaimer
|
||||
// in the documentation and/or other materials provided with the
|
||||
// distribution.
|
||||
// * Neither the name of Google Inc. nor the names of its
|
||||
// contributors may be used to endorse or promote products derived from
|
||||
// this software without specific prior written permission.
|
||||
//
|
||||
// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
|
||||
// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
|
||||
// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
|
||||
// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
|
||||
// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
|
||||
// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
|
||||
// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
|
||||
// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
|
||||
// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
|
||||
// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
|
||||
// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
//
|
||||
|
||||
#ifndef GRPC_CORE_EXT_CLIENT_CONFIG_METHOD_CONFIG_H |
||||
#define GRPC_CORE_EXT_CLIENT_CONFIG_METHOD_CONFIG_H |
||||
|
||||
#include <stdbool.h> |
||||
|
||||
#include <grpc/impl/codegen/gpr_types.h> |
||||
#include <grpc/impl/codegen/grpc_types.h> |
||||
|
||||
#include "src/core/lib/transport/mdstr_hash_table.h" |
||||
#include "src/core/lib/transport/metadata.h" |
||||
|
||||
/// Per-method configuration.
|
||||
typedef struct grpc_method_config grpc_method_config; |
||||
|
||||
/// Creates a grpc_method_config with the specified parameters.
|
||||
/// Any parameter may be NULL to indicate that the value is unset.
|
||||
///
|
||||
/// \a wait_for_ready indicates whether the client should wait until the
|
||||
/// request deadline for the channel to become ready, even if there is a
|
||||
/// temporary failure before the deadline while attempting to connect.
|
||||
///
|
||||
/// \a timeout indicates the timeout for calls.
|
||||
///
|
||||
/// \a max_request_message_bytes and \a max_response_message_bytes
|
||||
/// indicate the maximum sizes of the request (checked when sending) and
|
||||
/// response (checked when receiving) messages.
|
||||
grpc_method_config* grpc_method_config_create( |
||||
bool* wait_for_ready, gpr_timespec* timeout, |
||||
int32_t* max_request_message_bytes, int32_t* max_response_message_bytes); |
||||
|
||||
grpc_method_config* grpc_method_config_ref(grpc_method_config* method_config); |
||||
void grpc_method_config_unref(grpc_method_config* method_config); |
||||
|
||||
/// Compares two grpc_method_configs.
|
||||
/// The sort order is stable but undefined.
|
||||
int grpc_method_config_cmp(const grpc_method_config* method_config1, |
||||
const grpc_method_config* method_config2); |
||||
|
||||
/// These methods return NULL if the requested field is unset.
|
||||
/// The caller does NOT take ownership of the result.
|
||||
const bool* grpc_method_config_get_wait_for_ready( |
||||
const grpc_method_config* method_config); |
||||
const gpr_timespec* grpc_method_config_get_timeout( |
||||
const grpc_method_config* method_config); |
||||
const int32_t* grpc_method_config_get_max_request_message_bytes( |
||||
const grpc_method_config* method_config); |
||||
const int32_t* grpc_method_config_get_max_response_message_bytes( |
||||
const grpc_method_config* method_config); |
||||
|
||||
/// A table of method configs.
|
||||
typedef grpc_mdstr_hash_table grpc_method_config_table; |
||||
|
||||
typedef struct grpc_method_config_table_entry { |
||||
/// The name is of one of the following forms:
|
||||
/// service/method -- specifies exact service and method name
|
||||
/// service/* -- matches all methods for the specified service
|
||||
grpc_mdstr* method_name; |
||||
grpc_method_config* method_config; |
||||
} grpc_method_config_table_entry; |
||||
|
||||
/// Takes new references to all keys and values in \a entries.
|
||||
grpc_method_config_table* grpc_method_config_table_create( |
||||
size_t num_entries, grpc_method_config_table_entry* entries); |
||||
|
||||
grpc_method_config_table* grpc_method_config_table_ref( |
||||
grpc_method_config_table* table); |
||||
void grpc_method_config_table_unref(grpc_method_config_table* table); |
||||
|
||||
/// Compares two grpc_method_config_tables.
|
||||
/// The sort order is stable but undefined.
|
||||
int grpc_method_config_table_cmp(const grpc_method_config_table* table1, |
||||
const grpc_method_config_table* table2); |
||||
|
||||
/// Gets the method config for the specified \a path, which should be of
|
||||
/// the form "/service/method".
|
||||
/// Returns NULL if the method has no config.
|
||||
/// Caller does NOT own a reference to the result.
|
||||
grpc_method_config* grpc_method_config_table_get_method_config( |
||||
const grpc_method_config_table* table, const grpc_mdstr* path); |
||||
|
||||
/// Returns a channel arg containing \a table.
|
||||
grpc_arg grpc_method_config_table_create_channel_arg( |
||||
grpc_method_config_table* table); |
||||
|
||||
#endif /* GRPC_CORE_EXT_CLIENT_CONFIG_METHOD_CONFIG_H */ |
@ -0,0 +1,142 @@ |
||||
//
|
||||
// Copyright 2016, Google Inc.
|
||||
// All rights reserved.
|
||||
//
|
||||
// Redistribution and use in source and binary forms, with or without
|
||||
// modification, are permitted provided that the following conditions are
|
||||
// met:
|
||||
//
|
||||
// * Redistributions of source code must retain the above copyright
|
||||
// notice, this list of conditions and the following disclaimer.
|
||||
// * Redistributions in binary form must reproduce the above
|
||||
// copyright notice, this list of conditions and the following disclaimer
|
||||
// in the documentation and/or other materials provided with the
|
||||
// distribution.
|
||||
// * Neither the name of Google Inc. nor the names of its
|
||||
// contributors may be used to endorse or promote products derived from
|
||||
// this software without specific prior written permission.
|
||||
//
|
||||
// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
|
||||
// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
|
||||
// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
|
||||
// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
|
||||
// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
|
||||
// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
|
||||
// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
|
||||
// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
|
||||
// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
|
||||
// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
|
||||
// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
//
|
||||
|
||||
#include "src/core/lib/transport/mdstr_hash_table.h" |
||||
|
||||
#include <stdbool.h> |
||||
#include <string.h> |
||||
|
||||
#include <grpc/support/alloc.h> |
||||
#include <grpc/support/log.h> |
||||
|
||||
#include "src/core/lib/transport/metadata.h" |
||||
|
||||
struct grpc_mdstr_hash_table { |
||||
gpr_refcount refs; |
||||
size_t num_entries; |
||||
grpc_mdstr_hash_table_entry* entries; |
||||
}; |
||||
|
||||
// Helper function for insert and get operations that performs quadratic
|
||||
// probing (https://en.wikipedia.org/wiki/Quadratic_probing).
|
||||
static size_t grpc_mdstr_hash_table_find_index( |
||||
const grpc_mdstr_hash_table* table, const grpc_mdstr* key, |
||||
bool find_empty) { |
||||
for (size_t i = 0; i < table->num_entries; ++i) { |
||||
const size_t idx = (key->hash + i * i) % table->num_entries; |
||||
if (table->entries[idx].key == NULL) |
||||
return find_empty ? idx : table->num_entries; |
||||
if (table->entries[idx].key == key) return idx; |
||||
} |
||||
return table->num_entries; // Not found.
|
||||
} |
||||
|
||||
static void grpc_mdstr_hash_table_add( |
||||
grpc_mdstr_hash_table* table, grpc_mdstr* key, void* value, |
||||
const grpc_mdstr_hash_table_vtable* vtable) { |
||||
GPR_ASSERT(value != NULL); |
||||
const size_t idx = |
||||
grpc_mdstr_hash_table_find_index(table, key, true /* find_empty */); |
||||
GPR_ASSERT(idx != table->num_entries); // Table should never be full.
|
||||
grpc_mdstr_hash_table_entry* entry = &table->entries[idx]; |
||||
entry->key = GRPC_MDSTR_REF(key); |
||||
entry->value = vtable->copy_value(value); |
||||
entry->vtable = vtable; |
||||
} |
||||
|
||||
grpc_mdstr_hash_table* grpc_mdstr_hash_table_create( |
||||
size_t num_entries, grpc_mdstr_hash_table_entry* entries) { |
||||
grpc_mdstr_hash_table* table = gpr_malloc(sizeof(*table)); |
||||
memset(table, 0, sizeof(*table)); |
||||
gpr_ref_init(&table->refs, 1); |
||||
// Quadratic probing gets best performance when the table is no more
|
||||
// than half full.
|
||||
table->num_entries = num_entries * 2; |
||||
const size_t entry_size = |
||||
sizeof(grpc_mdstr_hash_table_entry) * table->num_entries; |
||||
table->entries = gpr_malloc(entry_size); |
||||
memset(table->entries, 0, entry_size); |
||||
for (size_t i = 0; i < num_entries; ++i) { |
||||
grpc_mdstr_hash_table_entry* entry = &entries[i]; |
||||
grpc_mdstr_hash_table_add(table, entry->key, entry->value, entry->vtable); |
||||
} |
||||
return table; |
||||
} |
||||
|
||||
grpc_mdstr_hash_table* grpc_mdstr_hash_table_ref(grpc_mdstr_hash_table* table) { |
||||
if (table != NULL) gpr_ref(&table->refs); |
||||
return table; |
||||
} |
||||
|
||||
int grpc_mdstr_hash_table_unref(grpc_mdstr_hash_table* table) { |
||||
if (table != NULL && gpr_unref(&table->refs)) { |
||||
for (size_t i = 0; i < table->num_entries; ++i) { |
||||
grpc_mdstr_hash_table_entry* entry = &table->entries[i]; |
||||
if (entry->key != NULL) { |
||||
GRPC_MDSTR_UNREF(entry->key); |
||||
entry->vtable->destroy_value(entry->value); |
||||
} |
||||
} |
||||
gpr_free(table->entries); |
||||
gpr_free(table); |
||||
return 1; |
||||
} |
||||
return 0; |
||||
} |
||||
|
||||
void* grpc_mdstr_hash_table_get(const grpc_mdstr_hash_table* table, |
||||
const grpc_mdstr* key) { |
||||
const size_t idx = |
||||
grpc_mdstr_hash_table_find_index(table, key, false /* find_empty */); |
||||
if (idx == table->num_entries) return NULL; // Not found.
|
||||
return table->entries[idx].value; |
||||
} |
||||
|
||||
int grpc_mdstr_hash_table_cmp(const grpc_mdstr_hash_table* table1, |
||||
const grpc_mdstr_hash_table* table2) { |
||||
// Compare by num_entries.
|
||||
if (table1->num_entries < table2->num_entries) return -1; |
||||
if (table1->num_entries > table2->num_entries) return 1; |
||||
for (size_t i = 0; i < table1->num_entries; ++i) { |
||||
grpc_mdstr_hash_table_entry* e1 = &table1->entries[i]; |
||||
grpc_mdstr_hash_table_entry* e2 = &table2->entries[i]; |
||||
// Compare keys by hash value.
|
||||
if (e1->key->hash < e2->key->hash) return -1; |
||||
if (e1->key->hash > e2->key->hash) return 1; |
||||
// Compare by vtable (pointer equality).
|
||||
if (e1->vtable < e2->vtable) return -1; |
||||
if (e1->vtable > e2->vtable) return 1; |
||||
// Compare values via vtable.
|
||||
const int value_result = e1->vtable->compare_value(e1->value, e2->value); |
||||
if (value_result != 0) return value_result; |
||||
} |
||||
return 0; |
||||
} |
@ -0,0 +1,83 @@ |
||||
/*
|
||||
* Copyright 2016, Google Inc. |
||||
* All rights reserved. |
||||
* |
||||
* Redistribution and use in source and binary forms, with or without |
||||
* modification, are permitted provided that the following conditions are |
||||
* met: |
||||
* |
||||
* * Redistributions of source code must retain the above copyright |
||||
* notice, this list of conditions and the following disclaimer. |
||||
* * Redistributions in binary form must reproduce the above |
||||
* copyright notice, this list of conditions and the following disclaimer |
||||
* in the documentation and/or other materials provided with the |
||||
* distribution. |
||||
* * Neither the name of Google Inc. nor the names of its |
||||
* contributors may be used to endorse or promote products derived from |
||||
* this software without specific prior written permission. |
||||
* |
||||
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS |
||||
* "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT |
||||
* LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR |
||||
* A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT |
||||
* OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, |
||||
* SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT |
||||
* LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, |
||||
* DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY |
||||
* THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT |
||||
* (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE |
||||
* OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. |
||||
*/ |
||||
|
||||
#ifndef GRPC_CORE_LIB_TRANSPORT_MDSTR_HASH_TABLE_H |
||||
#define GRPC_CORE_LIB_TRANSPORT_MDSTR_HASH_TABLE_H |
||||
|
||||
#include "src/core/lib/transport/metadata.h" |
||||
|
||||
/** Hash table implementation.
|
||||
* |
||||
* This implementation uses open addressing |
||||
* (https://en.wikipedia.org/wiki/Open_addressing) with quadratic
|
||||
* probing (https://en.wikipedia.org/wiki/Quadratic_probing).
|
||||
* |
||||
* The keys are \a grpc_mdstr objects. The values are arbitrary pointers |
||||
* with a common vtable. |
||||
* |
||||
* Hash tables are intentionally immutable, to avoid the need for locking. |
||||
*/ |
||||
|
||||
typedef struct grpc_mdstr_hash_table grpc_mdstr_hash_table; |
||||
|
||||
typedef struct grpc_mdstr_hash_table_vtable { |
||||
void (*destroy_value)(void* value); |
||||
void* (*copy_value)(void* value); |
||||
int (*compare_value)(void* value1, void* value2); |
||||
} grpc_mdstr_hash_table_vtable; |
||||
|
||||
typedef struct grpc_mdstr_hash_table_entry { |
||||
grpc_mdstr* key; |
||||
void* value; /* Must not be NULL. */ |
||||
const grpc_mdstr_hash_table_vtable* vtable; |
||||
} grpc_mdstr_hash_table_entry; |
||||
|
||||
/** Creates a new hash table of containing \a entries, which is an array
|
||||
of length \a num_entries. |
||||
Creates its own copy of all keys and values from \a entries. */ |
||||
grpc_mdstr_hash_table* grpc_mdstr_hash_table_create( |
||||
size_t num_entries, grpc_mdstr_hash_table_entry* entries); |
||||
|
||||
grpc_mdstr_hash_table* grpc_mdstr_hash_table_ref(grpc_mdstr_hash_table* table); |
||||
/** Returns 1 when \a table is destroyed. */ |
||||
int grpc_mdstr_hash_table_unref(grpc_mdstr_hash_table* table); |
||||
|
||||
/** Returns the value from \a table associated with \a key.
|
||||
Returns NULL if \a key is not found. */ |
||||
void* grpc_mdstr_hash_table_get(const grpc_mdstr_hash_table* table, |
||||
const grpc_mdstr* key); |
||||
|
||||
/** Compares two hash tables.
|
||||
The sort order is stable but undefined. */ |
||||
int grpc_mdstr_hash_table_cmp(const grpc_mdstr_hash_table* table1, |
||||
const grpc_mdstr_hash_table* table2); |
||||
|
||||
#endif /* GRPC_CORE_LIB_TRANSPORT_MDSTR_HASH_TABLE_H */ |
@ -0,0 +1,128 @@ |
||||
//
|
||||
// Copyright 2016, Google Inc.
|
||||
// All rights reserved.
|
||||
//
|
||||
// Redistribution and use in source and binary forms, with or without
|
||||
// modification, are permitted provided that the following conditions are
|
||||
// met:
|
||||
//
|
||||
// * Redistributions of source code must retain the above copyright
|
||||
// notice, this list of conditions and the following disclaimer.
|
||||
// * Redistributions in binary form must reproduce the above
|
||||
// copyright notice, this list of conditions and the following disclaimer
|
||||
// in the documentation and/or other materials provided with the
|
||||
// distribution.
|
||||
// * Neither the name of Google Inc. nor the names of its
|
||||
// contributors may be used to endorse or promote products derived from
|
||||
// this software without specific prior written permission.
|
||||
//
|
||||
// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
|
||||
// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
|
||||
// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
|
||||
// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
|
||||
// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
|
||||
// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
|
||||
// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
|
||||
// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
|
||||
// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
|
||||
// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
|
||||
// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
//
|
||||
|
||||
#include "test/core/end2end/end2end_tests.h" |
||||
|
||||
#include <string.h> |
||||
|
||||
#include <grpc/support/alloc.h> |
||||
#include <grpc/support/host_port.h> |
||||
#include <grpc/support/log.h> |
||||
#include <grpc/support/string_util.h> |
||||
#include <grpc/support/sync.h> |
||||
#include <grpc/support/thd.h> |
||||
#include <grpc/support/useful.h> |
||||
|
||||
#include "src/core/ext/client_config/client_channel.h" |
||||
#include "src/core/ext/transport/chttp2/transport/chttp2_transport.h" |
||||
#include "src/core/lib/channel/connected_channel.h" |
||||
#include "src/core/lib/channel/http_server_filter.h" |
||||
#include "src/core/lib/surface/channel.h" |
||||
#include "src/core/lib/surface/server.h" |
||||
#include "test/core/end2end/fake_resolver.h" |
||||
#include "test/core/util/port.h" |
||||
#include "test/core/util/test_config.h" |
||||
|
||||
typedef struct fullstack_fixture_data { |
||||
char *localaddr; |
||||
} fullstack_fixture_data; |
||||
|
||||
static grpc_end2end_test_fixture chttp2_create_fixture_fullstack( |
||||
grpc_channel_args *client_args, grpc_channel_args *server_args) { |
||||
grpc_end2end_test_fixture f; |
||||
int port = grpc_pick_unused_port_or_die(); |
||||
fullstack_fixture_data *ffd = gpr_malloc(sizeof(fullstack_fixture_data)); |
||||
memset(&f, 0, sizeof(f)); |
||||
|
||||
gpr_join_host_port(&ffd->localaddr, "127.0.0.1", port); |
||||
|
||||
f.fixture_data = ffd; |
||||
f.cq = grpc_completion_queue_create(NULL); |
||||
|
||||
return f; |
||||
} |
||||
|
||||
void chttp2_init_client_fullstack(grpc_end2end_test_fixture *f, |
||||
grpc_channel_args *client_args, |
||||
const char *query_args) { |
||||
fullstack_fixture_data *ffd = f->fixture_data; |
||||
char *server_uri; |
||||
gpr_asprintf(&server_uri, "test:%s%s%s", ffd->localaddr, |
||||
(query_args == NULL ? "" : "?"), |
||||
(query_args == NULL ? "" : query_args)); |
||||
gpr_log(GPR_INFO, "server_uri: %s", server_uri); |
||||
f->client = grpc_insecure_channel_create(server_uri, client_args, NULL); |
||||
GPR_ASSERT(f->client); |
||||
gpr_free(server_uri); |
||||
} |
||||
|
||||
void chttp2_init_server_fullstack(grpc_end2end_test_fixture *f, |
||||
grpc_channel_args *server_args) { |
||||
fullstack_fixture_data *ffd = f->fixture_data; |
||||
if (f->server) { |
||||
grpc_server_destroy(f->server); |
||||
} |
||||
f->server = grpc_server_create(server_args, NULL); |
||||
grpc_server_register_completion_queue(f->server, f->cq, NULL); |
||||
GPR_ASSERT(grpc_server_add_insecure_http2_port(f->server, ffd->localaddr)); |
||||
grpc_server_start(f->server); |
||||
} |
||||
|
||||
void chttp2_tear_down_fullstack(grpc_end2end_test_fixture *f) { |
||||
fullstack_fixture_data *ffd = f->fixture_data; |
||||
gpr_free(ffd->localaddr); |
||||
gpr_free(ffd); |
||||
} |
||||
|
||||
/* All test configurations */ |
||||
static grpc_end2end_test_config configs[] = { |
||||
{"chttp2/fullstack", FEATURE_MASK_SUPPORTS_DELAYED_CONNECTION | |
||||
FEATURE_MASK_SUPPORTS_QUERY_ARGS, |
||||
chttp2_create_fixture_fullstack, chttp2_init_client_fullstack, |
||||
chttp2_init_server_fullstack, chttp2_tear_down_fullstack}, |
||||
}; |
||||
|
||||
int main(int argc, char **argv) { |
||||
size_t i; |
||||
|
||||
grpc_test_init(argc, argv); |
||||
grpc_end2end_tests_pre_init(); |
||||
grpc_fake_resolver_init(); |
||||
grpc_init(); |
||||
|
||||
for (i = 0; i < sizeof(configs) / sizeof(*configs); i++) { |
||||
grpc_end2end_tests(argc, argv, configs[i]); |
||||
} |
||||
|
||||
grpc_shutdown(); |
||||
|
||||
return 0; |
||||
} |
Some files were not shown because too many files have changed in this diff Show More
Loading…
Reference in new issue