diff --git a/BUILD b/BUILD index 495af2a49cf..b4db5d56788 100644 --- a/BUILD +++ b/BUILD @@ -194,6 +194,7 @@ cc_library( "src/core/client_config/resolvers/sockaddr_resolver.h", "src/core/client_config/subchannel.h", "src/core/client_config/subchannel_factory.h", + "src/core/client_config/subchannel_index.h", "src/core/client_config/uri_parser.h", "src/core/compression/algorithm_metadata.h", "src/core/compression/message_compress.h", @@ -332,6 +333,7 @@ cc_library( "src/core/client_config/resolvers/sockaddr_resolver.c", "src/core/client_config/subchannel.c", "src/core/client_config/subchannel_factory.c", + "src/core/client_config/subchannel_index.c", "src/core/client_config/uri_parser.c", "src/core/compression/algorithm.c", "src/core/compression/message_compress.c", @@ -498,6 +500,7 @@ cc_library( "src/core/client_config/resolvers/sockaddr_resolver.h", "src/core/client_config/subchannel.h", "src/core/client_config/subchannel_factory.h", + "src/core/client_config/subchannel_index.h", "src/core/client_config/uri_parser.h", "src/core/compression/algorithm_metadata.h", "src/core/compression/message_compress.h", @@ -616,6 +619,7 @@ cc_library( "src/core/client_config/resolvers/sockaddr_resolver.c", "src/core/client_config/subchannel.c", "src/core/client_config/subchannel_factory.c", + "src/core/client_config/subchannel_index.c", "src/core/client_config/uri_parser.c", "src/core/compression/algorithm.c", "src/core/compression/message_compress.c", @@ -1293,6 +1297,7 @@ objc_library( "src/core/client_config/resolvers/sockaddr_resolver.c", "src/core/client_config/subchannel.c", "src/core/client_config/subchannel_factory.c", + "src/core/client_config/subchannel_index.c", "src/core/client_config/uri_parser.c", "src/core/compression/algorithm.c", "src/core/compression/message_compress.c", @@ -1454,6 +1459,7 @@ objc_library( "src/core/client_config/resolvers/sockaddr_resolver.h", "src/core/client_config/subchannel.h", "src/core/client_config/subchannel_factory.h", + "src/core/client_config/subchannel_index.h", "src/core/client_config/uri_parser.h", "src/core/compression/algorithm_metadata.h", "src/core/compression/message_compress.h", diff --git a/Makefile b/Makefile index cce7118829f..6c7febdabc3 100644 --- a/Makefile +++ b/Makefile @@ -2366,6 +2366,7 @@ LIBGRPC_SRC = \ src/core/client_config/resolvers/sockaddr_resolver.c \ src/core/client_config/subchannel.c \ src/core/client_config/subchannel_factory.c \ + src/core/client_config/subchannel_index.c \ src/core/client_config/uri_parser.c \ src/core/compression/algorithm.c \ src/core/compression/message_compress.c \ @@ -2651,6 +2652,7 @@ LIBGRPC_UNSECURE_SRC = \ src/core/client_config/resolvers/sockaddr_resolver.c \ src/core/client_config/subchannel.c \ src/core/client_config/subchannel_factory.c \ + src/core/client_config/subchannel_index.c \ src/core/client_config/uri_parser.c \ src/core/compression/algorithm.c \ src/core/compression/message_compress.c \ diff --git a/binding.gyp b/binding.gyp index 6d7f75ece4a..950e0dfe22a 100644 --- a/binding.gyp +++ b/binding.gyp @@ -605,6 +605,7 @@ 'src/core/client_config/resolvers/sockaddr_resolver.c', 'src/core/client_config/subchannel.c', 'src/core/client_config/subchannel_factory.c', + 'src/core/client_config/subchannel_index.c', 'src/core/client_config/uri_parser.c', 'src/core/compression/algorithm.c', 'src/core/compression/message_compress.c', diff --git a/build.yaml b/build.yaml index dc7fce3213f..b639b5d21e6 100644 --- a/build.yaml +++ b/build.yaml @@ -270,6 +270,7 @@ filegroups: - src/core/client_config/resolvers/sockaddr_resolver.h - src/core/client_config/subchannel.h - src/core/client_config/subchannel_factory.h + - src/core/client_config/subchannel_index.h - src/core/client_config/uri_parser.h - src/core/compression/algorithm_metadata.h - src/core/compression/message_compress.h @@ -385,6 +386,7 @@ filegroups: - src/core/client_config/resolvers/sockaddr_resolver.c - src/core/client_config/subchannel.c - src/core/client_config/subchannel_factory.c + - src/core/client_config/subchannel_index.c - src/core/client_config/uri_parser.c - src/core/compression/algorithm.c - src/core/compression/message_compress.c @@ -2627,8 +2629,8 @@ configs: LDXX: clang++ compile_the_world: true test_environ: - ASAN_OPTIONS: suppressions=tools/asan_suppressions.txt:detect_leaks=1:color=always - LSAN_OPTIONS: suppressions=tools/asan_suppressions.txt:report_objects=1 + ASAN_OPTIONS: detect_leaks=1:color=always + LSAN_OPTIONS: suppressions=tools/lsan_suppressions.txt:report_objects=1 timeout_multiplier: 1.5 asan-noleaks: CC: clang diff --git a/gRPC.podspec b/gRPC.podspec index c930bbd9945..cad15e6bd8b 100644 --- a/gRPC.podspec +++ b/gRPC.podspec @@ -198,6 +198,7 @@ Pod::Spec.new do |s| 'src/core/client_config/resolvers/sockaddr_resolver.h', 'src/core/client_config/subchannel.h', 'src/core/client_config/subchannel_factory.h', + 'src/core/client_config/subchannel_index.h', 'src/core/client_config/uri_parser.h', 'src/core/compression/algorithm_metadata.h', 'src/core/compression/message_compress.h', @@ -349,6 +350,7 @@ Pod::Spec.new do |s| 'src/core/client_config/resolvers/sockaddr_resolver.c', 'src/core/client_config/subchannel.c', 'src/core/client_config/subchannel_factory.c', + 'src/core/client_config/subchannel_index.c', 'src/core/client_config/uri_parser.c', 'src/core/compression/algorithm.c', 'src/core/compression/message_compress.c', @@ -506,6 +508,7 @@ Pod::Spec.new do |s| 'src/core/client_config/resolvers/sockaddr_resolver.h', 'src/core/client_config/subchannel.h', 'src/core/client_config/subchannel_factory.h', + 'src/core/client_config/subchannel_index.h', 'src/core/client_config/uri_parser.h', 'src/core/compression/algorithm_metadata.h', 'src/core/compression/message_compress.h', diff --git a/grpc.def b/grpc.def index d37e6879c57..bd0bc85a7c3 100644 --- a/grpc.def +++ b/grpc.def @@ -99,6 +99,7 @@ EXPORTS grpc_auth_context_set_peer_identity_property_name grpc_channel_credentials_release grpc_google_default_credentials_create + grpc_set_ssl_roots_override_callback grpc_ssl_credentials_create grpc_call_credentials_release grpc_composite_channel_credentials_create diff --git a/grpc.gemspec b/grpc.gemspec index 4a4a928f4ed..1358b0f6dfd 100755 --- a/grpc.gemspec +++ b/grpc.gemspec @@ -194,6 +194,7 @@ Gem::Specification.new do |s| s.files += %w( src/core/client_config/resolvers/sockaddr_resolver.h ) s.files += %w( src/core/client_config/subchannel.h ) s.files += %w( src/core/client_config/subchannel_factory.h ) + s.files += %w( src/core/client_config/subchannel_index.h ) s.files += %w( src/core/client_config/uri_parser.h ) s.files += %w( src/core/compression/algorithm_metadata.h ) s.files += %w( src/core/compression/message_compress.h ) @@ -332,6 +333,7 @@ Gem::Specification.new do |s| s.files += %w( src/core/client_config/resolvers/sockaddr_resolver.c ) s.files += %w( src/core/client_config/subchannel.c ) s.files += %w( src/core/client_config/subchannel_factory.c ) + s.files += %w( src/core/client_config/subchannel_index.c ) s.files += %w( src/core/client_config/uri_parser.c ) s.files += %w( src/core/compression/algorithm.c ) s.files += %w( src/core/compression/message_compress.c ) diff --git a/include/grpc++/support/channel_arguments.h b/include/grpc++/support/channel_arguments.h index a2960a7ecce..4e530d4b89c 100644 --- a/include/grpc++/support/channel_arguments.h +++ b/include/grpc++/support/channel_arguments.h @@ -1,6 +1,6 @@ /* * - * Copyright 2015, Google Inc. + * Copyright 2015-2016, Google Inc. * All rights reserved. * * Redistribution and use in source and binary forms, with or without @@ -51,7 +51,7 @@ class ChannelArgumentsTest; /// concrete setters are provided. class ChannelArguments { public: - ChannelArguments() {} + ChannelArguments(); ~ChannelArguments() {} ChannelArguments(const ChannelArguments& other); @@ -62,8 +62,8 @@ class ChannelArguments { void Swap(ChannelArguments& other); - /// Populates this instance with the arguments from \a channel_args. Does not - /// take ownership of \a channel_args. + /// Dump arguments in this instance to \a channel_args. Does not take + /// ownership of \a channel_args. /// /// Note that the underlying arguments are shared. Changes made to either \a /// channel_args or this instance would be reflected on both. @@ -77,6 +77,9 @@ class ChannelArguments { /// Set the compression algorithm for the channel. void SetCompressionAlgorithm(grpc_compression_algorithm algorithm); + /// The given string will be sent at the front of the user agent string. + void SetUserAgentPrefix(const grpc::string& user_agent_prefix); + // Generic channel argument setters. Only for advanced use cases. /// Set an integer argument \a value under \a key. void SetInt(const grpc::string& key, int value); diff --git a/include/grpc/grpc_security.h b/include/grpc/grpc_security.h index 3de5cae8be2..ef7205ded8b 100644 --- a/include/grpc/grpc_security.h +++ b/include/grpc/grpc_security.h @@ -167,7 +167,8 @@ typedef grpc_ssl_roots_override_result (*grpc_ssl_roots_override_callback)( before any ssl credentials are created to have the desired side effect. If GRPC_DEFAULT_SSL_ROOTS_FILE_PATH environment is set to a valid path, the callback will not be called. */ -void grpc_set_ssl_roots_override_callback(grpc_ssl_roots_override_callback cb); +GRPCAPI void grpc_set_ssl_roots_override_callback( + grpc_ssl_roots_override_callback cb); /* Object that holds a private key / certificate chain pair in PEM format. */ typedef struct { diff --git a/include/grpc/impl/codegen/grpc_types.h b/include/grpc/impl/codegen/grpc_types.h index ea1e96cf1d5..b11f6ffec41 100644 --- a/include/grpc/impl/codegen/grpc_types.h +++ b/include/grpc/impl/codegen/grpc_types.h @@ -68,6 +68,12 @@ typedef enum { GRPC_ARG_POINTER } grpc_arg_type; +typedef struct grpc_arg_pointer_vtable { + void *(*copy)(void *p); + void (*destroy)(void *p); + int (*cmp)(void *p, void *q); +} grpc_arg_pointer_vtable; + /** A single argument... each argument has a key and a value A note on naming keys: @@ -88,8 +94,7 @@ typedef struct { int integer; struct { void *p; - void *(*copy)(void *p); - void (*destroy)(void *p); + const grpc_arg_pointer_vtable *vtable; } pointer; } value; } grpc_arg; diff --git a/include/grpc/support/avl.h b/include/grpc/support/avl.h index 28eb5b175ea..2fe2d0b9d07 100644 --- a/include/grpc/support/avl.h +++ b/include/grpc/support/avl.h @@ -81,11 +81,12 @@ GPRAPI void gpr_avl_unref(gpr_avl avl); if key exists in avl, the new tree's key entry updated (i.e. a duplicate is not created) */ GPRAPI gpr_avl gpr_avl_add(gpr_avl avl, void *key, void *value); -/** return a new tree with key deleted */ +/** return a new tree with key deleted + implicitly unrefs avl to allow easy chaining. */ GPRAPI gpr_avl gpr_avl_remove(gpr_avl avl, void *key); /** lookup key, and return the associated value. does not mutate avl. returns NULL if key is not found. */ GPRAPI void *gpr_avl_get(gpr_avl avl, void *key); -#endif +#endif /* GRPC_SUPPORT_AVL_H */ diff --git a/include/grpc/support/useful.h b/include/grpc/support/useful.h index 9f08d788c0d..a0e76da29ef 100644 --- a/include/grpc/support/useful.h +++ b/include/grpc/support/useful.h @@ -1,6 +1,6 @@ /* * - * Copyright 2015, Google Inc. + * Copyright 2015-2016, Google Inc. * All rights reserved. * * Redistribution and use in source and binary forms, with or without @@ -72,4 +72,6 @@ 0x0f0f0f0f) % \ 255) +#define GPR_ICMP(a, b) ((a) < (b) ? -1 : ((a) > (b) ? 1 : 0)) + #endif /* GRPC_SUPPORT_USEFUL_H */ diff --git a/package.json b/package.json index f814e3ccd50..0a38182eaa7 100644 --- a/package.json +++ b/package.json @@ -139,6 +139,7 @@ "src/core/client_config/resolvers/sockaddr_resolver.h", "src/core/client_config/subchannel.h", "src/core/client_config/subchannel_factory.h", + "src/core/client_config/subchannel_index.h", "src/core/client_config/uri_parser.h", "src/core/compression/algorithm_metadata.h", "src/core/compression/message_compress.h", @@ -277,6 +278,7 @@ "src/core/client_config/resolvers/sockaddr_resolver.c", "src/core/client_config/subchannel.c", "src/core/client_config/subchannel_factory.c", + "src/core/client_config/subchannel_index.c", "src/core/client_config/uri_parser.c", "src/core/compression/algorithm.c", "src/core/compression/message_compress.c", diff --git a/src/core/channel/channel_args.c b/src/core/channel/channel_args.c index 0427ce0b8dc..bae7a90a015 100644 --- a/src/core/channel/channel_args.c +++ b/src/core/channel/channel_args.c @@ -37,6 +37,7 @@ #include #include +#include #include #include @@ -55,9 +56,8 @@ static grpc_arg copy_arg(const grpc_arg *src) { break; case GRPC_ARG_POINTER: dst.value.pointer = src->value.pointer; - dst.value.pointer.p = src->value.pointer.copy - ? src->value.pointer.copy(src->value.pointer.p) - : src->value.pointer.p; + dst.value.pointer.p = + src->value.pointer.vtable->copy(src->value.pointer.p); break; } return dst; @@ -94,6 +94,58 @@ grpc_channel_args *grpc_channel_args_merge(const grpc_channel_args *a, return grpc_channel_args_copy_and_add(a, b->args, b->num_args); } +static int cmp_arg(const grpc_arg *a, const grpc_arg *b) { + int c = GPR_ICMP(a->type, b->type); + if (c != 0) return c; + c = strcmp(a->key, b->key); + if (c != 0) return c; + switch (a->type) { + case GRPC_ARG_STRING: + return strcmp(a->value.string, b->value.string); + case GRPC_ARG_INTEGER: + return GPR_ICMP(a->value.integer, b->value.integer); + case GRPC_ARG_POINTER: + c = GPR_ICMP(a->value.pointer.p, b->value.pointer.p); + if (c != 0) { + c = GPR_ICMP(a->value.pointer.vtable, b->value.pointer.vtable); + if (c == 0) { + c = a->value.pointer.vtable->cmp(a->value.pointer.p, + b->value.pointer.p); + } + } + return c; + } + GPR_UNREACHABLE_CODE(return 0); +} + +/* stabilizing comparison function: since channel_args ordering matters for + * keys with the same name, we need to preserve that ordering */ +static int cmp_key_stable(const void *ap, const void *bp) { + const grpc_arg *const *a = ap; + const grpc_arg *const *b = bp; + int c = strcmp((*a)->key, (*b)->key); + if (c == 0) c = GPR_ICMP(*a, *b); + return c; +} + +grpc_channel_args *grpc_channel_args_normalize(const grpc_channel_args *a) { + grpc_arg **args = gpr_malloc(sizeof(grpc_arg *) * a->num_args); + for (size_t i = 0; i < a->num_args; i++) { + args[i] = &a->args[i]; + } + qsort(args, a->num_args, sizeof(grpc_arg *), cmp_key_stable); + + grpc_channel_args *b = gpr_malloc(sizeof(grpc_channel_args)); + b->num_args = a->num_args; + b->args = gpr_malloc(sizeof(grpc_arg) * b->num_args); + for (size_t i = 0; i < a->num_args; i++) { + b->args[i] = copy_arg(args[i]); + } + + gpr_free(args); + return b; +} + void grpc_channel_args_destroy(grpc_channel_args *a) { size_t i; for (i = 0; i < a->num_args; i++) { @@ -104,9 +156,7 @@ void grpc_channel_args_destroy(grpc_channel_args *a) { case GRPC_ARG_INTEGER: break; case GRPC_ARG_POINTER: - if (a->args[i].value.pointer.destroy) { - a->args[i].value.pointer.destroy(a->args[i].value.pointer.p); - } + a->args[i].value.pointer.vtable->destroy(a->args[i].value.pointer.p); break; } gpr_free(a->args[i].key); @@ -208,3 +258,14 @@ int grpc_channel_args_compression_algorithm_get_states( return (1u << GRPC_COMPRESS_ALGORITHMS_COUNT) - 1; /* All algs. enabled */ } } + +int grpc_channel_args_compare(const grpc_channel_args *a, + const grpc_channel_args *b) { + int c = GPR_ICMP(a->num_args, b->num_args); + if (c != 0) return c; + for (size_t i = 0; i < a->num_args; i++) { + c = cmp_arg(&a->args[i], &b->args[i]); + if (c != 0) return c; + } + return 0; +} diff --git a/src/core/channel/channel_args.h b/src/core/channel/channel_args.h index 480cc9aec2f..b3a7c9f4349 100644 --- a/src/core/channel/channel_args.h +++ b/src/core/channel/channel_args.h @@ -1,6 +1,6 @@ /* * - * Copyright 2015, Google Inc. + * Copyright 2015-2016, Google Inc. * All rights reserved. * * Redistribution and use in source and binary forms, with or without @@ -40,6 +40,9 @@ /* Copy some arguments */ grpc_channel_args *grpc_channel_args_copy(const grpc_channel_args *src); +/* Copy some arguments, stably sorting keys */ +grpc_channel_args *grpc_channel_args_normalize(const grpc_channel_args *a); + /** Copy some arguments and add the to_add parameter in the end. If to_add is NULL, it is equivalent to call grpc_channel_args_copy. */ grpc_channel_args *grpc_channel_args_copy_and_add(const grpc_channel_args *src, @@ -85,4 +88,7 @@ grpc_channel_args *grpc_channel_args_compression_algorithm_set_state( int grpc_channel_args_compression_algorithm_get_states( const grpc_channel_args *a); +int grpc_channel_args_compare(const grpc_channel_args *a, + const grpc_channel_args *b); + #endif /* GRPC_INTERNAL_CORE_CHANNEL_CHANNEL_ARGS_H */ diff --git a/src/core/client_config/connector.c b/src/core/client_config/connector.c index 1603ffb8be0..aa34aa7fab6 100644 --- a/src/core/client_config/connector.c +++ b/src/core/client_config/connector.c @@ -1,6 +1,6 @@ /* * - * Copyright 2015, Google Inc. + * Copyright 2015-2016, Google Inc. * All rights reserved. * * Redistribution and use in source and binary forms, with or without @@ -33,8 +33,9 @@ #include "src/core/client_config/connector.h" -void grpc_connector_ref(grpc_connector* connector) { +grpc_connector* grpc_connector_ref(grpc_connector* connector) { connector->vtable->ref(connector); + return connector; } void grpc_connector_unref(grpc_exec_ctx* exec_ctx, grpc_connector* connector) { diff --git a/src/core/client_config/connector.h b/src/core/client_config/connector.h index b4482fa2eeb..b91eb512c30 100644 --- a/src/core/client_config/connector.h +++ b/src/core/client_config/connector.h @@ -1,6 +1,6 @@ /* * - * Copyright 2015, Google Inc. + * Copyright 2015-2016, Google Inc. * All rights reserved. * * Redistribution and use in source and binary forms, with or without @@ -81,7 +81,7 @@ struct grpc_connector_vtable { grpc_connect_out_args *out_args, grpc_closure *notify); }; -void grpc_connector_ref(grpc_connector *connector); +grpc_connector *grpc_connector_ref(grpc_connector *connector); void grpc_connector_unref(grpc_exec_ctx *exec_ctx, grpc_connector *connector); /** Connect using the connector: max one outstanding call at a time */ void grpc_connector_connect(grpc_exec_ctx *exec_ctx, grpc_connector *connector, diff --git a/src/core/client_config/subchannel.c b/src/core/client_config/subchannel.c index 0a996a1e8bc..6599c75dba7 100644 --- a/src/core/client_config/subchannel.c +++ b/src/core/client_config/subchannel.c @@ -36,16 +36,17 @@ #include #include +#include #include "src/core/channel/channel_args.h" #include "src/core/channel/client_channel.h" #include "src/core/channel/connected_channel.h" #include "src/core/client_config/initial_connect_string.h" +#include "src/core/client_config/subchannel_index.h" #include "src/core/iomgr/timer.h" #include "src/core/profiling/timers.h" #include "src/core/surface/channel.h" #include "src/core/transport/connectivity_state.h" -#include "src/core/transport/connectivity_state.h" #define INTERNAL_REF_BITS 16 #define STRONG_REF_MASK (~(gpr_atm)((1 << INTERNAL_REF_BITS) - 1)) @@ -94,6 +95,8 @@ struct grpc_subchannel { struct sockaddr *addr; size_t addr_len; + grpc_subchannel_key *key; + /** initial string to send to peer */ gpr_slice initial_connect_string; @@ -207,6 +210,7 @@ static void subchannel_destroy(grpc_exec_ctx *exec_ctx, void *arg, grpc_connectivity_state_destroy(exec_ctx, &c->state_tracker); grpc_connector_unref(exec_ctx, c->connector); grpc_pollset_set_destroy(&c->pollset_set); + grpc_subchannel_key_destroy(exec_ctx, c->key); gpr_free(c); } @@ -222,22 +226,42 @@ static gpr_atm ref_mutate(grpc_subchannel *c, gpr_atm delta, return old_val; } -void grpc_subchannel_ref(grpc_subchannel *c GRPC_SUBCHANNEL_REF_EXTRA_ARGS) { +grpc_subchannel *grpc_subchannel_ref(grpc_subchannel *c + GRPC_SUBCHANNEL_REF_EXTRA_ARGS) { gpr_atm old_refs; old_refs = ref_mutate(c, (1 << INTERNAL_REF_BITS), 0 REF_MUTATE_PURPOSE("STRONG_REF")); GPR_ASSERT((old_refs & STRONG_REF_MASK) != 0); + return c; } -void grpc_subchannel_weak_ref(grpc_subchannel *c - GRPC_SUBCHANNEL_REF_EXTRA_ARGS) { +grpc_subchannel *grpc_subchannel_weak_ref(grpc_subchannel *c + GRPC_SUBCHANNEL_REF_EXTRA_ARGS) { gpr_atm old_refs; old_refs = ref_mutate(c, 1, 0 REF_MUTATE_PURPOSE("WEAK_REF")); GPR_ASSERT(old_refs != 0); + return c; +} + +grpc_subchannel *grpc_subchannel_ref_from_weak_ref( + grpc_subchannel *c GRPC_SUBCHANNEL_REF_EXTRA_ARGS) { + if (!c) return NULL; + for (;;) { + gpr_atm old_refs = gpr_atm_acq_load(&c->ref_pair); + if (old_refs >= (1 << INTERNAL_REF_BITS)) { + gpr_atm new_refs = old_refs + (1 << INTERNAL_REF_BITS); + if (gpr_atm_rel_cas(&c->ref_pair, old_refs, new_refs)) { + return c; + } + } else { + return NULL; + } + } } static void disconnect(grpc_exec_ctx *exec_ctx, grpc_subchannel *c) { grpc_connected_subchannel *con; + grpc_subchannel_index_unregister(exec_ctx, c->key, c); gpr_mu_lock(&c->mu); GPR_ASSERT(!c->disconnected); c->disconnected = 1; @@ -276,10 +300,19 @@ static uint32_t random_seed() { return (uint32_t)(gpr_time_to_millis(gpr_now(GPR_CLOCK_MONOTONIC))); } -grpc_subchannel *grpc_subchannel_create(grpc_connector *connector, +grpc_subchannel *grpc_subchannel_create(grpc_exec_ctx *exec_ctx, + grpc_connector *connector, grpc_subchannel_args *args) { - grpc_subchannel *c = gpr_malloc(sizeof(*c)); + grpc_subchannel_key *key = grpc_subchannel_key_create(connector, args); + grpc_subchannel *c = grpc_subchannel_index_find(exec_ctx, key); + if (c) { + grpc_subchannel_key_destroy(exec_ctx, key); + return c; + } + + c = gpr_malloc(sizeof(*c)); memset(c, 0, sizeof(*c)); + c->key = key; gpr_atm_no_barrier_store(&c->ref_pair, 1 << INTERNAL_REF_BITS); c->connector = connector; grpc_connector_ref(c->connector); @@ -305,7 +338,8 @@ grpc_subchannel *grpc_subchannel_create(grpc_connector *connector, grpc_connectivity_state_init(&c->state_tracker, GRPC_CHANNEL_IDLE, "subchannel"); gpr_mu_init(&c->mu); - return c; + + return grpc_subchannel_index_register(exec_ctx, key, c); } static void continue_connect(grpc_exec_ctx *exec_ctx, grpc_subchannel *c) { diff --git a/src/core/client_config/subchannel.h b/src/core/client_config/subchannel.h index 57c7c9dc674..313e63c75c8 100644 --- a/src/core/client_config/subchannel.h +++ b/src/core/client_config/subchannel.h @@ -1,6 +1,6 @@ /* * - * Copyright 2015, Google Inc. + * Copyright 2015-2016, Google Inc. * All rights reserved. * * Redistribution and use in source and binary forms, with or without @@ -48,6 +48,8 @@ typedef struct grpc_subchannel_args grpc_subchannel_args; #ifdef GRPC_STREAM_REFCOUNT_DEBUG #define GRPC_SUBCHANNEL_REF(p, r) \ grpc_subchannel_ref((p), __FILE__, __LINE__, (r)) +#define GRPC_SUBCHANNEL_REF_FROM_WEAK_REF(p, r) \ + grpc_subchannel_ref_from_weak_ref((p), __FILE__, __LINE__, (r)) #define GRPC_SUBCHANNEL_UNREF(cl, p, r) \ grpc_subchannel_unref((cl), (p), __FILE__, __LINE__, (r)) #define GRPC_SUBCHANNEL_WEAK_REF(p, r) \ @@ -66,6 +68,8 @@ typedef struct grpc_subchannel_args grpc_subchannel_args; , const char *file, int line, const char *reason #else #define GRPC_SUBCHANNEL_REF(p, r) grpc_subchannel_ref((p)) +#define GRPC_SUBCHANNEL_REF_FROM_WEAK_REF(p, r) \ + grpc_subchannel_ref_from_weak_ref((p)) #define GRPC_SUBCHANNEL_UNREF(cl, p, r) grpc_subchannel_unref((cl), (p)) #define GRPC_SUBCHANNEL_WEAK_REF(p, r) grpc_subchannel_weak_ref((p)) #define GRPC_SUBCHANNEL_WEAK_UNREF(cl, p, r) \ @@ -79,13 +83,15 @@ typedef struct grpc_subchannel_args grpc_subchannel_args; #define GRPC_SUBCHANNEL_REF_EXTRA_ARGS #endif -void grpc_subchannel_ref(grpc_subchannel *channel - GRPC_SUBCHANNEL_REF_EXTRA_ARGS); +grpc_subchannel *grpc_subchannel_ref(grpc_subchannel *channel + GRPC_SUBCHANNEL_REF_EXTRA_ARGS); +grpc_subchannel *grpc_subchannel_ref_from_weak_ref( + grpc_subchannel *channel GRPC_SUBCHANNEL_REF_EXTRA_ARGS); void grpc_subchannel_unref(grpc_exec_ctx *exec_ctx, grpc_subchannel *channel GRPC_SUBCHANNEL_REF_EXTRA_ARGS); -void grpc_subchannel_weak_ref(grpc_subchannel *channel - GRPC_SUBCHANNEL_REF_EXTRA_ARGS); +grpc_subchannel *grpc_subchannel_weak_ref(grpc_subchannel *channel + GRPC_SUBCHANNEL_REF_EXTRA_ARGS); void grpc_subchannel_weak_unref(grpc_exec_ctx *exec_ctx, grpc_subchannel *channel GRPC_SUBCHANNEL_REF_EXTRA_ARGS); @@ -146,6 +152,8 @@ grpc_call_stack *grpc_subchannel_call_get_call_stack( grpc_subchannel_call *subchannel_call); struct grpc_subchannel_args { + /* When updating this struct, also update subchannel_index.c */ + /** Channel filters for this channel - wrapped factories will likely want to mutate this */ const grpc_channel_filter **filters; @@ -159,7 +167,8 @@ struct grpc_subchannel_args { }; /** create a subchannel given a connector */ -grpc_subchannel *grpc_subchannel_create(grpc_connector *connector, +grpc_subchannel *grpc_subchannel_create(grpc_exec_ctx *exec_ctx, + grpc_connector *connector, grpc_subchannel_args *args); #endif /* GRPC_INTERNAL_CORE_CLIENT_CONFIG_SUBCHANNEL_H */ diff --git a/src/core/client_config/subchannel_index.c b/src/core/client_config/subchannel_index.c new file mode 100644 index 00000000000..f78a7fd588c --- /dev/null +++ b/src/core/client_config/subchannel_index.c @@ -0,0 +1,259 @@ +// +// +// 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/client_config/subchannel_index.h" + +#include +#include + +#include +#include +#include + +#include "src/core/channel/channel_args.h" + +// a map of subchannel_key --> subchannel, used for detecting connections +// to the same destination in order to share them +static gpr_avl g_subchannel_index; + +static gpr_mu g_mu; + +struct grpc_subchannel_key { + grpc_connector *connector; + grpc_subchannel_args args; +}; + +GPR_TLS_DECL(subchannel_index_exec_ctx); + +static void enter_ctx(grpc_exec_ctx *exec_ctx) { + GPR_ASSERT(gpr_tls_get(&subchannel_index_exec_ctx) == 0); + gpr_tls_set(&subchannel_index_exec_ctx, (intptr_t)exec_ctx); +} + +static void leave_ctx(grpc_exec_ctx *exec_ctx) { + GPR_ASSERT(gpr_tls_get(&subchannel_index_exec_ctx) == (intptr_t)exec_ctx); + gpr_tls_set(&subchannel_index_exec_ctx, 0); +} + +static grpc_exec_ctx *current_ctx() { + grpc_exec_ctx *c = (grpc_exec_ctx *)gpr_tls_get(&subchannel_index_exec_ctx); + GPR_ASSERT(c != NULL); + return c; +} + +static grpc_subchannel_key *create_key( + grpc_connector *connector, grpc_subchannel_args *args, + grpc_channel_args *(*copy_channel_args)(const grpc_channel_args *args)) { + grpc_subchannel_key *k = gpr_malloc(sizeof(*k)); + k->connector = grpc_connector_ref(connector); + k->args.filter_count = args->filter_count; + k->args.filters = gpr_malloc(sizeof(*k->args.filters) * k->args.filter_count); + memcpy((grpc_channel_filter *)k->args.filters, args->filters, + sizeof(*k->args.filters) * k->args.filter_count); + k->args.addr_len = args->addr_len; + k->args.addr = gpr_malloc(args->addr_len); + memcpy(k->args.addr, args->addr, k->args.addr_len); + k->args.args = copy_channel_args(args->args); + return k; +} + +grpc_subchannel_key *grpc_subchannel_key_create(grpc_connector *connector, + grpc_subchannel_args *args) { + return create_key(connector, args, grpc_channel_args_normalize); +} + +static grpc_subchannel_key *subchannel_key_copy(grpc_subchannel_key *k) { + return create_key(k->connector, &k->args, grpc_channel_args_copy); +} + +static int subchannel_key_compare(grpc_subchannel_key *a, + grpc_subchannel_key *b) { + int c = GPR_ICMP(a->connector, b->connector); + if (c != 0) return c; + c = GPR_ICMP(a->args.addr_len, b->args.addr_len); + if (c != 0) return c; + c = GPR_ICMP(a->args.filter_count, b->args.filter_count); + if (c != 0) return c; + c = memcmp(a->args.addr, b->args.addr, a->args.addr_len); + if (c != 0) return c; + c = memcmp(a->args.filters, b->args.filters, + a->args.filter_count * sizeof(*a->args.filters)); + return grpc_channel_args_compare(a->args.args, b->args.args); +} + +void grpc_subchannel_key_destroy(grpc_exec_ctx *exec_ctx, + grpc_subchannel_key *k) { + grpc_connector_unref(exec_ctx, k->connector); + gpr_free(k->args.addr); + gpr_free((grpc_channel_args *)k->args.filters); + grpc_channel_args_destroy((grpc_channel_args *)k->args.args); + gpr_free(k); +} + +static void sck_avl_destroy(void *p) { + grpc_subchannel_key_destroy(current_ctx(), p); +} + +static void *sck_avl_copy(void *p) { return subchannel_key_copy(p); } + +static long sck_avl_compare(void *a, void *b) { + return subchannel_key_compare(a, b); +} + +static void scv_avl_destroy(void *p) { + GRPC_SUBCHANNEL_WEAK_UNREF(current_ctx(), p, "subchannel_index"); +} + +static void *scv_avl_copy(void *p) { + GRPC_SUBCHANNEL_WEAK_REF(p, "subchannel_index"); + return p; +} + +static const gpr_avl_vtable subchannel_avl_vtable = { + .destroy_key = sck_avl_destroy, + .copy_key = sck_avl_copy, + .compare_keys = sck_avl_compare, + .destroy_value = scv_avl_destroy, + .copy_value = scv_avl_copy}; + +void grpc_subchannel_index_init(void) { + g_subchannel_index = gpr_avl_create(&subchannel_avl_vtable); + gpr_mu_init(&g_mu); +} + +void grpc_subchannel_index_shutdown(void) { + gpr_mu_destroy(&g_mu); + gpr_avl_unref(g_subchannel_index); +} + +grpc_subchannel *grpc_subchannel_index_find(grpc_exec_ctx *exec_ctx, + grpc_subchannel_key *key) { + enter_ctx(exec_ctx); + + // Lock, and take a reference to the subchannel index. + // We don't need to do the search under a lock as avl's are immutable. + gpr_mu_lock(&g_mu); + gpr_avl index = gpr_avl_ref(g_subchannel_index); + gpr_mu_unlock(&g_mu); + + grpc_subchannel *c = + GRPC_SUBCHANNEL_REF_FROM_WEAK_REF(gpr_avl_get(index, key), "index_find"); + gpr_avl_unref(index); + + leave_ctx(exec_ctx); + return c; +} + +grpc_subchannel *grpc_subchannel_index_register(grpc_exec_ctx *exec_ctx, + grpc_subchannel_key *key, + grpc_subchannel *constructed) { + enter_ctx(exec_ctx); + + grpc_subchannel *c = NULL; + + while (c == NULL) { + // Compare and swap loop: + // - take a reference to the current index + gpr_mu_lock(&g_mu); + gpr_avl index = gpr_avl_ref(g_subchannel_index); + gpr_mu_unlock(&g_mu); + + // - Check to see if a subchannel already exists + c = gpr_avl_get(index, key); + if (c != NULL) { + // yes -> we're done + GRPC_SUBCHANNEL_WEAK_UNREF(exec_ctx, constructed, "index_register"); + } else { + // no -> update the avl and compare/swap + gpr_avl updated = + gpr_avl_add(gpr_avl_ref(index), subchannel_key_copy(key), + GRPC_SUBCHANNEL_WEAK_REF(constructed, "index_register")); + + // it may happen (but it's expected to be unlikely) + // that some other thread has changed the index: + // compare/swap here to check that, and retry as necessary + gpr_mu_lock(&g_mu); + if (index.root == g_subchannel_index.root) { + GPR_SWAP(gpr_avl, updated, g_subchannel_index); + c = constructed; + } + gpr_mu_unlock(&g_mu); + + gpr_avl_unref(updated); + } + gpr_avl_unref(index); + } + + leave_ctx(exec_ctx); + + return c; +} + +void grpc_subchannel_index_unregister(grpc_exec_ctx *exec_ctx, + grpc_subchannel_key *key, + grpc_subchannel *constructed) { + enter_ctx(exec_ctx); + + bool done = false; + while (!done) { + // Compare and swap loop: + // - take a reference to the current index + gpr_mu_lock(&g_mu); + gpr_avl index = gpr_avl_ref(g_subchannel_index); + gpr_mu_unlock(&g_mu); + + // Check to see if this key still refers to the previously + // registered subchannel + grpc_subchannel *c = gpr_avl_get(index, key); + if (c != constructed) { + gpr_avl_unref(index); + break; + } + + // compare and swap the update (some other thread may have + // mutated the index behind us) + gpr_avl updated = gpr_avl_remove(gpr_avl_ref(index), key); + + gpr_mu_lock(&g_mu); + if (index.root == g_subchannel_index.root) { + GPR_SWAP(gpr_avl, updated, g_subchannel_index); + done = true; + } + gpr_mu_unlock(&g_mu); + + gpr_avl_unref(updated); + gpr_avl_unref(index); + } + + leave_ctx(exec_ctx); +} diff --git a/src/core/client_config/subchannel_index.h b/src/core/client_config/subchannel_index.h new file mode 100644 index 00000000000..095ef178194 --- /dev/null +++ b/src/core/client_config/subchannel_index.h @@ -0,0 +1,77 @@ +/* + * + * 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_INTERNAL_CORE_CLIENT_CONFIG_SUBCHANNEL_INDEX_H +#define GRPC_INTERNAL_CORE_CLIENT_CONFIG_SUBCHANNEL_INDEX_H + +#include "src/core/client_config/connector.h" +#include "src/core/client_config/subchannel.h" + +/** \file Provides an index of active subchannels so that they can be + shared amongst channels */ + +typedef struct grpc_subchannel_key grpc_subchannel_key; + +/** Create a key that can be used to uniquely identify a subchannel */ +grpc_subchannel_key *grpc_subchannel_key_create(grpc_connector *con, + grpc_subchannel_args *args); + +/** Destroy a subchannel key */ +void grpc_subchannel_key_destroy(grpc_exec_ctx *exec_ctx, + grpc_subchannel_key *key); + +/** Given a subchannel key, find the subchannel registered for it. + Returns NULL if no such channel exists. + Thread-safe. */ +grpc_subchannel *grpc_subchannel_index_find(grpc_exec_ctx *exec_ctx, + grpc_subchannel_key *key); + +/** Register a subchannel against a key. + Takes ownership of \a constructed. + Returns the registered subchannel. This may be different from + \a constructed in the case of a registration race. */ +grpc_subchannel *grpc_subchannel_index_register(grpc_exec_ctx *exec_ctx, + grpc_subchannel_key *key, + grpc_subchannel *constructed); + +/** Remove \a constructed as the registered subchannel for \a key. */ +void grpc_subchannel_index_unregister(grpc_exec_ctx *exec_ctx, + grpc_subchannel_key *key, + grpc_subchannel *constructed); + +/** Initialize the subchannel index (global) */ +void grpc_subchannel_index_init(void); +/** Shutdown the subchannel index (global) */ +void grpc_subchannel_index_shutdown(void); + +#endif /* GRPC_INTERNAL_CORE_CLIENT_CONFIG_SUBCHANNEL_INDEX_H */ diff --git a/src/core/security/credentials.c b/src/core/security/credentials.c index afba0079f56..c58574bd6d8 100644 --- a/src/core/security/credentials.c +++ b/src/core/security/credentials.c @@ -196,14 +196,21 @@ static void *server_credentials_pointer_arg_copy(void *p) { return grpc_server_credentials_ref(p); } +static int server_credentials_pointer_cmp(void *a, void *b) { + return GPR_ICMP(a, b); +} + +static const grpc_arg_pointer_vtable cred_ptr_vtable = { + server_credentials_pointer_arg_copy, server_credentials_pointer_arg_destroy, + server_credentials_pointer_cmp}; + grpc_arg grpc_server_credentials_to_arg(grpc_server_credentials *p) { grpc_arg arg; memset(&arg, 0, sizeof(grpc_arg)); arg.type = GRPC_ARG_POINTER; arg.key = GRPC_SERVER_CREDENTIALS_ARG; arg.value.pointer.p = p; - arg.value.pointer.copy = server_credentials_pointer_arg_copy; - arg.value.pointer.destroy = server_credentials_pointer_arg_destroy; + arg.value.pointer.vtable = &cred_ptr_vtable; return arg; } diff --git a/src/core/security/security_connector.c b/src/core/security/security_connector.c index bdccbabfea3..b46205323bf 100644 --- a/src/core/security/security_connector.c +++ b/src/core/security/security_connector.c @@ -202,12 +202,17 @@ static void *connector_pointer_arg_copy(void *p) { return GRPC_SECURITY_CONNECTOR_REF(p, "connector_pointer_arg"); } +static int connector_pointer_cmp(void *a, void *b) { return GPR_ICMP(a, b); } + +static const grpc_arg_pointer_vtable connector_pointer_vtable = { + connector_pointer_arg_copy, connector_pointer_arg_destroy, + connector_pointer_cmp}; + grpc_arg grpc_security_connector_to_arg(grpc_security_connector *sc) { grpc_arg result; result.type = GRPC_ARG_POINTER; result.key = GRPC_SECURITY_CONNECTOR_ARG; - result.value.pointer.destroy = connector_pointer_arg_destroy; - result.value.pointer.copy = connector_pointer_arg_copy; + result.value.pointer.vtable = &connector_pointer_vtable; result.value.pointer.p = sc; return result; } diff --git a/src/core/security/security_context.c b/src/core/security/security_context.c index 2068c97d78c..a71b3bc9153 100644 --- a/src/core/security/security_context.c +++ b/src/core/security/security_context.c @@ -1,6 +1,6 @@ /* * - * Copyright 2015, Google Inc. + * Copyright 2015-2016, Google Inc. * All rights reserved. * * Redistribution and use in source and binary forms, with or without @@ -309,14 +309,19 @@ static void *auth_context_pointer_arg_copy(void *p) { return GRPC_AUTH_CONTEXT_REF(p, "auth_context_pointer_arg"); } +static int auth_context_pointer_cmp(void *a, void *b) { return GPR_ICMP(a, b); } + +static const grpc_arg_pointer_vtable auth_context_pointer_vtable = { + auth_context_pointer_arg_copy, auth_context_pointer_arg_destroy, + auth_context_pointer_cmp}; + grpc_arg grpc_auth_context_to_arg(grpc_auth_context *p) { grpc_arg arg; memset(&arg, 0, sizeof(grpc_arg)); arg.type = GRPC_ARG_POINTER; arg.key = GRPC_AUTH_CONTEXT_ARG; arg.value.pointer.p = p; - arg.value.pointer.copy = auth_context_pointer_arg_copy; - arg.value.pointer.destroy = auth_context_pointer_arg_destroy; + arg.value.pointer.vtable = &auth_context_pointer_vtable; return arg; } diff --git a/src/core/support/avl.c b/src/core/support/avl.c index 9734c9987fe..f378b3ee17a 100644 --- a/src/core/support/avl.c +++ b/src/core/support/avl.c @@ -1,6 +1,6 @@ /* * - * Copyright 2015, Google Inc. + * Copyright 2015-2016, Google Inc. * All rights reserved. * * Redistribution and use in source and binary forms, with or without @@ -167,7 +167,7 @@ static gpr_avl_node *rotate_right_left(const gpr_avl_vtable *vtable, void *key, vtable->copy_key(right->left->key), vtable->copy_value(right->left->value), new_node(key, value, left, ref_node(right->left->left)), - new_node(vtable->copy_key(right->key), vtable->copy_key(right->value), + new_node(vtable->copy_key(right->key), vtable->copy_value(right->value), ref_node(right->left->right), ref_node(right->right))); unref_node(vtable, right); return n; diff --git a/src/core/surface/channel_create.c b/src/core/surface/channel_create.c index 4d4337d2889..fd7e20e9cce 100644 --- a/src/core/surface/channel_create.c +++ b/src/core/surface/channel_create.c @@ -172,7 +172,7 @@ static grpc_subchannel *subchannel_factory_create_subchannel( c->base.vtable = &connector_vtable; gpr_ref_init(&c->refs, 1); args->args = final_args; - s = grpc_subchannel_create(&c->base, args); + s = grpc_subchannel_create(exec_ctx, &c->base, args); grpc_connector_unref(exec_ctx, &c->base); grpc_channel_args_destroy(final_args); return s; diff --git a/src/core/surface/init.c b/src/core/surface/init.c index e3ab70dba70..a4a53d3ec1a 100644 --- a/src/core/surface/init.c +++ b/src/core/surface/init.c @@ -46,6 +46,8 @@ #include "src/core/client_config/resolver_registry.h" #include "src/core/client_config/resolvers/dns_resolver.h" #include "src/core/client_config/resolvers/sockaddr_resolver.h" +#include "src/core/client_config/subchannel.h" +#include "src/core/client_config/subchannel_index.h" #include "src/core/debug/trace.h" #include "src/core/iomgr/executor.h" #include "src/core/iomgr/iomgr.h" @@ -127,6 +129,7 @@ void grpc_init(void) { } gpr_timers_global_init(); grpc_cq_global_init(); + grpc_subchannel_index_init(); for (i = 0; i < g_number_of_plugins; i++) { if (g_all_of_the_plugins[i].init != NULL) { g_all_of_the_plugins[i].init(); @@ -145,6 +148,7 @@ void grpc_shutdown(void) { grpc_executor_shutdown(); grpc_cq_global_shutdown(); grpc_iomgr_shutdown(); + grpc_subchannel_index_shutdown(); census_shutdown(); gpr_timers_global_destroy(); grpc_tracer_shutdown(); diff --git a/src/core/surface/secure_channel_create.c b/src/core/surface/secure_channel_create.c index dd1441ad67a..9c04426d872 100644 --- a/src/core/surface/secure_channel_create.c +++ b/src/core/surface/secure_channel_create.c @@ -238,7 +238,7 @@ static grpc_subchannel *subchannel_factory_create_subchannel( gpr_mu_init(&c->mu); gpr_ref_init(&c->refs, 1); args->args = final_args; - s = grpc_subchannel_create(&c->base, args); + s = grpc_subchannel_create(exec_ctx, &c->base, args); grpc_connector_unref(exec_ctx, &c->base); grpc_channel_args_destroy(final_args); return s; diff --git a/src/cpp/client/create_channel.cc b/src/cpp/client/create_channel.cc index fdaa28ffef2..76a1b31e2f7 100644 --- a/src/cpp/client/create_channel.cc +++ b/src/cpp/client/create_channel.cc @@ -32,7 +32,6 @@ */ #include -#include #include #include @@ -56,13 +55,8 @@ std::shared_ptr CreateCustomChannel( const ChannelArguments& args) { internal::GrpcLibrary init_lib; // We need to call init in case of a bad creds. - ChannelArguments cp_args = args; - std::ostringstream user_agent_prefix; - user_agent_prefix << "grpc-c++/" << grpc_version_string(); - cp_args.SetString(GRPC_ARG_PRIMARY_USER_AGENT_STRING, - user_agent_prefix.str()); return creds - ? creds->CreateChannel(target, cp_args) + ? creds->CreateChannel(target, args) : CreateChannelInternal("", grpc_lame_client_channel_create( NULL, GRPC_STATUS_INVALID_ARGUMENT, "Invalid credentials.")); diff --git a/src/cpp/common/channel_arguments.cc b/src/cpp/common/channel_arguments.cc index 90cd5136af3..989c1058324 100644 --- a/src/cpp/common/channel_arguments.cc +++ b/src/cpp/common/channel_arguments.cc @@ -1,6 +1,6 @@ /* * - * Copyright 2015, Google Inc. + * Copyright 2015-2016, Google Inc. * All rights reserved. * * Redistribution and use in source and binary forms, with or without @@ -30,14 +30,23 @@ * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. * */ - #include +#include + +#include #include #include "src/core/channel/channel_args.h" namespace grpc { +ChannelArguments::ChannelArguments() { + std::ostringstream user_agent_prefix; + user_agent_prefix << "grpc-c++/" << grpc_version_string(); + // This will be ignored if used on the server side. + SetString(GRPC_ARG_PRIMARY_USER_AGENT_STRING, user_agent_prefix.str()); +} + ChannelArguments::ChannelArguments(const ChannelArguments& other) : strings_(other.strings_) { args_.reserve(other.args_.size()); @@ -62,9 +71,7 @@ ChannelArguments::ChannelArguments(const ChannelArguments& other) break; case GRPC_ARG_POINTER: ap.value.pointer = a->value.pointer; - ap.value.pointer.p = a->value.pointer.copy - ? a->value.pointer.copy(ap.value.pointer.p) - : ap.value.pointer.p; + ap.value.pointer.p = a->value.pointer.vtable->copy(ap.value.pointer.p); break; } args_.push_back(ap); @@ -81,6 +88,31 @@ void ChannelArguments::SetCompressionAlgorithm( SetInt(GRPC_COMPRESSION_ALGORITHM_ARG, algorithm); } +// Note: a second call to this will add in front the result of the first call. +// An example is calling this on a copy of ChannelArguments which already has a +// prefix. The user can build up a prefix string by calling this multiple times, +// each with more significant identifier. +void ChannelArguments::SetUserAgentPrefix( + const grpc::string& user_agent_prefix) { + if (user_agent_prefix.empty()) { + return; + } + bool replaced = false; + for (auto it = args_.begin(); it != args_.end(); ++it) { + const grpc_arg& arg = *it; + if (arg.type == GRPC_ARG_STRING && + grpc::string(arg.key) == GRPC_ARG_PRIMARY_USER_AGENT_STRING) { + strings_.push_back(user_agent_prefix + " " + arg.value.string); + it->value.string = const_cast(strings_.back().c_str()); + replaced = true; + break; + } + } + if (!replaced) { + SetString(GRPC_ARG_PRIMARY_USER_AGENT_STRING, user_agent_prefix); + } +} + void ChannelArguments::SetInt(const grpc::string& key, int value) { grpc_arg arg; arg.type = GRPC_ARG_INTEGER; @@ -92,13 +124,24 @@ void ChannelArguments::SetInt(const grpc::string& key, int value) { } void ChannelArguments::SetPointer(const grpc::string& key, void* value) { + struct VtableMembers { + static void* Copy(void* in) { return in; } + static void Destroy(void* in) {} + static int Compare(void* a, void* b) { + if (a < b) return -1; + if (a > b) return 1; + return 0; + } + }; + static const grpc_arg_pointer_vtable vtable = { + &VtableMembers::Copy, &VtableMembers::Destroy, &VtableMembers::Compare}; + grpc_arg arg; arg.type = GRPC_ARG_POINTER; strings_.push_back(key); arg.key = const_cast(strings_.back().c_str()); arg.value.pointer.p = value; - arg.value.pointer.copy = nullptr; - arg.value.pointer.destroy = nullptr; + arg.value.pointer.vtable = &vtable; args_.push_back(arg); } diff --git a/src/csharp/Grpc.Core/Grpc.Core.csproj b/src/csharp/Grpc.Core/Grpc.Core.csproj index 9587503e4b3..8d7d2cae0de 100644 --- a/src/csharp/Grpc.Core/Grpc.Core.csproj +++ b/src/csharp/Grpc.Core/Grpc.Core.csproj @@ -59,6 +59,7 @@ + diff --git a/src/csharp/Grpc.Core/Logging/NullLogger.cs b/src/csharp/Grpc.Core/Logging/NullLogger.cs new file mode 100644 index 00000000000..58679a0ff9f --- /dev/null +++ b/src/csharp/Grpc.Core/Logging/NullLogger.cs @@ -0,0 +1,122 @@ +#region Copyright notice and license + +// 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. + +#endregion + +using System; + +namespace Grpc.Core.Logging +{ + /// + /// Logger which doesn't log any information anywhere. + /// + public sealed class NullLogger : ILogger + { + /// + /// As with all logging calls on this logger, this method is a no-op. + /// + public void Debug(string message) + { + } + + /// + /// As with all logging calls on this logger, this method is a no-op. + /// + public void Debug(string format, params object[] formatArgs) + { + } + + /// + /// As with all logging calls on this logger, this method is a no-op. + /// + public void Error(string message) + { + } + + /// + /// As with all logging calls on this logger, this method is a no-op. + /// + public void Error(Exception exception, string message) + { + } + + /// + /// As with all logging calls on this logger, this method is a no-op. + /// + public void Error(string format, params object[] formatArgs) + { + } + + /// + /// Returns a reference to the instance on which the method is called, as + /// instances aren't associated with specific types. + /// + public ILogger ForType() + { + return this; + } + + /// + /// As with all logging calls on this logger, this method is a no-op. + /// + public void Info(string message) + { + } + + /// + /// As with all logging calls on this logger, this method is a no-op. + /// + public void Info(string format, params object[] formatArgs) + { + } + + /// + /// As with all logging calls on this logger, this method is a no-op. + /// + public void Warning(string message) + { + } + + /// + /// As with all logging calls on this logger, this method is a no-op. + /// + public void Warning(Exception exception, string message) + { + } + + /// + /// As with all logging calls on this logger, this method is a no-op. + /// + public void Warning(string format, params object[] formatArgs) + { + } + } +} diff --git a/src/python/grpcio/grpc/_cython/imports.generated.c b/src/python/grpcio/grpc/_cython/imports.generated.c index 817303c8a4a..4b1860ce8c9 100644 --- a/src/python/grpcio/grpc/_cython/imports.generated.c +++ b/src/python/grpcio/grpc/_cython/imports.generated.c @@ -137,6 +137,7 @@ grpc_auth_context_add_cstring_property_type grpc_auth_context_add_cstring_proper grpc_auth_context_set_peer_identity_property_name_type grpc_auth_context_set_peer_identity_property_name_import; grpc_channel_credentials_release_type grpc_channel_credentials_release_import; grpc_google_default_credentials_create_type grpc_google_default_credentials_create_import; +grpc_set_ssl_roots_override_callback_type grpc_set_ssl_roots_override_callback_import; grpc_ssl_credentials_create_type grpc_ssl_credentials_create_import; grpc_call_credentials_release_type grpc_call_credentials_release_import; grpc_composite_channel_credentials_create_type grpc_composite_channel_credentials_create_import; @@ -296,6 +297,10 @@ gpr_thd_options_is_joinable_type gpr_thd_options_is_joinable_import; gpr_thd_currentid_type gpr_thd_currentid_import; gpr_thd_join_type gpr_thd_join_import; +#ifdef __cplusplus +extern "C" { +#endif /* __cpluslus */ + void pygrpc_load_imports(HMODULE library) { census_initialize_import = (census_initialize_type) GetProcAddress(library, "census_initialize"); census_shutdown_import = (census_shutdown_type) GetProcAddress(library, "census_shutdown"); @@ -397,6 +402,7 @@ void pygrpc_load_imports(HMODULE library) { grpc_auth_context_set_peer_identity_property_name_import = (grpc_auth_context_set_peer_identity_property_name_type) GetProcAddress(library, "grpc_auth_context_set_peer_identity_property_name"); grpc_channel_credentials_release_import = (grpc_channel_credentials_release_type) GetProcAddress(library, "grpc_channel_credentials_release"); grpc_google_default_credentials_create_import = (grpc_google_default_credentials_create_type) GetProcAddress(library, "grpc_google_default_credentials_create"); + grpc_set_ssl_roots_override_callback_import = (grpc_set_ssl_roots_override_callback_type) GetProcAddress(library, "grpc_set_ssl_roots_override_callback"); grpc_ssl_credentials_create_import = (grpc_ssl_credentials_create_type) GetProcAddress(library, "grpc_ssl_credentials_create"); grpc_call_credentials_release_import = (grpc_call_credentials_release_type) GetProcAddress(library, "grpc_call_credentials_release"); grpc_composite_channel_credentials_create_import = (grpc_composite_channel_credentials_create_type) GetProcAddress(library, "grpc_composite_channel_credentials_create"); @@ -557,4 +563,8 @@ void pygrpc_load_imports(HMODULE library) { gpr_thd_join_import = (gpr_thd_join_type) GetProcAddress(library, "gpr_thd_join"); } +#ifdef __cplusplus +} +#endif /* __cpluslus */ + #endif /* !GPR_WIN32 */ diff --git a/src/python/grpcio/grpc/_cython/imports.generated.h b/src/python/grpcio/grpc/_cython/imports.generated.h index 6d0a6e06c00..ca30742abcb 100644 --- a/src/python/grpcio/grpc/_cython/imports.generated.h +++ b/src/python/grpcio/grpc/_cython/imports.generated.h @@ -361,6 +361,9 @@ extern grpc_channel_credentials_release_type grpc_channel_credentials_release_im typedef grpc_channel_credentials *(*grpc_google_default_credentials_create_type)(void); extern grpc_google_default_credentials_create_type grpc_google_default_credentials_create_import; #define grpc_google_default_credentials_create grpc_google_default_credentials_create_import +typedef void(*grpc_set_ssl_roots_override_callback_type)(grpc_ssl_roots_override_callback cb); +extern grpc_set_ssl_roots_override_callback_type grpc_set_ssl_roots_override_callback_import; +#define grpc_set_ssl_roots_override_callback grpc_set_ssl_roots_override_callback_import typedef grpc_channel_credentials *(*grpc_ssl_credentials_create_type)(const char *pem_root_certs, grpc_ssl_pem_key_cert_pair *pem_key_cert_pair, void *reserved); extern grpc_ssl_credentials_create_type grpc_ssl_credentials_create_import; #define grpc_ssl_credentials_create grpc_ssl_credentials_create_import @@ -836,8 +839,16 @@ typedef void(*gpr_thd_join_type)(gpr_thd_id t); extern gpr_thd_join_type gpr_thd_join_import; #define gpr_thd_join gpr_thd_join_import +#ifdef __cplusplus +extern "C" { +#endif /* __cpluslus */ + void pygrpc_load_imports(HMODULE library); +#ifdef __cplusplus +} +#endif /* __cpluslus */ + #else /* !GPR_WIN32 */ #include diff --git a/src/python/grpcio/grpc/_cython/loader.c b/src/python/grpcio/grpc/_cython/loader.c index cdd47deed30..3b72806ea18 100644 --- a/src/python/grpcio/grpc/_cython/loader.c +++ b/src/python/grpcio/grpc/_cython/loader.c @@ -33,6 +33,10 @@ #include "loader.h" +#ifdef __cplusplus +extern "C" { +#endif /* __cpluslus */ + #if GPR_WIN32 int pygrpc_load_core(char *path) { @@ -56,4 +60,9 @@ int pygrpc_load_core(char *path) { int pygrpc_load_core(char *path) { return 1; } -#endif +#endif /* !GPR_WIN32 */ + +#ifdef __cplusplus +} +#endif /* __cpluslus */ + diff --git a/src/python/grpcio/grpc/_cython/loader.h b/src/python/grpcio/grpc/_cython/loader.h index dd31e1561b5..3b8796d39f7 100644 --- a/src/python/grpcio/grpc/_cython/loader.h +++ b/src/python/grpcio/grpc/_cython/loader.h @@ -39,7 +39,16 @@ /* Additional inclusions not covered by "imports.generated.h" */ #include +#ifdef __cplusplus +extern "C" { +#endif /* __cpluslus */ + /* Attempts to load the core if necessary, and return non-zero upon succes. */ int pygrpc_load_core(char *path); +#ifdef __cplusplus +} +#endif /* __cpluslus */ + #endif /* GRPC_RB_BYTE_BUFFER_H_ */ + diff --git a/src/python/grpcio/grpc_core_dependencies.py b/src/python/grpcio/grpc_core_dependencies.py index 632a7c4c081..38b2226e4e5 100644 --- a/src/python/grpcio/grpc_core_dependencies.py +++ b/src/python/grpcio/grpc_core_dependencies.py @@ -121,6 +121,7 @@ CORE_SOURCE_FILES = [ 'src/core/client_config/resolvers/sockaddr_resolver.c', 'src/core/client_config/subchannel.c', 'src/core/client_config/subchannel_factory.c', + 'src/core/client_config/subchannel_index.c', 'src/core/client_config/uri_parser.c', 'src/core/compression/algorithm.c', 'src/core/compression/message_compress.c', diff --git a/src/ruby/ext/grpc/rb_grpc_imports.generated.c b/src/ruby/ext/grpc/rb_grpc_imports.generated.c index d4ddb734c0d..1af34d97fbc 100644 --- a/src/ruby/ext/grpc/rb_grpc_imports.generated.c +++ b/src/ruby/ext/grpc/rb_grpc_imports.generated.c @@ -137,6 +137,7 @@ grpc_auth_context_add_cstring_property_type grpc_auth_context_add_cstring_proper grpc_auth_context_set_peer_identity_property_name_type grpc_auth_context_set_peer_identity_property_name_import; grpc_channel_credentials_release_type grpc_channel_credentials_release_import; grpc_google_default_credentials_create_type grpc_google_default_credentials_create_import; +grpc_set_ssl_roots_override_callback_type grpc_set_ssl_roots_override_callback_import; grpc_ssl_credentials_create_type grpc_ssl_credentials_create_import; grpc_call_credentials_release_type grpc_call_credentials_release_import; grpc_composite_channel_credentials_create_type grpc_composite_channel_credentials_create_import; @@ -397,6 +398,7 @@ void grpc_rb_load_imports(HMODULE library) { grpc_auth_context_set_peer_identity_property_name_import = (grpc_auth_context_set_peer_identity_property_name_type) GetProcAddress(library, "grpc_auth_context_set_peer_identity_property_name"); grpc_channel_credentials_release_import = (grpc_channel_credentials_release_type) GetProcAddress(library, "grpc_channel_credentials_release"); grpc_google_default_credentials_create_import = (grpc_google_default_credentials_create_type) GetProcAddress(library, "grpc_google_default_credentials_create"); + grpc_set_ssl_roots_override_callback_import = (grpc_set_ssl_roots_override_callback_type) GetProcAddress(library, "grpc_set_ssl_roots_override_callback"); grpc_ssl_credentials_create_import = (grpc_ssl_credentials_create_type) GetProcAddress(library, "grpc_ssl_credentials_create"); grpc_call_credentials_release_import = (grpc_call_credentials_release_type) GetProcAddress(library, "grpc_call_credentials_release"); grpc_composite_channel_credentials_create_import = (grpc_composite_channel_credentials_create_type) GetProcAddress(library, "grpc_composite_channel_credentials_create"); diff --git a/src/ruby/ext/grpc/rb_grpc_imports.generated.h b/src/ruby/ext/grpc/rb_grpc_imports.generated.h index 618ae5e7fcf..b61c5282b6d 100644 --- a/src/ruby/ext/grpc/rb_grpc_imports.generated.h +++ b/src/ruby/ext/grpc/rb_grpc_imports.generated.h @@ -361,6 +361,9 @@ extern grpc_channel_credentials_release_type grpc_channel_credentials_release_im typedef grpc_channel_credentials *(*grpc_google_default_credentials_create_type)(void); extern grpc_google_default_credentials_create_type grpc_google_default_credentials_create_import; #define grpc_google_default_credentials_create grpc_google_default_credentials_create_import +typedef void(*grpc_set_ssl_roots_override_callback_type)(grpc_ssl_roots_override_callback cb); +extern grpc_set_ssl_roots_override_callback_type grpc_set_ssl_roots_override_callback_import; +#define grpc_set_ssl_roots_override_callback grpc_set_ssl_roots_override_callback_import typedef grpc_channel_credentials *(*grpc_ssl_credentials_create_type)(const char *pem_root_certs, grpc_ssl_pem_key_cert_pair *pem_key_cert_pair, void *reserved); extern grpc_ssl_credentials_create_type grpc_ssl_credentials_create_import; #define grpc_ssl_credentials_create grpc_ssl_credentials_create_import diff --git a/templates/src/python/grpcio/grpc/_cython/imports.generated.c.template b/templates/src/python/grpcio/grpc/_cython/imports.generated.c.template index be33280c0ce..62fe0947d25 100644 --- a/templates/src/python/grpcio/grpc/_cython/imports.generated.c.template +++ b/templates/src/python/grpcio/grpc/_cython/imports.generated.c.template @@ -43,10 +43,19 @@ ${api.name}_type ${api.name}_import; %endfor + #ifdef __cplusplus + extern "C" { + #endif /* __cpluslus */ + void pygrpc_load_imports(HMODULE library) { %for api in c_apis: ${api.name}_import = (${api.name}_type) GetProcAddress(library, "${api.name}"); %endfor } + #ifdef __cplusplus + } + #endif /* __cpluslus */ + #endif /* !GPR_WIN32 */ + diff --git a/templates/src/python/grpcio/grpc/_cython/imports.generated.h.template b/templates/src/python/grpcio/grpc/_cython/imports.generated.h.template index 6866a61caef..8e7c1831800 100644 --- a/templates/src/python/grpcio/grpc/_cython/imports.generated.h.template +++ b/templates/src/python/grpcio/grpc/_cython/imports.generated.h.template @@ -52,8 +52,16 @@ #define ${api.name} ${api.name}_import %endfor + #ifdef __cplusplus + extern "C" { + #endif /* __cpluslus */ + void pygrpc_load_imports(HMODULE library); + #ifdef __cplusplus + } + #endif /* __cpluslus */ + #else /* !GPR_WIN32 */ #include diff --git a/test/core/end2end/fixtures/h2_uchannel.c b/test/core/end2end/fixtures/h2_uchannel.c index 5ab64f9800b..dbdd3524ed0 100644 --- a/test/core/end2end/fixtures/h2_uchannel.c +++ b/test/core/end2end/fixtures/h2_uchannel.c @@ -159,7 +159,7 @@ static grpc_subchannel *subchannel_factory_create_subchannel( c->base.vtable = &connector_vtable; gpr_ref_init(&c->refs, 1); args->args = final_args; - s = grpc_subchannel_create(&c->base, args); + s = grpc_subchannel_create(exec_ctx, &c->base, args); grpc_connector_unref(exec_ctx, &c->base); grpc_channel_args_destroy(final_args); if (*f->sniffed_subchannel) { diff --git a/test/cpp/common/channel_arguments_test.cc b/test/cpp/common/channel_arguments_test.cc index e010d375cf9..5ee63bf6885 100644 --- a/test/cpp/common/channel_arguments_test.cc +++ b/test/cpp/common/channel_arguments_test.cc @@ -1,6 +1,6 @@ /* * - * Copyright 2015, Google Inc. + * Copyright 2015-2016, Google Inc. * All rights reserved. * * Redistribution and use in source and binary forms, with or without @@ -45,90 +45,131 @@ class ChannelArgumentsTest : public ::testing::Test { grpc_channel_args* args) { channel_args.SetChannelArgs(args); } + + grpc::string GetDefaultUserAgentPrefix() { + std::ostringstream user_agent_prefix; + user_agent_prefix << "grpc-c++/" << grpc_version_string(); + return user_agent_prefix.str(); + } + + void VerifyDefaultChannelArgs() { + grpc_channel_args args; + SetChannelArgs(channel_args_, &args); + EXPECT_EQ(static_cast(1), args.num_args); + EXPECT_STREQ(GRPC_ARG_PRIMARY_USER_AGENT_STRING, args.args[0].key); + EXPECT_EQ(GetDefaultUserAgentPrefix(), + grpc::string(args.args[0].value.string)); + } + + bool HasArg(grpc_arg expected_arg) { + grpc_channel_args args; + SetChannelArgs(channel_args_, &args); + for (size_t i = 0; i < args.num_args; i++) { + const grpc_arg& arg = args.args[i]; + if (arg.type == expected_arg.type && + grpc::string(arg.key) == expected_arg.key) { + if (arg.type == GRPC_ARG_INTEGER) { + return arg.value.integer == expected_arg.value.integer; + } else if (arg.type == GRPC_ARG_STRING) { + return grpc::string(arg.value.string) == expected_arg.value.string; + } else if (arg.type == GRPC_ARG_POINTER) { + return arg.value.pointer.p == expected_arg.value.pointer.p && + arg.value.pointer.copy == expected_arg.value.pointer.copy && + arg.value.pointer.destroy == + expected_arg.value.pointer.destroy; + } + } + } + return false; + } + ChannelArguments channel_args_; }; TEST_F(ChannelArgumentsTest, SetInt) { - grpc_channel_args args; - ChannelArguments channel_args; - // Empty arguments. - SetChannelArgs(channel_args, &args); - EXPECT_EQ(static_cast(0), args.num_args); - - grpc::string key("key0"); - channel_args.SetInt(key, 0); + VerifyDefaultChannelArgs(); + grpc::string key0("key0"); + grpc_arg arg0; + arg0.type = GRPC_ARG_INTEGER; + arg0.key = const_cast(key0.c_str()); + arg0.value.integer = 0; + grpc::string key1("key1"); + grpc_arg arg1; + arg1.type = GRPC_ARG_INTEGER; + arg1.key = const_cast(key1.c_str()); + arg1.value.integer = 1; + + grpc::string arg_key0(key0); + channel_args_.SetInt(arg_key0, arg0.value.integer); // Clear key early to make sure channel_args takes a copy - key = ""; - SetChannelArgs(channel_args, &args); - EXPECT_EQ(static_cast(1), args.num_args); - EXPECT_EQ(GRPC_ARG_INTEGER, args.args[0].type); - EXPECT_STREQ("key0", args.args[0].key); - EXPECT_EQ(0, args.args[0].value.integer); - - key = "key1"; - channel_args.SetInt(key, 1); - key = ""; - SetChannelArgs(channel_args, &args); - EXPECT_EQ(static_cast(2), args.num_args); - // We do not enforce order on the arguments. - for (size_t i = 0; i < args.num_args; i++) { - EXPECT_EQ(GRPC_ARG_INTEGER, args.args[i].type); - if (grpc::string(args.args[i].key) == "key0") { - EXPECT_EQ(0, args.args[i].value.integer); - } else if (grpc::string(args.args[i].key) == "key1") { - EXPECT_EQ(1, args.args[i].value.integer); - } - } + arg_key0.clear(); + EXPECT_TRUE(HasArg(arg0)); + + grpc::string arg_key1(key1); + channel_args_.SetInt(arg_key1, arg1.value.integer); + arg_key1.clear(); + EXPECT_TRUE(HasArg(arg0)); + EXPECT_TRUE(HasArg(arg1)); } TEST_F(ChannelArgumentsTest, SetString) { - grpc_channel_args args; - ChannelArguments channel_args; - // Empty arguments. - SetChannelArgs(channel_args, &args); - EXPECT_EQ(static_cast(0), args.num_args); - - grpc::string key("key0"); - grpc::string val("val0"); - channel_args.SetString(key, val); + VerifyDefaultChannelArgs(); + grpc::string key0("key0"); + grpc::string val0("val0"); + grpc_arg arg0; + arg0.type = GRPC_ARG_STRING; + arg0.key = const_cast(key0.c_str()); + arg0.value.string = const_cast(val0.c_str()); + grpc::string key1("key1"); + grpc::string val1("val1"); + grpc_arg arg1; + arg1.type = GRPC_ARG_STRING; + arg1.key = const_cast(key1.c_str()); + arg1.value.string = const_cast(val1.c_str()); + + grpc::string key(key0); + grpc::string val(val0); + channel_args_.SetString(key, val); // Clear key/val early to make sure channel_args takes a copy key = ""; val = ""; - SetChannelArgs(channel_args, &args); - EXPECT_EQ(static_cast(1), args.num_args); - EXPECT_EQ(GRPC_ARG_STRING, args.args[0].type); - EXPECT_STREQ("key0", args.args[0].key); - EXPECT_STREQ("val0", args.args[0].value.string); - - key = "key1"; - val = "val1"; - channel_args.SetString(key, val); - SetChannelArgs(channel_args, &args); - EXPECT_EQ(static_cast(2), args.num_args); - // We do not enforce order on the arguments. - for (size_t i = 0; i < args.num_args; i++) { - EXPECT_EQ(GRPC_ARG_STRING, args.args[i].type); - if (grpc::string(args.args[i].key) == "key0") { - EXPECT_STREQ("val0", args.args[i].value.string); - } else if (grpc::string(args.args[i].key) == "key1") { - EXPECT_STREQ("val1", args.args[i].value.string); - } - } + EXPECT_TRUE(HasArg(arg0)); + + key = key1; + val = val1; + channel_args_.SetString(key, val); + // Clear key/val early to make sure channel_args takes a copy + key = ""; + val = ""; + EXPECT_TRUE(HasArg(arg0)); + EXPECT_TRUE(HasArg(arg1)); } TEST_F(ChannelArgumentsTest, SetPointer) { - grpc_channel_args args; - ChannelArguments channel_args; - // Empty arguments. - SetChannelArgs(channel_args, &args); - EXPECT_EQ(static_cast(0), args.num_args); - - grpc::string key("key0"); - channel_args.SetPointer(key, &key); - SetChannelArgs(channel_args, &args); - EXPECT_EQ(static_cast(1), args.num_args); - EXPECT_EQ(GRPC_ARG_POINTER, args.args[0].type); - EXPECT_STREQ("key0", args.args[0].key); - EXPECT_EQ(&key, args.args[0].value.pointer.p); + VerifyDefaultChannelArgs(); + grpc::string key0("key0"); + grpc_arg arg0; + arg0.type = GRPC_ARG_POINTER; + arg0.key = const_cast(key0.c_str()); + arg0.value.pointer.p = &key0; + arg0.value.pointer.copy = nullptr; + arg0.value.pointer.destroy = nullptr; + + grpc::string key(key0); + channel_args_.SetPointer(key, arg0.value.pointer.p); + EXPECT_TRUE(HasArg(arg0)); +} + +TEST_F(ChannelArgumentsTest, SetUserAgentPrefix) { + VerifyDefaultChannelArgs(); + grpc::string prefix("prefix"); + grpc::string whole_prefix = prefix + " " + GetDefaultUserAgentPrefix(); + grpc_arg arg0; + arg0.type = GRPC_ARG_STRING; + arg0.key = const_cast(GRPC_ARG_PRIMARY_USER_AGENT_STRING); + arg0.value.string = const_cast(whole_prefix.c_str()); + + channel_args_.SetUserAgentPrefix(prefix); + EXPECT_TRUE(HasArg(arg0)); } } // namespace testing diff --git a/test/cpp/end2end/end2end_test.cc b/test/cpp/end2end/end2end_test.cc index 65da71b3915..c8523847ab2 100644 --- a/test/cpp/end2end/end2end_test.cc +++ b/test/cpp/end2end/end2end_test.cc @@ -252,6 +252,9 @@ class End2endTest : public ::testing::TestWithParam { args.SetSslTargetNameOverride("foo.test.google.fr"); channel_creds = SslCredentials(ssl_opts); } + if (!user_agent_prefix_.empty()) { + args.SetUserAgentPrefix(user_agent_prefix_); + } args.SetString(GRPC_ARG_SECONDARY_USER_AGENT_STRING, "end2end_test"); channel_ = CreateCustomChannel(server_address_.str(), channel_creds, args); } @@ -285,6 +288,7 @@ class End2endTest : public ::testing::TestWithParam { TestServiceImpl service_; TestServiceImpl special_service_; TestServiceImplDupPkg dup_pkg_service_; + grpc::string user_agent_prefix_; }; static void SendRpc(grpc::testing::EchoTestService::Stub* stub, int num_rpcs, @@ -601,6 +605,25 @@ TEST_P(End2endServerTryCancelTest, BidiStreamServerCancelAfter) { TestBidiStreamServerCancel(CANCEL_AFTER_PROCESSING, 5); } +TEST_P(End2endTest, SimpleRpcWithCustomeUserAgentPrefix) { + user_agent_prefix_ = "custom_prefix"; + ResetStub(); + EchoRequest request; + EchoResponse response; + request.set_message("Hello hello hello hello"); + request.mutable_param()->set_echo_metadata(true); + + ClientContext context; + Status s = stub_->Echo(&context, request, &response); + EXPECT_EQ(response.message(), request.message()); + EXPECT_TRUE(s.ok()); + const auto& trailing_metadata = context.GetServerTrailingMetadata(); + auto iter = trailing_metadata.find("user-agent"); + EXPECT_TRUE(iter != trailing_metadata.end()); + grpc::string expected_prefix = user_agent_prefix_ + " grpc-c++/"; + EXPECT_TRUE(iter->second.starts_with(expected_prefix)); +} + TEST_P(End2endTest, MultipleRpcsWithVariedBinaryMetadataValue) { ResetStub(); std::vector threads; diff --git a/test/cpp/qps/qps-sweep.sh b/test/cpp/qps/qps-sweep.sh index 539da1d8930..7a357888497 100755 --- a/test/cpp/qps/qps-sweep.sh +++ b/test/cpp/qps/qps-sweep.sh @@ -37,9 +37,26 @@ fi bins=`find . .. ../.. ../../.. -name bins | head -1` +# Print out each command that gets executed set -x +# +# Specify parameters used in some of the tests +# + +# big is the size in bytes of large messages (0 is the size otherwise) big=65536 + +# wide is the number of client channels in multi-channel tests (1 otherwise) +wide=64 + +# deep is the number of RPCs outstanding on a channel in non-ping-pong tests +# (the value used is 1 otherwise) +deep=100 + +# half is half the count of worker processes, used in the crossbar scenario +# that uses equal clients and servers. The other scenarios use only 1 server +# and either 1 client or N-1 clients as appropriate half=`echo $QPS_WORKERS | awk -F, '{print int(NF/2)}'` for secure in true false; do @@ -52,30 +69,40 @@ for secure in true false; do # Scenario 2: generic async streaming "unconstrained" (QPS) "$bins"/opt/qps_driver --rpc_type=STREAMING --client_type=ASYNC_CLIENT \ - --server_type=ASYNC_GENERIC_SERVER --outstanding_rpcs_per_channel=100 \ - --client_channels=64 --bbuf_req_size=0 --bbuf_resp_size=0 \ + --server_type=ASYNC_GENERIC_SERVER --outstanding_rpcs_per_channel=$deep \ + --client_channels=$wide --bbuf_req_size=0 --bbuf_resp_size=0 \ --async_client_threads=0 --async_server_threads=0 --secure_test=$secure \ - --num_servers=1 --num_clients=0 + --num_servers=1 --num_clients=0 |& tee /tmp/qps-test.$$ # Scenario 2b: QPS with a single server core "$bins"/opt/qps_driver --rpc_type=STREAMING --client_type=ASYNC_CLIENT \ - --server_type=ASYNC_GENERIC_SERVER --outstanding_rpcs_per_channel=100 \ - --client_channels=64 --bbuf_req_size=0 --bbuf_resp_size=0 \ + --server_type=ASYNC_GENERIC_SERVER --outstanding_rpcs_per_channel=$deep \ + --client_channels=$wide --bbuf_req_size=0 --bbuf_resp_size=0 \ --async_client_threads=0 --async_server_threads=0 --secure_test=$secure \ --num_servers=1 --num_clients=0 --server_core_limit=1 # Scenario 2c: protobuf-based QPS "$bins"/opt/qps_driver --rpc_type=STREAMING --client_type=ASYNC_CLIENT \ - --server_type=ASYNC_SERVER --outstanding_rpcs_per_channel=100 \ - --client_channels=64 --simple_req_size=0 --simple_resp_size=0 \ + --server_type=ASYNC_SERVER --outstanding_rpcs_per_channel=$deep \ + --client_channels=$wide --simple_req_size=0 --simple_resp_size=0 \ --async_client_threads=0 --async_server_threads=0 --secure_test=$secure \ --num_servers=1 --num_clients=0 - # Scenario 3: Latency at near-peak load (TBD) + # Scenario 3: Latency at sub-peak load (all clients equally loaded) + for loadfactor in 0.2 0.5 0.7; do + "$bins"/opt/qps_driver --rpc_type=STREAMING --client_type=ASYNC_CLIENT \ + --server_type=ASYNC_GENERIC_SERVER --outstanding_rpcs_per_channel=$deep \ + --client_channels=$wide --bbuf_req_size=0 --bbuf_resp_size=0 \ + --async_client_threads=0 --async_server_threads=0 --secure_test=$secure \ + --num_servers=1 --num_clients=0 --poisson_load=`awk -v lf=$loadfactor \ + '$5 == "QPS:" {print int(lf * $6); exit}' /tmp/qps-test.$$` + done + + rm /tmp/qps-test.$$ # Scenario 4: Single-channel bidirectional throughput test (like TCP_STREAM). "$bins"/opt/qps_driver --rpc_type=STREAMING --client_type=ASYNC_CLIENT \ - --server_type=ASYNC_GENERIC_SERVER --outstanding_rpcs_per_channel=100 \ + --server_type=ASYNC_GENERIC_SERVER --outstanding_rpcs_per_channel=$deep \ --client_channels=1 --bbuf_req_size=$big --bbuf_resp_size=$big \ --async_client_threads=1 --async_server_threads=1 --secure_test=$secure \ --num_servers=1 --num_clients=1 @@ -108,35 +135,35 @@ for secure in true false; do # Scenario 9: Crossbar QPS test "$bins"/opt/qps_driver --rpc_type=STREAMING --client_type=ASYNC_CLIENT \ - --server_type=ASYNC_GENERIC_SERVER --outstanding_rpcs_per_channel=100 \ - --client_channels=64 --bbuf_req_size=0 --bbuf_resp_size=0 \ + --server_type=ASYNC_GENERIC_SERVER --outstanding_rpcs_per_channel=$deep \ + --client_channels=$wide --bbuf_req_size=0 --bbuf_resp_size=0 \ --async_client_threads=0 --async_server_threads=0 --secure_test=$secure \ --num_servers=$half --num_clients=0 # Scenario 10: Multi-channel bidir throughput test "$bins"/opt/qps_driver --rpc_type=STREAMING --client_type=ASYNC_CLIENT \ - --server_type=ASYNC_GENERIC_SERVER --outstanding_rpcs_per_channel=100 \ - --client_channels=64 --bbuf_req_size=$big --bbuf_resp_size=$big \ + --server_type=ASYNC_GENERIC_SERVER --outstanding_rpcs_per_channel=1 \ + --client_channels=$wide --bbuf_req_size=$big --bbuf_resp_size=$big \ --async_client_threads=0 --async_server_threads=0 --secure_test=$secure \ --num_servers=1 --num_clients=1 # Scenario 11: Single-channel request throughput test "$bins"/opt/qps_driver --rpc_type=STREAMING --client_type=ASYNC_CLIENT \ - --server_type=ASYNC_GENERIC_SERVER --outstanding_rpcs_per_channel=100 \ + --server_type=ASYNC_GENERIC_SERVER --outstanding_rpcs_per_channel=$deep \ --client_channels=1 --bbuf_req_size=$big --bbuf_resp_size=0 \ --async_client_threads=1 --async_server_threads=1 --secure_test=$secure \ --num_servers=1 --num_clients=1 # Scenario 12: Single-channel response throughput test "$bins"/opt/qps_driver --rpc_type=STREAMING --client_type=ASYNC_CLIENT \ - --server_type=ASYNC_GENERIC_SERVER --outstanding_rpcs_per_channel=100 \ + --server_type=ASYNC_GENERIC_SERVER --outstanding_rpcs_per_channel=$deep \ --client_channels=1 --bbuf_req_size=0 --bbuf_resp_size=$big \ --async_client_threads=1 --async_server_threads=1 --secure_test=$secure \ --num_servers=1 --num_clients=1 # Scenario 13: Single-channel bidirectional protobuf throughput test "$bins"/opt/qps_driver --rpc_type=STREAMING --client_type=ASYNC_CLIENT \ - --server_type=ASYNC_SERVER --outstanding_rpcs_per_channel=100 \ + --server_type=ASYNC_SERVER --outstanding_rpcs_per_channel=$deep \ --client_channels=1 --simple_req_size=$big --simple_resp_size=$big \ --async_client_threads=1 --async_server_threads=1 --secure_test=$secure \ --num_servers=1 --num_clients=1 diff --git a/tools/distrib/check_copyright.py b/tools/distrib/check_copyright.py index d1a34a920dc..99771f9632c 100755 --- a/tools/distrib/check_copyright.py +++ b/tools/distrib/check_copyright.py @@ -71,9 +71,9 @@ with open('LICENSE') as f: # that given a line of license text, returns what should # be in the file LICENSE_PREFIX = { - '.c': r'\s*\*\s*', - '.cc': r'\s*\*\s*', - '.h': r'\s*\*\s*', + '.c': r'\s*(?://|\*)\s*', + '.cc': r'\s*(?://|\*)\s*', + '.h': r'\s*(?://|\*)\s*', '.m': r'\s*\*\s*', '.php': r'\s*\*\s*', '.js': r'\s*\*\s*', diff --git a/tools/doxygen/Doxyfile.core.internal b/tools/doxygen/Doxyfile.core.internal index 502fe39844d..219ca7ff7e6 100644 --- a/tools/doxygen/Doxyfile.core.internal +++ b/tools/doxygen/Doxyfile.core.internal @@ -813,6 +813,7 @@ src/core/client_config/resolvers/dns_resolver.h \ src/core/client_config/resolvers/sockaddr_resolver.h \ src/core/client_config/subchannel.h \ src/core/client_config/subchannel_factory.h \ +src/core/client_config/subchannel_index.h \ src/core/client_config/uri_parser.h \ src/core/compression/algorithm_metadata.h \ src/core/compression/message_compress.h \ @@ -951,6 +952,7 @@ src/core/client_config/resolvers/dns_resolver.c \ src/core/client_config/resolvers/sockaddr_resolver.c \ src/core/client_config/subchannel.c \ src/core/client_config/subchannel_factory.c \ +src/core/client_config/subchannel_index.c \ src/core/client_config/uri_parser.c \ src/core/compression/algorithm.c \ src/core/compression/message_compress.c \ diff --git a/tools/asan_suppressions.txt b/tools/lsan_suppressions.txt similarity index 100% rename from tools/asan_suppressions.txt rename to tools/lsan_suppressions.txt diff --git a/tools/run_tests/configs.json b/tools/run_tests/configs.json index d508c6394cb..9d7b8a3c725 100644 --- a/tools/run_tests/configs.json +++ b/tools/run_tests/configs.json @@ -45,8 +45,8 @@ { "config": "asan", "environ": { - "ASAN_OPTIONS": "suppressions=tools/asan_suppressions.txt:detect_leaks=1:color=always", - "LSAN_OPTIONS": "suppressions=tools/asan_suppressions.txt:report_objects=1" + "ASAN_OPTIONS": "detect_leaks=1:color=always", + "LSAN_OPTIONS": "suppressions=tools/lsan_suppressions.txt:report_objects=1" }, "timeout_multiplier": 1.5 }, diff --git a/tools/run_tests/sources_and_headers.json b/tools/run_tests/sources_and_headers.json index a5ff6b51b82..5b1b67439db 100644 --- a/tools/run_tests/sources_and_headers.json +++ b/tools/run_tests/sources_and_headers.json @@ -3010,6 +3010,7 @@ "src/core/client_config/resolvers/sockaddr_resolver.h", "src/core/client_config/subchannel.h", "src/core/client_config/subchannel_factory.h", + "src/core/client_config/subchannel_index.h", "src/core/client_config/uri_parser.h", "src/core/compression/algorithm_metadata.h", "src/core/compression/message_compress.h", @@ -3190,6 +3191,8 @@ "src/core/client_config/subchannel.h", "src/core/client_config/subchannel_factory.c", "src/core/client_config/subchannel_factory.h", + "src/core/client_config/subchannel_index.c", + "src/core/client_config/subchannel_index.h", "src/core/client_config/uri_parser.c", "src/core/client_config/uri_parser.h", "src/core/compression/algorithm.c", @@ -3538,6 +3541,7 @@ "src/core/client_config/resolvers/sockaddr_resolver.h", "src/core/client_config/subchannel.h", "src/core/client_config/subchannel_factory.h", + "src/core/client_config/subchannel_index.h", "src/core/client_config/uri_parser.h", "src/core/compression/algorithm_metadata.h", "src/core/compression/message_compress.h", @@ -3703,6 +3707,8 @@ "src/core/client_config/subchannel.h", "src/core/client_config/subchannel_factory.c", "src/core/client_config/subchannel_factory.h", + "src/core/client_config/subchannel_index.c", + "src/core/client_config/subchannel_index.h", "src/core/client_config/uri_parser.c", "src/core/client_config/uri_parser.h", "src/core/compression/algorithm.c", diff --git a/vsprojects/vcxproj/grpc/grpc.vcxproj b/vsprojects/vcxproj/grpc/grpc.vcxproj index faef347883f..569200ceea5 100644 --- a/vsprojects/vcxproj/grpc/grpc.vcxproj +++ b/vsprojects/vcxproj/grpc/grpc.vcxproj @@ -322,6 +322,7 @@ + @@ -510,6 +511,8 @@ + + diff --git a/vsprojects/vcxproj/grpc/grpc.vcxproj.filters b/vsprojects/vcxproj/grpc/grpc.vcxproj.filters index 9afcbf00535..275cf6e169d 100644 --- a/vsprojects/vcxproj/grpc/grpc.vcxproj.filters +++ b/vsprojects/vcxproj/grpc/grpc.vcxproj.filters @@ -145,6 +145,9 @@ src\core\client_config + + src\core\client_config + src\core\client_config @@ -626,6 +629,9 @@ src\core\client_config + + src\core\client_config + src\core\client_config diff --git a/vsprojects/vcxproj/grpc_unsecure/grpc_unsecure.vcxproj b/vsprojects/vcxproj/grpc_unsecure/grpc_unsecure.vcxproj index 4edcfab8291..2092397136f 100644 --- a/vsprojects/vcxproj/grpc_unsecure/grpc_unsecure.vcxproj +++ b/vsprojects/vcxproj/grpc_unsecure/grpc_unsecure.vcxproj @@ -298,6 +298,7 @@ + @@ -446,6 +447,8 @@ + + diff --git a/vsprojects/vcxproj/grpc_unsecure/grpc_unsecure.vcxproj.filters b/vsprojects/vcxproj/grpc_unsecure/grpc_unsecure.vcxproj.filters index 11510b5ceb4..f6e5275b799 100644 --- a/vsprojects/vcxproj/grpc_unsecure/grpc_unsecure.vcxproj.filters +++ b/vsprojects/vcxproj/grpc_unsecure/grpc_unsecure.vcxproj.filters @@ -85,6 +85,9 @@ src\core\client_config + + src\core\client_config + src\core\client_config @@ -521,6 +524,9 @@ src\core\client_config + + src\core\client_config + src\core\client_config