mirror of https://github.com/grpc/grpc.git
commit
9ea0f2c6e8
116 changed files with 5992 additions and 2113 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