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