mirror of https://github.com/grpc/grpc.git
Merge pull request #14450 from markdroth/c++_service_config
Convert slice hash table and service config code to C++reviewable/pr10684/r30^2
commit
02a8d09cae
35 changed files with 1120 additions and 1000 deletions
@ -0,0 +1,103 @@ |
|||||||
|
/*
|
||||||
|
* |
||||||
|
* Copyright 2015 gRPC authors. |
||||||
|
* |
||||||
|
* Licensed under the Apache License, Version 2.0 (the "License"); |
||||||
|
* you may not use this file except in compliance with the License. |
||||||
|
* You may obtain a copy of the License at |
||||||
|
* |
||||||
|
* http://www.apache.org/licenses/LICENSE-2.0
|
||||||
|
* |
||||||
|
* Unless required by applicable law or agreed to in writing, software |
||||||
|
* distributed under the License is distributed on an "AS IS" BASIS, |
||||||
|
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. |
||||||
|
* See the License for the specific language governing permissions and |
||||||
|
* limitations under the License. |
||||||
|
* |
||||||
|
*/ |
||||||
|
|
||||||
|
#include <grpc/support/port_platform.h> |
||||||
|
|
||||||
|
#include <stdio.h> |
||||||
|
#include <string.h> |
||||||
|
|
||||||
|
#include <grpc/support/alloc.h> |
||||||
|
#include <grpc/support/log.h> |
||||||
|
#include <grpc/support/string_util.h> |
||||||
|
|
||||||
|
#include "src/core/ext/filters/client_channel/method_params.h" |
||||||
|
#include "src/core/lib/gpr/string.h" |
||||||
|
#include "src/core/lib/gprpp/memory.h" |
||||||
|
|
||||||
|
namespace grpc_core { |
||||||
|
namespace internal { |
||||||
|
|
||||||
|
namespace { |
||||||
|
|
||||||
|
bool ParseWaitForReady( |
||||||
|
grpc_json* field, ClientChannelMethodParams::WaitForReady* wait_for_ready) { |
||||||
|
if (field->type != GRPC_JSON_TRUE && field->type != GRPC_JSON_FALSE) { |
||||||
|
return false; |
||||||
|
} |
||||||
|
*wait_for_ready = field->type == GRPC_JSON_TRUE |
||||||
|
? ClientChannelMethodParams::WAIT_FOR_READY_TRUE |
||||||
|
: ClientChannelMethodParams::WAIT_FOR_READY_FALSE; |
||||||
|
return true; |
||||||
|
} |
||||||
|
|
||||||
|
// Parses a JSON field of the form generated for a google.proto.Duration
|
||||||
|
// proto message.
|
||||||
|
bool ParseDuration(grpc_json* field, grpc_millis* duration) { |
||||||
|
if (field->type != GRPC_JSON_STRING) return false; |
||||||
|
size_t len = strlen(field->value); |
||||||
|
if (field->value[len - 1] != 's') return false; |
||||||
|
UniquePtr<char> buf(gpr_strdup(field->value)); |
||||||
|
*(buf.get() + len - 1) = '\0'; // Remove trailing 's'.
|
||||||
|
char* decimal_point = strchr(buf.get(), '.'); |
||||||
|
int nanos = 0; |
||||||
|
if (decimal_point != nullptr) { |
||||||
|
*decimal_point = '\0'; |
||||||
|
nanos = gpr_parse_nonnegative_int(decimal_point + 1); |
||||||
|
if (nanos == -1) { |
||||||
|
return false; |
||||||
|
} |
||||||
|
int num_digits = (int)strlen(decimal_point + 1); |
||||||
|
if (num_digits > 9) { // We don't accept greater precision than nanos.
|
||||||
|
return false; |
||||||
|
} |
||||||
|
for (int i = 0; i < (9 - num_digits); ++i) { |
||||||
|
nanos *= 10; |
||||||
|
} |
||||||
|
} |
||||||
|
int seconds = |
||||||
|
decimal_point == buf.get() ? 0 : gpr_parse_nonnegative_int(buf.get()); |
||||||
|
if (seconds == -1) return false; |
||||||
|
*duration = seconds * GPR_MS_PER_SEC + nanos / GPR_NS_PER_MS; |
||||||
|
return true; |
||||||
|
} |
||||||
|
|
||||||
|
} // namespace
|
||||||
|
|
||||||
|
RefCountedPtr<ClientChannelMethodParams> |
||||||
|
ClientChannelMethodParams::CreateFromJson(const grpc_json* json) { |
||||||
|
RefCountedPtr<ClientChannelMethodParams> method_params = |
||||||
|
MakeRefCounted<ClientChannelMethodParams>(); |
||||||
|
for (grpc_json* field = json->child; field != nullptr; field = field->next) { |
||||||
|
if (field->key == nullptr) continue; |
||||||
|
if (strcmp(field->key, "waitForReady") == 0) { |
||||||
|
if (method_params->wait_for_ready_ != WAIT_FOR_READY_UNSET) { |
||||||
|
return nullptr; // Duplicate.
|
||||||
|
} |
||||||
|
if (!ParseWaitForReady(field, &method_params->wait_for_ready_)) { |
||||||
|
return nullptr; |
||||||
|
} |
||||||
|
} else if (strcmp(field->key, "timeout") == 0) { |
||||||
|
if (method_params->timeout_ > 0) return nullptr; // Duplicate.
|
||||||
|
if (!ParseDuration(field, &method_params->timeout_)) return nullptr; |
||||||
|
} |
||||||
|
} |
||||||
|
return method_params; |
||||||
|
} |
||||||
|
|
||||||
|
} // namespace internal
|
||||||
|
} // namespace grpc_core
|
@ -0,0 +1,63 @@ |
|||||||
|
/*
|
||||||
|
* |
||||||
|
* Copyright 2015 gRPC authors. |
||||||
|
* |
||||||
|
* Licensed under the Apache License, Version 2.0 (the "License"); |
||||||
|
* you may not use this file except in compliance with the License. |
||||||
|
* You may obtain a copy of the License at |
||||||
|
* |
||||||
|
* http://www.apache.org/licenses/LICENSE-2.0
|
||||||
|
* |
||||||
|
* Unless required by applicable law or agreed to in writing, software |
||||||
|
* distributed under the License is distributed on an "AS IS" BASIS, |
||||||
|
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. |
||||||
|
* See the License for the specific language governing permissions and |
||||||
|
* limitations under the License. |
||||||
|
* |
||||||
|
*/ |
||||||
|
|
||||||
|
#ifndef GRPC_CORE_EXT_FILTERS_CLIENT_CHANNEL_METHOD_PARAMS_H |
||||||
|
#define GRPC_CORE_EXT_FILTERS_CLIENT_CHANNEL_METHOD_PARAMS_H |
||||||
|
|
||||||
|
#include <grpc/support/port_platform.h> |
||||||
|
|
||||||
|
#include "src/core/lib/gprpp/ref_counted.h" |
||||||
|
#include "src/core/lib/gprpp/ref_counted_ptr.h" |
||||||
|
#include "src/core/lib/iomgr/exec_ctx.h" // for grpc_millis |
||||||
|
#include "src/core/lib/json/json.h" |
||||||
|
|
||||||
|
namespace grpc_core { |
||||||
|
namespace internal { |
||||||
|
|
||||||
|
class ClientChannelMethodParams : public RefCounted<ClientChannelMethodParams> { |
||||||
|
public: |
||||||
|
enum WaitForReady { |
||||||
|
WAIT_FOR_READY_UNSET = 0, |
||||||
|
WAIT_FOR_READY_FALSE, |
||||||
|
WAIT_FOR_READY_TRUE |
||||||
|
}; |
||||||
|
|
||||||
|
/// Creates a method_parameters object from \a json.
|
||||||
|
/// Intended for use with ServiceConfig::CreateMethodConfigTable().
|
||||||
|
static RefCountedPtr<ClientChannelMethodParams> CreateFromJson( |
||||||
|
const grpc_json* json); |
||||||
|
|
||||||
|
grpc_millis timeout() const { return timeout_; } |
||||||
|
WaitForReady wait_for_ready() const { return wait_for_ready_; } |
||||||
|
|
||||||
|
private: |
||||||
|
// So New() can call our private ctor.
|
||||||
|
template <typename T, typename... Args> |
||||||
|
friend T* grpc_core::New(Args&&... args); |
||||||
|
|
||||||
|
ClientChannelMethodParams() {} |
||||||
|
virtual ~ClientChannelMethodParams() {} |
||||||
|
|
||||||
|
grpc_millis timeout_ = 0; |
||||||
|
WaitForReady wait_for_ready_ = WAIT_FOR_READY_UNSET; |
||||||
|
}; |
||||||
|
|
||||||
|
} // namespace internal
|
||||||
|
} // namespace grpc_core
|
||||||
|
|
||||||
|
#endif /* GRPC_CORE_EXT_FILTERS_CLIENT_CHANNEL_METHOD_PARAMS_H */ |
@ -1,61 +0,0 @@ |
|||||||
/*
|
|
||||||
* |
|
||||||
* Copyright 2017 gRPC authors. |
|
||||||
* |
|
||||||
* Licensed under the Apache License, Version 2.0 (the "License"); |
|
||||||
* you may not use this file except in compliance with the License. |
|
||||||
* You may obtain a copy of the License at |
|
||||||
* |
|
||||||
* http://www.apache.org/licenses/LICENSE-2.0
|
|
||||||
* |
|
||||||
* Unless required by applicable law or agreed to in writing, software |
|
||||||
* distributed under the License is distributed on an "AS IS" BASIS, |
|
||||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. |
|
||||||
* See the License for the specific language governing permissions and |
|
||||||
* limitations under the License. |
|
||||||
* |
|
||||||
*/ |
|
||||||
|
|
||||||
#include <grpc/support/port_platform.h> |
|
||||||
|
|
||||||
#include <grpc/support/log.h> |
|
||||||
|
|
||||||
#include "src/core/lib/channel/channel_args.h" |
|
||||||
#include "src/core/lib/security/transport/lb_targets_info.h" |
|
||||||
|
|
||||||
/* Channel arg key for the mapping of LB server addresses to their names for
|
|
||||||
* secure naming purposes. */ |
|
||||||
#define GRPC_ARG_LB_SECURE_NAMING_MAP "grpc.lb_secure_naming_map" |
|
||||||
|
|
||||||
static void* targets_info_copy(void* p) { |
|
||||||
return grpc_slice_hash_table_ref(static_cast<grpc_slice_hash_table*>(p)); |
|
||||||
} |
|
||||||
static void targets_info_destroy(void* p) { |
|
||||||
grpc_slice_hash_table_unref(static_cast<grpc_slice_hash_table*>(p)); |
|
||||||
} |
|
||||||
static int targets_info_cmp(void* a, void* b) { |
|
||||||
return grpc_slice_hash_table_cmp( |
|
||||||
static_cast<const grpc_slice_hash_table*>(a), |
|
||||||
static_cast<const grpc_slice_hash_table*>(b)); |
|
||||||
} |
|
||||||
static const grpc_arg_pointer_vtable server_to_balancer_names_vtable = { |
|
||||||
targets_info_copy, targets_info_destroy, targets_info_cmp}; |
|
||||||
|
|
||||||
grpc_arg grpc_lb_targets_info_create_channel_arg( |
|
||||||
grpc_slice_hash_table* targets_info) { |
|
||||||
return grpc_channel_arg_pointer_create((char*)GRPC_ARG_LB_SECURE_NAMING_MAP, |
|
||||||
targets_info, |
|
||||||
&server_to_balancer_names_vtable); |
|
||||||
} |
|
||||||
|
|
||||||
grpc_slice_hash_table* grpc_lb_targets_info_find_in_args( |
|
||||||
const grpc_channel_args* args) { |
|
||||||
const grpc_arg* targets_info_arg = |
|
||||||
grpc_channel_args_find(args, GRPC_ARG_LB_SECURE_NAMING_MAP); |
|
||||||
if (targets_info_arg != nullptr) { |
|
||||||
GPR_ASSERT(targets_info_arg->type == GRPC_ARG_POINTER); |
|
||||||
return static_cast<grpc_slice_hash_table*>( |
|
||||||
targets_info_arg->value.pointer.p); |
|
||||||
} |
|
||||||
return nullptr; |
|
||||||
} |
|
@ -0,0 +1,75 @@ |
|||||||
|
/*
|
||||||
|
* |
||||||
|
* Copyright 2017 gRPC authors. |
||||||
|
* |
||||||
|
* Licensed under the Apache License, Version 2.0 (the "License"); |
||||||
|
* you may not use this file except in compliance with the License. |
||||||
|
* You may obtain a copy of the License at |
||||||
|
* |
||||||
|
* http://www.apache.org/licenses/LICENSE-2.0
|
||||||
|
* |
||||||
|
* Unless required by applicable law or agreed to in writing, software |
||||||
|
* distributed under the License is distributed on an "AS IS" BASIS, |
||||||
|
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. |
||||||
|
* See the License for the specific language governing permissions and |
||||||
|
* limitations under the License. |
||||||
|
* |
||||||
|
*/ |
||||||
|
|
||||||
|
#include <grpc/support/port_platform.h> |
||||||
|
|
||||||
|
#include <grpc/support/log.h> |
||||||
|
|
||||||
|
#include "src/core/lib/channel/channel_args.h" |
||||||
|
#include "src/core/lib/security/transport/target_authority_table.h" |
||||||
|
|
||||||
|
// Channel arg key for the mapping of target addresses to their authorities.
|
||||||
|
#define GRPC_ARG_TARGET_AUTHORITY_TABLE "grpc.target_authority_table" |
||||||
|
|
||||||
|
namespace grpc_core { |
||||||
|
namespace { |
||||||
|
|
||||||
|
void* target_authority_table_copy(void* p) { |
||||||
|
TargetAuthorityTable* table = static_cast<TargetAuthorityTable*>(p); |
||||||
|
// TODO(roth): When channel_args are converted to C++, pass the
|
||||||
|
// RefCountedPtr<> directly instead of managing the ref manually.
|
||||||
|
table->Ref().release(); |
||||||
|
return p; |
||||||
|
} |
||||||
|
void target_authority_table_destroy(void* p) { |
||||||
|
TargetAuthorityTable* table = static_cast<TargetAuthorityTable*>(p); |
||||||
|
table->Unref(); |
||||||
|
} |
||||||
|
int target_authority_table_cmp(void* a, void* b) { |
||||||
|
return TargetAuthorityTable::Cmp( |
||||||
|
*static_cast<const TargetAuthorityTable*>(a), |
||||||
|
*static_cast<const TargetAuthorityTable*>(b)); |
||||||
|
} |
||||||
|
const grpc_arg_pointer_vtable target_authority_table_arg_vtable = { |
||||||
|
target_authority_table_copy, target_authority_table_destroy, |
||||||
|
target_authority_table_cmp}; |
||||||
|
|
||||||
|
} // namespace
|
||||||
|
|
||||||
|
grpc_arg CreateTargetAuthorityTableChannelArg(TargetAuthorityTable* table) { |
||||||
|
return grpc_channel_arg_pointer_create((char*)GRPC_ARG_TARGET_AUTHORITY_TABLE, |
||||||
|
table, |
||||||
|
&target_authority_table_arg_vtable); |
||||||
|
} |
||||||
|
|
||||||
|
TargetAuthorityTable* FindTargetAuthorityTableInArgs( |
||||||
|
const grpc_channel_args* args) { |
||||||
|
const grpc_arg* arg = |
||||||
|
grpc_channel_args_find(args, GRPC_ARG_TARGET_AUTHORITY_TABLE); |
||||||
|
if (arg != nullptr) { |
||||||
|
if (arg->type == GRPC_ARG_POINTER) { |
||||||
|
return static_cast<TargetAuthorityTable*>(arg->value.pointer.p); |
||||||
|
} else { |
||||||
|
gpr_log(GPR_ERROR, "value of " GRPC_ARG_TARGET_AUTHORITY_TABLE |
||||||
|
" channel arg was not pointer type; ignoring"); |
||||||
|
} |
||||||
|
} |
||||||
|
return nullptr; |
||||||
|
} |
||||||
|
|
||||||
|
} // namespace grpc_core
|
@ -1,147 +0,0 @@ |
|||||||
//
|
|
||||||
// Copyright 2016 gRPC authors.
|
|
||||||
//
|
|
||||||
// Licensed under the Apache License, Version 2.0 (the "License");
|
|
||||||
// you may not use this file except in compliance with the License.
|
|
||||||
// You may obtain a copy of the License at
|
|
||||||
//
|
|
||||||
// http://www.apache.org/licenses/LICENSE-2.0
|
|
||||||
//
|
|
||||||
// Unless required by applicable law or agreed to in writing, software
|
|
||||||
// distributed under the License is distributed on an "AS IS" BASIS,
|
|
||||||
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
|
||||||
// See the License for the specific language governing permissions and
|
|
||||||
// limitations under the License.
|
|
||||||
//
|
|
||||||
|
|
||||||
#include <grpc/support/port_platform.h> |
|
||||||
|
|
||||||
#include "src/core/lib/slice/slice_hash_table.h" |
|
||||||
|
|
||||||
#include <stdbool.h> |
|
||||||
#include <string.h> |
|
||||||
|
|
||||||
#include <grpc/support/alloc.h> |
|
||||||
#include <grpc/support/log.h> |
|
||||||
|
|
||||||
#include "src/core/lib/slice/slice_internal.h" |
|
||||||
#include "src/core/lib/transport/metadata.h" |
|
||||||
|
|
||||||
struct grpc_slice_hash_table { |
|
||||||
gpr_refcount refs; |
|
||||||
void (*destroy_value)(void* value); |
|
||||||
int (*value_cmp)(void* a, void* b); |
|
||||||
size_t size; |
|
||||||
size_t max_num_probes; |
|
||||||
grpc_slice_hash_table_entry* entries; |
|
||||||
}; |
|
||||||
|
|
||||||
static bool is_empty(grpc_slice_hash_table_entry* entry) { |
|
||||||
return entry->value == nullptr; |
|
||||||
} |
|
||||||
|
|
||||||
static void grpc_slice_hash_table_add(grpc_slice_hash_table* table, |
|
||||||
grpc_slice key, void* value) { |
|
||||||
GPR_ASSERT(value != nullptr); |
|
||||||
const size_t hash = grpc_slice_hash(key); |
|
||||||
for (size_t offset = 0; offset < table->size; ++offset) { |
|
||||||
const size_t idx = (hash + offset) % table->size; |
|
||||||
if (is_empty(&table->entries[idx])) { |
|
||||||
table->entries[idx].key = key; |
|
||||||
table->entries[idx].value = value; |
|
||||||
// Keep track of the maximum number of probes needed, since this
|
|
||||||
// provides an upper bound for lookups.
|
|
||||||
if (offset > table->max_num_probes) table->max_num_probes = offset; |
|
||||||
return; |
|
||||||
} |
|
||||||
} |
|
||||||
GPR_ASSERT(false); // Table should never be full.
|
|
||||||
} |
|
||||||
|
|
||||||
grpc_slice_hash_table* grpc_slice_hash_table_create( |
|
||||||
size_t num_entries, grpc_slice_hash_table_entry* entries, |
|
||||||
void (*destroy_value)(void* value), int (*value_cmp)(void* a, void* b)) { |
|
||||||
grpc_slice_hash_table* table = |
|
||||||
static_cast<grpc_slice_hash_table*>(gpr_zalloc(sizeof(*table))); |
|
||||||
gpr_ref_init(&table->refs, 1); |
|
||||||
table->destroy_value = destroy_value; |
|
||||||
table->value_cmp = value_cmp; |
|
||||||
// Keep load factor low to improve performance of lookups.
|
|
||||||
table->size = num_entries * 2; |
|
||||||
const size_t entry_size = sizeof(grpc_slice_hash_table_entry) * table->size; |
|
||||||
table->entries = |
|
||||||
static_cast<grpc_slice_hash_table_entry*>(gpr_zalloc(entry_size)); |
|
||||||
for (size_t i = 0; i < num_entries; ++i) { |
|
||||||
grpc_slice_hash_table_entry* entry = &entries[i]; |
|
||||||
grpc_slice_hash_table_add(table, entry->key, entry->value); |
|
||||||
} |
|
||||||
return table; |
|
||||||
} |
|
||||||
|
|
||||||
grpc_slice_hash_table* grpc_slice_hash_table_ref(grpc_slice_hash_table* table) { |
|
||||||
if (table != nullptr) gpr_ref(&table->refs); |
|
||||||
return table; |
|
||||||
} |
|
||||||
|
|
||||||
void grpc_slice_hash_table_unref(grpc_slice_hash_table* table) { |
|
||||||
if (table != nullptr && gpr_unref(&table->refs)) { |
|
||||||
for (size_t i = 0; i < table->size; ++i) { |
|
||||||
grpc_slice_hash_table_entry* entry = &table->entries[i]; |
|
||||||
if (!is_empty(entry)) { |
|
||||||
grpc_slice_unref_internal(entry->key); |
|
||||||
table->destroy_value(entry->value); |
|
||||||
} |
|
||||||
} |
|
||||||
gpr_free(table->entries); |
|
||||||
gpr_free(table); |
|
||||||
} |
|
||||||
} |
|
||||||
|
|
||||||
void* grpc_slice_hash_table_get(const grpc_slice_hash_table* table, |
|
||||||
const grpc_slice key) { |
|
||||||
const size_t hash = grpc_slice_hash(key); |
|
||||||
// We cap the number of probes at the max number recorded when
|
|
||||||
// populating the table.
|
|
||||||
for (size_t offset = 0; offset <= table->max_num_probes; ++offset) { |
|
||||||
const size_t idx = (hash + offset) % table->size; |
|
||||||
if (is_empty(&table->entries[idx])) break; |
|
||||||
if (grpc_slice_eq(table->entries[idx].key, key)) { |
|
||||||
return table->entries[idx].value; |
|
||||||
} |
|
||||||
} |
|
||||||
return nullptr; // Not found.
|
|
||||||
} |
|
||||||
|
|
||||||
static int pointer_cmp(void* a, void* b) { return GPR_ICMP(a, b); } |
|
||||||
int grpc_slice_hash_table_cmp(const grpc_slice_hash_table* a, |
|
||||||
const grpc_slice_hash_table* b) { |
|
||||||
int (*const value_cmp_fn_a)(void* a, void* b) = |
|
||||||
a->value_cmp != nullptr ? a->value_cmp : pointer_cmp; |
|
||||||
int (*const value_cmp_fn_b)(void* a, void* b) = |
|
||||||
b->value_cmp != nullptr ? b->value_cmp : pointer_cmp; |
|
||||||
// Compare value_fns
|
|
||||||
const int value_fns_cmp = |
|
||||||
GPR_ICMP((void*)value_cmp_fn_a, (void*)value_cmp_fn_b); |
|
||||||
if (value_fns_cmp != 0) return value_fns_cmp; |
|
||||||
// Compare sizes
|
|
||||||
if (a->size < b->size) return -1; |
|
||||||
if (a->size > b->size) return 1; |
|
||||||
// Compare rows.
|
|
||||||
for (size_t i = 0; i < a->size; ++i) { |
|
||||||
if (is_empty(&a->entries[i])) { |
|
||||||
if (!is_empty(&b->entries[i])) { |
|
||||||
return -1; // a empty but b non-empty
|
|
||||||
} |
|
||||||
continue; // both empty, no need to check key or value
|
|
||||||
} else if (is_empty(&b->entries[i])) { |
|
||||||
return 1; // a non-empty but b empty
|
|
||||||
} |
|
||||||
// neither entry is empty
|
|
||||||
const int key_cmp = grpc_slice_cmp(a->entries[i].key, b->entries[i].key); |
|
||||||
if (key_cmp != 0) return key_cmp; |
|
||||||
const int value_cmp = |
|
||||||
value_cmp_fn_a(a->entries[i].value, b->entries[i].value); |
|
||||||
if (value_cmp != 0) return value_cmp; |
|
||||||
} |
|
||||||
return 0; |
|
||||||
} |
|
Loading…
Reference in new issue