From 5e9848e7b078ac35c0b6899d27c780e3836b3905 Mon Sep 17 00:00:00 2001 From: "Mark D. Roth" Date: Fri, 6 Oct 2017 13:59:32 -0700 Subject: [PATCH 01/47] Refactor subchannel_list code out of RR and use it in PF. --- BUILD | 17 + CMakeLists.txt | 2 + Makefile | 2 + binding.gyp | 1 + build.yaml | 10 + config.m4 | 2 + config.w32 | 1 + gRPC-Core.podspec | 3 + grpc.gemspec | 2 + grpc.gyp | 2 + package.xml | 2 + .../lb_policy/pick_first/pick_first.cc | 709 ++++++++---------- .../lb_policy/round_robin/round_robin.cc | 426 +++-------- .../lb_policy/subchannel_list.cc | 282 +++++++ .../lb_policy/subchannel_list.h | 149 ++++ src/python/grpcio/grpc_core_dependencies.py | 1 + tools/doxygen/Doxyfile.core.internal | 2 + .../generated/sources_and_headers.json | 25 +- 18 files changed, 903 insertions(+), 735 deletions(-) create mode 100644 src/core/ext/filters/client_channel/lb_policy/subchannel_list.cc create mode 100644 src/core/ext/filters/client_channel/lb_policy/subchannel_list.h diff --git a/BUILD b/BUILD index d0b37dfa6cc..3bab706a9b5 100644 --- a/BUILD +++ b/BUILD @@ -1071,6 +1071,21 @@ grpc_cc_library( ], ) +grpc_cc_library( + name = "grpc_lb_subchannel_list", + srcs = [ + "src/core/ext/filters/client_channel/lb_policy/subchannel_list.cc", + ], + hdrs = [ + "src/core/ext/filters/client_channel/lb_policy/subchannel_list.h", + ], + language = "c++", + deps = [ + "grpc_base", + "grpc_client_channel", + ], +) + grpc_cc_library( name = "grpc_lb_policy_pick_first", srcs = [ @@ -1080,6 +1095,7 @@ grpc_cc_library( deps = [ "grpc_base", "grpc_client_channel", + "grpc_lb_subchannel_list", ], ) @@ -1092,6 +1108,7 @@ grpc_cc_library( deps = [ "grpc_base", "grpc_client_channel", + "grpc_lb_subchannel_list", ], ) diff --git a/CMakeLists.txt b/CMakeLists.txt index 759d49bd980..8114c2cfe38 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -1186,6 +1186,7 @@ add_library(grpc third_party/nanopb/pb_encode.c src/core/ext/filters/client_channel/resolver/fake/fake_resolver.cc src/core/ext/filters/client_channel/lb_policy/pick_first/pick_first.cc + src/core/ext/filters/client_channel/lb_policy/subchannel_list.cc src/core/ext/filters/client_channel/lb_policy/round_robin/round_robin.cc src/core/ext/filters/client_channel/resolver/dns/c_ares/dns_resolver_ares.cc src/core/ext/filters/client_channel/resolver/dns/c_ares/grpc_ares_ev_driver_posix.cc @@ -2344,6 +2345,7 @@ add_library(grpc_unsecure third_party/nanopb/pb_decode.c third_party/nanopb/pb_encode.c src/core/ext/filters/client_channel/lb_policy/pick_first/pick_first.cc + src/core/ext/filters/client_channel/lb_policy/subchannel_list.cc src/core/ext/filters/client_channel/lb_policy/round_robin/round_robin.cc src/core/ext/census/base_resources.cc src/core/ext/census/context.cc diff --git a/Makefile b/Makefile index 5ea638a9e74..1d68d5a93c4 100644 --- a/Makefile +++ b/Makefile @@ -3177,6 +3177,7 @@ LIBGRPC_SRC = \ third_party/nanopb/pb_encode.c \ src/core/ext/filters/client_channel/resolver/fake/fake_resolver.cc \ src/core/ext/filters/client_channel/lb_policy/pick_first/pick_first.cc \ + src/core/ext/filters/client_channel/lb_policy/subchannel_list.cc \ src/core/ext/filters/client_channel/lb_policy/round_robin/round_robin.cc \ src/core/ext/filters/client_channel/resolver/dns/c_ares/dns_resolver_ares.cc \ src/core/ext/filters/client_channel/resolver/dns/c_ares/grpc_ares_ev_driver_posix.cc \ @@ -4303,6 +4304,7 @@ LIBGRPC_UNSECURE_SRC = \ third_party/nanopb/pb_decode.c \ third_party/nanopb/pb_encode.c \ src/core/ext/filters/client_channel/lb_policy/pick_first/pick_first.cc \ + src/core/ext/filters/client_channel/lb_policy/subchannel_list.cc \ src/core/ext/filters/client_channel/lb_policy/round_robin/round_robin.cc \ src/core/ext/census/base_resources.cc \ src/core/ext/census/context.cc \ diff --git a/binding.gyp b/binding.gyp index 1fd430154b4..08c7a2ceefa 100644 --- a/binding.gyp +++ b/binding.gyp @@ -889,6 +889,7 @@ 'third_party/nanopb/pb_encode.c', 'src/core/ext/filters/client_channel/resolver/fake/fake_resolver.cc', 'src/core/ext/filters/client_channel/lb_policy/pick_first/pick_first.cc', + 'src/core/ext/filters/client_channel/lb_policy/subchannel_list.cc', 'src/core/ext/filters/client_channel/lb_policy/round_robin/round_robin.cc', 'src/core/ext/filters/client_channel/resolver/dns/c_ares/dns_resolver_ares.cc', 'src/core/ext/filters/client_channel/resolver/dns/c_ares/grpc_ares_ev_driver_posix.cc', diff --git a/build.yaml b/build.yaml index 7033d52542d..022aeb5c4c8 100644 --- a/build.yaml +++ b/build.yaml @@ -588,6 +588,7 @@ filegroups: uses: - grpc_base - grpc_client_channel + - grpc_lb_subchannel_list - name: grpc_lb_policy_round_robin src: - src/core/ext/filters/client_channel/lb_policy/round_robin/round_robin.cc @@ -595,6 +596,15 @@ filegroups: uses: - grpc_base - grpc_client_channel + - grpc_lb_subchannel_list +- name: grpc_lb_subchannel_list + headers: + - src/core/ext/filters/client_channel/lb_policy/subchannel_list.h + src: + - src/core/ext/filters/client_channel/lb_policy/subchannel_list.cc + uses: + - grpc_base + - grpc_client_channel - name: grpc_max_age_filter headers: - src/core/ext/filters/max_age/max_age_filter.h diff --git a/config.m4 b/config.m4 index 34d7116c731..33509512485 100644 --- a/config.m4 +++ b/config.m4 @@ -317,6 +317,7 @@ if test "$PHP_GRPC" != "no"; then third_party/nanopb/pb_encode.c \ src/core/ext/filters/client_channel/resolver/fake/fake_resolver.cc \ src/core/ext/filters/client_channel/lb_policy/pick_first/pick_first.cc \ + src/core/ext/filters/client_channel/lb_policy/subchannel_list.cc \ src/core/ext/filters/client_channel/lb_policy/round_robin/round_robin.cc \ src/core/ext/filters/client_channel/resolver/dns/c_ares/dns_resolver_ares.cc \ src/core/ext/filters/client_channel/resolver/dns/c_ares/grpc_ares_ev_driver_posix.cc \ @@ -660,6 +661,7 @@ if test "$PHP_GRPC" != "no"; then PHP_ADD_BUILD_DIR($ext_builddir/src/core/ext/census) PHP_ADD_BUILD_DIR($ext_builddir/src/core/ext/census/gen) PHP_ADD_BUILD_DIR($ext_builddir/src/core/ext/filters/client_channel) + PHP_ADD_BUILD_DIR($ext_builddir/src/core/ext/filters/client_channel/lb_policy) PHP_ADD_BUILD_DIR($ext_builddir/src/core/ext/filters/client_channel/lb_policy/grpclb) PHP_ADD_BUILD_DIR($ext_builddir/src/core/ext/filters/client_channel/lb_policy/grpclb/proto/grpc/lb/v1) PHP_ADD_BUILD_DIR($ext_builddir/src/core/ext/filters/client_channel/lb_policy/pick_first) diff --git a/config.w32 b/config.w32 index 35355826995..3feb06d1a39 100644 --- a/config.w32 +++ b/config.w32 @@ -294,6 +294,7 @@ if (PHP_GRPC != "no") { "third_party\\nanopb\\pb_encode.c " + "src\\core\\ext\\filters\\client_channel\\resolver\\fake\\fake_resolver.cc " + "src\\core\\ext\\filters\\client_channel\\lb_policy\\pick_first\\pick_first.cc " + + "src\\core\\ext\\filters\\client_channel\\lb_policy\\subchannel_list.cc " + "src\\core\\ext\\filters\\client_channel\\lb_policy\\round_robin\\round_robin.cc " + "src\\core\\ext\\filters\\client_channel\\resolver\\dns\\c_ares\\dns_resolver_ares.cc " + "src\\core\\ext\\filters\\client_channel\\resolver\\dns\\c_ares\\grpc_ares_ev_driver_posix.cc " + diff --git a/gRPC-Core.podspec b/gRPC-Core.podspec index ca5301aa102..0a91809e094 100644 --- a/gRPC-Core.podspec +++ b/gRPC-Core.podspec @@ -434,6 +434,7 @@ Pod::Spec.new do |s| 'src/core/ext/filters/client_channel/lb_policy/grpclb/load_balancer_api.h', 'src/core/ext/filters/client_channel/lb_policy/grpclb/proto/grpc/lb/v1/load_balancer.pb.h', 'src/core/ext/filters/client_channel/resolver/fake/fake_resolver.h', + 'src/core/ext/filters/client_channel/lb_policy/subchannel_list.h', 'src/core/ext/filters/client_channel/resolver/dns/c_ares/grpc_ares_ev_driver.h', 'src/core/ext/filters/client_channel/resolver/dns/c_ares/grpc_ares_wrapper.h', 'src/core/ext/filters/load_reporting/server_load_reporting_filter.h', @@ -689,6 +690,7 @@ Pod::Spec.new do |s| 'src/core/ext/filters/client_channel/lb_policy/grpclb/proto/grpc/lb/v1/load_balancer.pb.c', 'src/core/ext/filters/client_channel/resolver/fake/fake_resolver.cc', 'src/core/ext/filters/client_channel/lb_policy/pick_first/pick_first.cc', + 'src/core/ext/filters/client_channel/lb_policy/subchannel_list.cc', 'src/core/ext/filters/client_channel/lb_policy/round_robin/round_robin.cc', 'src/core/ext/filters/client_channel/resolver/dns/c_ares/dns_resolver_ares.cc', 'src/core/ext/filters/client_channel/resolver/dns/c_ares/grpc_ares_ev_driver_posix.cc', @@ -933,6 +935,7 @@ Pod::Spec.new do |s| 'src/core/ext/filters/client_channel/lb_policy/grpclb/load_balancer_api.h', 'src/core/ext/filters/client_channel/lb_policy/grpclb/proto/grpc/lb/v1/load_balancer.pb.h', 'src/core/ext/filters/client_channel/resolver/fake/fake_resolver.h', + 'src/core/ext/filters/client_channel/lb_policy/subchannel_list.h', 'src/core/ext/filters/client_channel/resolver/dns/c_ares/grpc_ares_ev_driver.h', 'src/core/ext/filters/client_channel/resolver/dns/c_ares/grpc_ares_wrapper.h', 'src/core/ext/filters/load_reporting/server_load_reporting_filter.h', diff --git a/grpc.gemspec b/grpc.gemspec index c37859f3d17..0c0473cacf7 100644 --- a/grpc.gemspec +++ b/grpc.gemspec @@ -381,6 +381,7 @@ Gem::Specification.new do |s| s.files += %w( third_party/nanopb/pb_decode.h ) s.files += %w( third_party/nanopb/pb_encode.h ) s.files += %w( src/core/ext/filters/client_channel/resolver/fake/fake_resolver.h ) + s.files += %w( src/core/ext/filters/client_channel/lb_policy/subchannel_list.h ) s.files += %w( src/core/ext/filters/client_channel/resolver/dns/c_ares/grpc_ares_ev_driver.h ) s.files += %w( src/core/ext/filters/client_channel/resolver/dns/c_ares/grpc_ares_wrapper.h ) s.files += %w( src/core/ext/filters/load_reporting/server_load_reporting_filter.h ) @@ -639,6 +640,7 @@ Gem::Specification.new do |s| s.files += %w( third_party/nanopb/pb_encode.c ) s.files += %w( src/core/ext/filters/client_channel/resolver/fake/fake_resolver.cc ) s.files += %w( src/core/ext/filters/client_channel/lb_policy/pick_first/pick_first.cc ) + s.files += %w( src/core/ext/filters/client_channel/lb_policy/subchannel_list.cc ) s.files += %w( src/core/ext/filters/client_channel/lb_policy/round_robin/round_robin.cc ) s.files += %w( src/core/ext/filters/client_channel/resolver/dns/c_ares/dns_resolver_ares.cc ) s.files += %w( src/core/ext/filters/client_channel/resolver/dns/c_ares/grpc_ares_ev_driver_posix.cc ) diff --git a/grpc.gyp b/grpc.gyp index 5579f0298a7..9bf33f958b5 100644 --- a/grpc.gyp +++ b/grpc.gyp @@ -455,6 +455,7 @@ 'third_party/nanopb/pb_encode.c', 'src/core/ext/filters/client_channel/resolver/fake/fake_resolver.cc', 'src/core/ext/filters/client_channel/lb_policy/pick_first/pick_first.cc', + 'src/core/ext/filters/client_channel/lb_policy/subchannel_list.cc', 'src/core/ext/filters/client_channel/lb_policy/round_robin/round_robin.cc', 'src/core/ext/filters/client_channel/resolver/dns/c_ares/dns_resolver_ares.cc', 'src/core/ext/filters/client_channel/resolver/dns/c_ares/grpc_ares_ev_driver_posix.cc', @@ -1129,6 +1130,7 @@ 'third_party/nanopb/pb_decode.c', 'third_party/nanopb/pb_encode.c', 'src/core/ext/filters/client_channel/lb_policy/pick_first/pick_first.cc', + 'src/core/ext/filters/client_channel/lb_policy/subchannel_list.cc', 'src/core/ext/filters/client_channel/lb_policy/round_robin/round_robin.cc', 'src/core/ext/census/base_resources.cc', 'src/core/ext/census/context.cc', diff --git a/package.xml b/package.xml index 36206890f18..f4e7fef72cf 100644 --- a/package.xml +++ b/package.xml @@ -393,6 +393,7 @@ + @@ -651,6 +652,7 @@ + diff --git a/src/core/ext/filters/client_channel/lb_policy/pick_first/pick_first.cc b/src/core/ext/filters/client_channel/lb_policy/pick_first/pick_first.cc index b07fc3b720b..bbf05484052 100644 --- a/src/core/ext/filters/client_channel/lb_policy/pick_first/pick_first.cc +++ b/src/core/ext/filters/client_channel/lb_policy/pick_first/pick_first.cc @@ -20,6 +20,7 @@ #include +#include "src/core/ext/filters/client_channel/lb_policy/subchannel_list.h" #include "src/core/ext/filters/client_channel/lb_policy_registry.h" #include "src/core/ext/filters/client_channel/subchannel.h" #include "src/core/ext/filters/client_channel/subchannel_index.h" @@ -42,99 +43,73 @@ typedef struct { /** base policy: must be first */ grpc_lb_policy base; /** all our subchannels */ - grpc_subchannel **subchannels; - grpc_subchannel **new_subchannels; - size_t num_subchannels; - size_t num_new_subchannels; - - grpc_closure connectivity_changed; - - /** remaining members are protected by the combiner */ - - /** the selected channel */ - grpc_connected_subchannel *selected; - - /** the subchannel key for \a selected, or NULL if \a selected not set */ - const grpc_subchannel_key *selected_key; - + grpc_lb_subchannel_list *subchannel_list; + /** Latest pending subchannel list. */ + grpc_lb_subchannel_list *latest_pending_subchannel_list; + /** Selected subchannel in \a subchannel_list. */ + grpc_lb_subchannel_data *selected; /** have we started picking? */ bool started_picking; /** are we shut down? */ bool shutdown; - /** are we updating the selected subchannel? */ - bool updating_selected; - /** are we updating the subchannel candidates? */ - bool updating_subchannels; - /** args from the latest update received while already updating, or NULL */ - grpc_lb_policy_args *pending_update_args; - /** which subchannel are we watching? */ - size_t checking_subchannel; - /** what is the connectivity of that channel? */ - grpc_connectivity_state checking_connectivity; /** list of picks that are waiting on connectivity */ pending_pick *pending_picks; - /** our connectivity state tracker */ grpc_connectivity_state_tracker state_tracker; } pick_first_lb_policy; static void pf_destroy(grpc_exec_ctx *exec_ctx, grpc_lb_policy *pol) { pick_first_lb_policy *p = (pick_first_lb_policy *)pol; + GPR_ASSERT(p->subchannel_list == NULL); + GPR_ASSERT(p->latest_pending_subchannel_list == NULL); GPR_ASSERT(p->pending_picks == NULL); - for (size_t i = 0; i < p->num_subchannels; i++) { - GRPC_SUBCHANNEL_UNREF(exec_ctx, p->subchannels[i], "pick_first_destroy"); - } - if (p->selected != NULL) { - GRPC_CONNECTED_SUBCHANNEL_UNREF(exec_ctx, p->selected, - "picked_first_destroy"); - } grpc_connectivity_state_destroy(exec_ctx, &p->state_tracker); - grpc_subchannel_index_unref(); - if (p->pending_update_args != NULL) { - grpc_channel_args_destroy(exec_ctx, p->pending_update_args->args); - gpr_free(p->pending_update_args); - } - gpr_free(p->subchannels); - gpr_free(p->new_subchannels); gpr_free(p); + grpc_subchannel_index_unref(); if (GRPC_TRACER_ON(grpc_lb_pick_first_trace)) { gpr_log(GPR_DEBUG, "Pick First %p destroyed.", (void *)p); } } -static void pf_shutdown_locked(grpc_exec_ctx *exec_ctx, grpc_lb_policy *pol) { - pick_first_lb_policy *p = (pick_first_lb_policy *)pol; - pending_pick *pp; +static void shutdown_locked(grpc_exec_ctx *exec_ctx, pick_first_lb_policy *p, + grpc_error *error) { + if (GRPC_TRACER_ON(grpc_lb_pick_first_trace)) { + gpr_log(GPR_DEBUG, "Pick First %p Shutting down", p); + } p->shutdown = true; - pp = p->pending_picks; - p->pending_picks = NULL; + pending_pick *pp; + while ((pp = p->pending_picks) != NULL) { + p->pending_picks = pp->next; + *pp->target = NULL; + GRPC_CLOSURE_SCHED(exec_ctx, pp->on_complete, GRPC_ERROR_REF(error)); + gpr_free(pp); + } grpc_connectivity_state_set( exec_ctx, &p->state_tracker, GRPC_CHANNEL_SHUTDOWN, - GRPC_ERROR_CREATE_FROM_STATIC_STRING("Channel shutdown"), "shutdown"); - /* cancel subscription */ - if (p->selected != NULL) { - grpc_connected_subchannel_notify_on_state_change( - exec_ctx, p->selected, NULL, NULL, &p->connectivity_changed); - } else if (p->num_subchannels > 0 && p->started_picking) { - grpc_subchannel_notify_on_state_change( - exec_ctx, p->subchannels[p->checking_subchannel], NULL, NULL, - &p->connectivity_changed); + GRPC_ERROR_REF(error), "shutdown"); + if (p->subchannel_list != NULL) { + grpc_lb_subchannel_list_shutdown_and_unref(exec_ctx, p->subchannel_list, + "pf_shutdown"); + p->subchannel_list = NULL; } - while (pp != NULL) { - pending_pick *next = pp->next; - *pp->target = NULL; - GRPC_CLOSURE_SCHED(exec_ctx, pp->on_complete, GRPC_ERROR_NONE); - gpr_free(pp); - pp = next; + if (p->latest_pending_subchannel_list != NULL) { + grpc_lb_subchannel_list_shutdown_and_unref( + exec_ctx, p->latest_pending_subchannel_list, "pf_shutdown"); + p->latest_pending_subchannel_list = NULL; } + GRPC_ERROR_UNREF(error); +} + +static void pf_shutdown_locked(grpc_exec_ctx *exec_ctx, grpc_lb_policy *pol) { + shutdown_locked(exec_ctx, (pick_first_lb_policy *)pol, + GRPC_ERROR_CREATE_FROM_STATIC_STRING("Channel shutdown")); } static void pf_cancel_pick_locked(grpc_exec_ctx *exec_ctx, grpc_lb_policy *pol, grpc_connected_subchannel **target, grpc_error *error) { pick_first_lb_policy *p = (pick_first_lb_policy *)pol; - pending_pick *pp; - pp = p->pending_picks; + pending_pick *pp = p->pending_picks; p->pending_picks = NULL; while (pp != NULL) { pending_pick *next = pp->next; @@ -158,8 +133,7 @@ static void pf_cancel_picks_locked(grpc_exec_ctx *exec_ctx, grpc_lb_policy *pol, uint32_t initial_metadata_flags_eq, grpc_error *error) { pick_first_lb_policy *p = (pick_first_lb_policy *)pol; - pending_pick *pp; - pp = p->pending_picks; + pending_pick *pp = p->pending_picks; p->pending_picks = NULL; while (pp != NULL) { pending_pick *next = pp->next; @@ -181,15 +155,12 @@ static void pf_cancel_picks_locked(grpc_exec_ctx *exec_ctx, grpc_lb_policy *pol, static void start_picking_locked(grpc_exec_ctx *exec_ctx, pick_first_lb_policy *p) { p->started_picking = true; - if (p->subchannels != NULL) { - GPR_ASSERT(p->num_subchannels > 0); - p->checking_subchannel = 0; - p->checking_connectivity = GRPC_CHANNEL_IDLE; - GRPC_LB_POLICY_WEAK_REF(&p->base, "pick_first_connectivity"); - grpc_subchannel_notify_on_state_change( - exec_ctx, p->subchannels[p->checking_subchannel], - p->base.interested_parties, &p->checking_connectivity, - &p->connectivity_changed); + if (p->subchannel_list != NULL && p->subchannel_list->num_subchannels > 0) { + p->subchannel_list->checking_subchannel = 0; + grpc_lb_subchannel_list_ref_for_connectivity_watch( + p->subchannel_list, "connectivity_watch+start_picking"); + grpc_lb_subchannel_data_start_connectivity_watch( + exec_ctx, &p->subchannel_list->subchannels[0]); } } @@ -206,19 +177,17 @@ static int pf_pick_locked(grpc_exec_ctx *exec_ctx, grpc_lb_policy *pol, grpc_call_context_element *context, void **user_data, grpc_closure *on_complete) { pick_first_lb_policy *p = (pick_first_lb_policy *)pol; - pending_pick *pp; - - /* Check atomically for a selected channel */ + // If we have a selected subchannel already, return synchronously. if (p->selected != NULL) { - *target = GRPC_CONNECTED_SUBCHANNEL_REF(p->selected, "picked"); + *target = GRPC_CONNECTED_SUBCHANNEL_REF(p->selected->connected_subchannel, + "picked"); return 1; } - - /* No subchannel selected yet, so try again */ + // No subchannel selected yet, so handle asynchronously. if (!p->started_picking) { start_picking_locked(exec_ctx, p); } - pp = (pending_pick *)gpr_malloc(sizeof(*pp)); + pending_pick *pp = (pending_pick *)gpr_malloc(sizeof(*pp)); pp->next = p->pending_picks; pp->target = target; pp->initial_metadata_flags = pick_args->initial_metadata_flags; @@ -227,19 +196,15 @@ static int pf_pick_locked(grpc_exec_ctx *exec_ctx, grpc_lb_policy *pol, return 0; } -static void destroy_subchannels_locked(grpc_exec_ctx *exec_ctx, - pick_first_lb_policy *p) { - size_t num_subchannels = p->num_subchannels; - grpc_subchannel **subchannels = p->subchannels; - - p->num_subchannels = 0; - p->subchannels = NULL; - GRPC_LB_POLICY_WEAK_UNREF(exec_ctx, &p->base, "destroy_subchannels"); - - for (size_t i = 0; i < num_subchannels; i++) { - GRPC_SUBCHANNEL_UNREF(exec_ctx, subchannels[i], "pick_first"); +static void destroy_unselected_subchannels_locked(grpc_exec_ctx *exec_ctx, + pick_first_lb_policy *p) { + for (size_t i = 0; i < p->subchannel_list->num_subchannels; ++i) { + grpc_lb_subchannel_data *sd = &p->subchannel_list->subchannels[i]; + if (p->selected != sd) { + grpc_lb_subchannel_data_unref_subchannel(exec_ctx, sd, + "selected_different_subchannel"); + } } - gpr_free(subchannels); } static grpc_connectivity_state pf_check_connectivity_locked( @@ -261,46 +226,24 @@ static void pf_ping_one_locked(grpc_exec_ctx *exec_ctx, grpc_lb_policy *pol, grpc_closure *closure) { pick_first_lb_policy *p = (pick_first_lb_policy *)pol; if (p->selected) { - grpc_connected_subchannel_ping(exec_ctx, p->selected, closure); + grpc_connected_subchannel_ping(exec_ctx, p->selected->connected_subchannel, + closure); } else { GRPC_CLOSURE_SCHED(exec_ctx, closure, GRPC_ERROR_CREATE_FROM_STATIC_STRING("Not connected")); } } -/* unsubscribe all subchannels */ -static void stop_connectivity_watchers(grpc_exec_ctx *exec_ctx, - pick_first_lb_policy *p) { - if (p->num_subchannels > 0) { - GPR_ASSERT(p->selected == NULL); - if (GRPC_TRACER_ON(grpc_lb_pick_first_trace)) { - gpr_log(GPR_DEBUG, "Pick First %p unsubscribing from subchannel %p", - (void *)p, (void *)p->subchannels[p->checking_subchannel]); - } - grpc_subchannel_notify_on_state_change( - exec_ctx, p->subchannels[p->checking_subchannel], NULL, NULL, - &p->connectivity_changed); - p->updating_subchannels = true; - } else if (p->selected != NULL) { - if (GRPC_TRACER_ON(grpc_lb_pick_first_trace)) { - gpr_log(GPR_DEBUG, - "Pick First %p unsubscribing from selected subchannel %p", - (void *)p, (void *)p->selected); - } - grpc_connected_subchannel_notify_on_state_change( - exec_ctx, p->selected, NULL, NULL, &p->connectivity_changed); - p->updating_selected = true; - } -} +static void pf_connectivity_changed_locked(grpc_exec_ctx *exec_ctx, void *arg, + grpc_error *error); -/* true upon success */ static void pf_update_locked(grpc_exec_ctx *exec_ctx, grpc_lb_policy *policy, const grpc_lb_policy_args *args) { pick_first_lb_policy *p = (pick_first_lb_policy *)policy; const grpc_arg *arg = grpc_channel_args_find(args->args, GRPC_ARG_LB_ADDRESSES); if (arg == NULL || arg->type != GRPC_ARG_POINTER) { - if (p->subchannels == NULL) { + if (p->subchannel_list == NULL) { // If we don't have a current subchannel list, go into TRANSIENT FAILURE. grpc_connectivity_state_set( exec_ctx, &p->state_tracker, GRPC_CHANNEL_TRANSIENT_FAILURE, @@ -317,270 +260,228 @@ static void pf_update_locked(grpc_exec_ctx *exec_ctx, grpc_lb_policy *policy, } const grpc_lb_addresses *addresses = (const grpc_lb_addresses *)arg->value.pointer.p; - if (addresses->num_addresses == 0) { - // Empty update. Unsubscribe from all current subchannels and put the - // channel in TRANSIENT_FAILURE. + if (GRPC_TRACER_ON(grpc_lb_pick_first_trace)) { + gpr_log(GPR_INFO, "Pick First %p received update with %lu addresses", + (void *)p, (unsigned long)addresses->num_addresses); + } + grpc_lb_subchannel_list *subchannel_list = grpc_lb_subchannel_list_create( + exec_ctx, &p->base, addresses, args, pf_connectivity_changed_locked); + if (subchannel_list->num_subchannels == 0) { + // Empty update or no valid subchannels. Unsubscribe from all current + // subchannels and put the channel in TRANSIENT_FAILURE. grpc_connectivity_state_set( exec_ctx, &p->state_tracker, GRPC_CHANNEL_TRANSIENT_FAILURE, GRPC_ERROR_CREATE_FROM_STATIC_STRING("Empty update"), "pf_update_empty"); - stop_connectivity_watchers(exec_ctx, p); + if (p->subchannel_list != NULL) { + grpc_lb_subchannel_list_shutdown_and_unref(exec_ctx, p->subchannel_list, + "sl_shutdown_empty_update"); + } + p->subchannel_list = subchannel_list; // Empty list. + p->selected = NULL; return; } - if (GRPC_TRACER_ON(grpc_lb_pick_first_trace)) { - gpr_log(GPR_INFO, "Pick First %p received update with %lu addresses", - (void *)p, (unsigned long)addresses->num_addresses); - } - grpc_subchannel_args *sc_args = (grpc_subchannel_args *)gpr_zalloc( - sizeof(*sc_args) * addresses->num_addresses); - /* We remove the following keys in order for subchannel keys belonging to - * subchannels point to the same address to match. */ - static const char *keys_to_remove[] = {GRPC_ARG_SUBCHANNEL_ADDRESS, - GRPC_ARG_LB_ADDRESSES}; - size_t sc_args_count = 0; - - /* Create list of subchannel args for new addresses in \a args. */ - for (size_t i = 0; i < addresses->num_addresses; i++) { - // If there were any balancer, we would have chosen grpclb policy instead. - GPR_ASSERT(!addresses->addresses[i].is_balancer); - if (addresses->addresses[i].user_data != NULL) { - gpr_log(GPR_ERROR, - "This LB policy doesn't support user data. It will be ignored"); + if (p->selected == NULL) { + // We don't yet have a selected subchannel, so replace the current + // subchannel list immediately. + if (p->subchannel_list != NULL) { + grpc_lb_subchannel_list_shutdown_and_unref( + exec_ctx, p->subchannel_list, "pf_update_before_selected"); } - grpc_arg addr_arg = - grpc_create_subchannel_address_arg(&addresses->addresses[i].address); - grpc_channel_args *new_args = grpc_channel_args_copy_and_add_and_remove( - args->args, keys_to_remove, GPR_ARRAY_SIZE(keys_to_remove), &addr_arg, - 1); - gpr_free(addr_arg.value.string); - sc_args[sc_args_count++].args = new_args; - } - - /* Check if p->selected is amongst them. If so, we are done. */ - if (p->selected != NULL) { - GPR_ASSERT(p->selected_key != NULL); - for (size_t i = 0; i < sc_args_count; i++) { - grpc_subchannel_key *ith_sc_key = grpc_subchannel_key_create(&sc_args[i]); - const bool found_selected = - grpc_subchannel_key_compare(p->selected_key, ith_sc_key) == 0; - grpc_subchannel_key_destroy(exec_ctx, ith_sc_key); - if (found_selected) { + p->subchannel_list = subchannel_list; + } else { + // We do have a selected subchannel. + // Check if it's present in the new list. If so, we're done. + for (size_t i = 0; i < subchannel_list->num_subchannels; ++i) { + grpc_lb_subchannel_data *sd = &subchannel_list->subchannels[i]; + if (sd->subchannel == p->selected->subchannel) { // The currently selected subchannel is in the update: we are done. if (GRPC_TRACER_ON(grpc_lb_pick_first_trace)) { gpr_log(GPR_INFO, - "Pick First %p found already selected subchannel %p amongst " - "updates. Update done.", - (void *)p, (void *)p->selected); + "Pick First %p found already selected subchannel %p " + "at update index %" PRIdPTR " of %" PRIdPTR "; update done", + p, p->selected->subchannel, i, + subchannel_list->num_subchannels); + } + grpc_lb_subchannel_list_ref_for_connectivity_watch( + subchannel_list, "connectivity_watch+replace_selected"); + grpc_lb_subchannel_data_start_connectivity_watch(exec_ctx, sd); + if (p->subchannel_list != NULL) { + grpc_lb_subchannel_list_shutdown_and_unref( + exec_ctx, p->subchannel_list, "pf_update_includes_selected"); + } + p->subchannel_list = subchannel_list; + if (p->selected->connected_subchannel != NULL) { + sd->connected_subchannel = GRPC_CONNECTED_SUBCHANNEL_REF( + grpc_subchannel_get_connected_subchannel(sd->subchannel), + "pf_update_includes_selected"); } - for (size_t j = 0; j < sc_args_count; j++) { - grpc_channel_args_destroy(exec_ctx, - (grpc_channel_args *)sc_args[j].args); + p->selected = sd; + destroy_unselected_subchannels_locked(exec_ctx, p); + // If there was a previously pending update (which may or may + // not have contained the currently selected subchannel), drop + // it, so that it doesn't override what we've done here. + if (p->latest_pending_subchannel_list != NULL) { + grpc_lb_subchannel_list_shutdown_and_unref( + exec_ctx, p->latest_pending_subchannel_list, + "pf_update_includes_selected+outdated"); + p->latest_pending_subchannel_list = NULL; } - gpr_free(sc_args); return; } } - } - // We only check for already running updates here because if the previous - // steps were successful, the update can be considered done without any - // interference (ie, no callbacks were scheduled). - if (p->updating_selected || p->updating_subchannels) { - if (GRPC_TRACER_ON(grpc_lb_pick_first_trace)) { - gpr_log(GPR_INFO, - "Update already in progress for pick first %p. Deferring update.", - (void *)p); - } - if (p->pending_update_args != NULL) { - grpc_channel_args_destroy(exec_ctx, p->pending_update_args->args); - gpr_free(p->pending_update_args); - } - p->pending_update_args = - (grpc_lb_policy_args *)gpr_zalloc(sizeof(*p->pending_update_args)); - p->pending_update_args->client_channel_factory = - args->client_channel_factory; - p->pending_update_args->args = grpc_channel_args_copy(args->args); - p->pending_update_args->combiner = args->combiner; - return; - } - /* Create the subchannels for the new subchannel args/addresses. */ - grpc_subchannel **new_subchannels = - (grpc_subchannel **)gpr_zalloc(sizeof(*new_subchannels) * sc_args_count); - size_t num_new_subchannels = 0; - for (size_t i = 0; i < sc_args_count; i++) { - grpc_subchannel *subchannel = grpc_client_channel_factory_create_subchannel( - exec_ctx, args->client_channel_factory, &sc_args[i]); - if (GRPC_TRACER_ON(grpc_lb_pick_first_trace)) { - char *address_uri = - grpc_sockaddr_to_uri(&addresses->addresses[i].address); - gpr_log(GPR_INFO, - "Pick First %p created subchannel %p for address uri %s", - (void *)p, (void *)subchannel, address_uri); - gpr_free(address_uri); + // Not keeping the previous selected subchannel, so set the latest + // pending subchannel list to the new subchannel list. We will wait + // for it to report READY before swapping it into the current + // subchannel list. + if (p->latest_pending_subchannel_list != NULL) { + if (GRPC_TRACER_ON(grpc_lb_pick_first_trace)) { + gpr_log(GPR_DEBUG, + "Pick First %p Shutting down latest pending subchannel list " + "%p, about to be replaced by newer latest %p", + (void *)p, (void *)p->latest_pending_subchannel_list, + (void *)subchannel_list); + } + grpc_lb_subchannel_list_shutdown_and_unref( + exec_ctx, p->latest_pending_subchannel_list, + "sl_outdated_dont_smash"); } - grpc_channel_args_destroy(exec_ctx, (grpc_channel_args *)sc_args[i].args); - if (subchannel != NULL) new_subchannels[num_new_subchannels++] = subchannel; + p->latest_pending_subchannel_list = subchannel_list; } - gpr_free(sc_args); - if (num_new_subchannels == 0) { - gpr_free(new_subchannels); - // Empty update. Unsubscribe from all current subchannels and put the - // channel in TRANSIENT_FAILURE. - grpc_connectivity_state_set( - exec_ctx, &p->state_tracker, GRPC_CHANNEL_TRANSIENT_FAILURE, - GRPC_ERROR_CREATE_FROM_STATIC_STRING("No valid addresses in update"), - "pf_update_no_valid_addresses"); - stop_connectivity_watchers(exec_ctx, p); - return; - } - - /* Destroy the current subchannels. Repurpose pf_shutdown/destroy. */ - stop_connectivity_watchers(exec_ctx, p); - - /* Save new subchannels. The switch over will happen in - * pf_connectivity_changed_locked */ - if (p->updating_selected || p->updating_subchannels) { - p->num_new_subchannels = num_new_subchannels; - p->new_subchannels = new_subchannels; - } else { /* nothing is updating. Get things moving from here */ - p->num_subchannels = num_new_subchannels; - p->subchannels = new_subchannels; - p->new_subchannels = NULL; - p->num_new_subchannels = 0; - if (p->started_picking) { - p->checking_subchannel = 0; - p->checking_connectivity = GRPC_CHANNEL_IDLE; - grpc_subchannel_notify_on_state_change( - exec_ctx, p->subchannels[p->checking_subchannel], - p->base.interested_parties, &p->checking_connectivity, - &p->connectivity_changed); - } + // If we've started picking, start trying to connect to the first + // subchannel in the new list. + if (p->started_picking && subchannel_list->num_subchannels > 0) { + grpc_lb_subchannel_list_ref_for_connectivity_watch( + subchannel_list, "connectivity_watch+update"); + grpc_lb_subchannel_data_start_connectivity_watch( + exec_ctx, &subchannel_list->subchannels[0]); } } static void pf_connectivity_changed_locked(grpc_exec_ctx *exec_ctx, void *arg, grpc_error *error) { - pick_first_lb_policy *p = (pick_first_lb_policy *)arg; - grpc_subchannel *selected_subchannel; - pending_pick *pp; - + grpc_lb_subchannel_data *sd = (grpc_lb_subchannel_data *)arg; + pick_first_lb_policy *p = (pick_first_lb_policy *)sd->subchannel_list->policy; if (GRPC_TRACER_ON(grpc_lb_pick_first_trace)) { gpr_log( GPR_DEBUG, - "Pick First %p connectivity changed. Updating selected: %d; Updating " - "subchannels: %d; Checking %lu index (%lu total); State: %d; ", - (void *)p, p->updating_selected, p->updating_subchannels, - (unsigned long)p->checking_subchannel, - (unsigned long)p->num_subchannels, p->checking_connectivity); - } - bool restart = false; - if (p->updating_selected && error != GRPC_ERROR_NONE) { - /* Captured the unsubscription for p->selected */ - GPR_ASSERT(p->selected != NULL); - GRPC_CONNECTED_SUBCHANNEL_UNREF(exec_ctx, p->selected, - "pf_update_connectivity"); - if (GRPC_TRACER_ON(grpc_lb_pick_first_trace)) { - gpr_log(GPR_DEBUG, "Pick First %p unreffing selected subchannel %p", - (void *)p, (void *)p->selected); - } - p->updating_selected = false; - if (p->num_new_subchannels == 0) { - p->selected = NULL; - return; - } - restart = true; - } - if (p->updating_subchannels && error != GRPC_ERROR_NONE) { - /* Captured the unsubscription for the checking subchannel */ - GPR_ASSERT(p->selected == NULL); - for (size_t i = 0; i < p->num_subchannels; i++) { - GRPC_SUBCHANNEL_UNREF(exec_ctx, p->subchannels[i], - "pf_update_connectivity"); - if (GRPC_TRACER_ON(grpc_lb_pick_first_trace)) { - gpr_log(GPR_DEBUG, "Pick First %p unreffing subchannel %p", (void *)p, - (void *)p->subchannels[i]); - } - } - gpr_free(p->subchannels); - p->subchannels = NULL; - p->num_subchannels = 0; - p->updating_subchannels = false; - if (p->num_new_subchannels == 0) return; - restart = true; + "Pick First %p connectivity changed for subchannel %p (%" PRIdPTR + " of %" PRIdPTR "), subchannel_list %p: state=%s p->shutdown=%d " + "sd->subchannel_list->shutting_down=%d error=%s", + (void *)p, (void *)sd->subchannel, + p->subchannel_list->checking_subchannel, + sd->subchannel_list->num_subchannels, (void *)sd->subchannel_list, + grpc_connectivity_state_name(sd->pending_connectivity_state_unsafe), + p->shutdown, sd->subchannel_list->shutting_down, + grpc_error_string(error)); } - if (restart) { - p->selected = NULL; - p->selected_key = NULL; - GPR_ASSERT(p->new_subchannels != NULL); - GPR_ASSERT(p->num_new_subchannels > 0); - p->num_subchannels = p->num_new_subchannels; - p->subchannels = p->new_subchannels; - p->num_new_subchannels = 0; - p->new_subchannels = NULL; - if (p->started_picking) { - /* If we were picking, continue to do so over the new subchannels, - * starting from the 0th index. */ - p->checking_subchannel = 0; - p->checking_connectivity = GRPC_CHANNEL_IDLE; - /* reuses the weak ref from start_picking_locked */ - grpc_subchannel_notify_on_state_change( - exec_ctx, p->subchannels[p->checking_subchannel], - p->base.interested_parties, &p->checking_connectivity, - &p->connectivity_changed); - } - if (p->pending_update_args != NULL) { - const grpc_lb_policy_args *args = p->pending_update_args; - p->pending_update_args = NULL; - pf_update_locked(exec_ctx, &p->base, args); - } + // If the policy is shutting down, unref and return. + if (p->shutdown) { + grpc_lb_subchannel_data_stop_connectivity_watch(exec_ctx, sd); + grpc_lb_subchannel_data_unref_subchannel(exec_ctx, sd, "pf_shutdown"); + grpc_lb_subchannel_list_unref_for_connectivity_watch( + exec_ctx, sd->subchannel_list, "pf_shutdown"); return; } - GRPC_ERROR_REF(error); - if (p->shutdown) { - GRPC_LB_POLICY_WEAK_UNREF(exec_ctx, &p->base, "pick_first_connectivity"); - GRPC_ERROR_UNREF(error); + // If the subchannel list is shutting down, stop watching. + if (sd->subchannel_list->shutting_down || error == GRPC_ERROR_CANCELLED) { + grpc_lb_subchannel_data_stop_connectivity_watch(exec_ctx, sd); + grpc_lb_subchannel_data_unref_subchannel(exec_ctx, sd, "pf_sl_shutdown"); + grpc_lb_subchannel_list_unref_for_connectivity_watch( + exec_ctx, sd->subchannel_list, "pf_sl_shutdown"); return; - } else if (p->selected != NULL) { - if (p->checking_connectivity == GRPC_CHANNEL_TRANSIENT_FAILURE) { - /* if the selected channel goes bad, we're done */ - p->checking_connectivity = GRPC_CHANNEL_SHUTDOWN; - } - grpc_connectivity_state_set(exec_ctx, &p->state_tracker, - p->checking_connectivity, GRPC_ERROR_REF(error), - "selected_changed"); - if (p->checking_connectivity != GRPC_CHANNEL_SHUTDOWN) { - grpc_connected_subchannel_notify_on_state_change( - exec_ctx, p->selected, p->base.interested_parties, - &p->checking_connectivity, &p->connectivity_changed); + } + // If we're still here, the notification must be for a subchannel in + // either the current or latest pending subchannel lists. + GPR_ASSERT(sd->subchannel_list == p->subchannel_list || + sd->subchannel_list == p->latest_pending_subchannel_list); + // Update state counters. + sd->curr_connectivity_state = sd->pending_connectivity_state_unsafe; + if (sd->curr_connectivity_state == GRPC_CHANNEL_SHUTDOWN) { + ++sd->subchannel_list->num_shutdown; + } + sd->prev_connectivity_state = sd->curr_connectivity_state; + // Handle updates for the currently selected subchannel. + if (p->selected == sd) { + // If the new state is anything other than READY and there is a + // pending update, switch to the pending update. + if (sd->curr_connectivity_state != GRPC_CHANNEL_READY && + p->latest_pending_subchannel_list != NULL) { + p->selected = NULL; + grpc_lb_subchannel_list_shutdown_and_unref( + exec_ctx, p->subchannel_list, "selected_not_ready+switch_to_update"); + p->subchannel_list = p->latest_pending_subchannel_list; + p->latest_pending_subchannel_list = NULL; + grpc_lb_subchannel_data *new_sd = &p->subchannel_list->subchannels[ + p->subchannel_list->checking_subchannel]; + grpc_connectivity_state_set(exec_ctx, &p->state_tracker, + new_sd->curr_connectivity_state, + GRPC_ERROR_REF(error), + "selected_not_ready+switch_to_update"); } else { - GRPC_LB_POLICY_WEAK_UNREF(exec_ctx, &p->base, "pick_first_connectivity"); + if (sd->curr_connectivity_state == + GRPC_CHANNEL_TRANSIENT_FAILURE) { + /* if the selected channel goes bad, we're done */ + sd->curr_connectivity_state = GRPC_CHANNEL_SHUTDOWN; + } + grpc_connectivity_state_set(exec_ctx, &p->state_tracker, + sd->curr_connectivity_state, + GRPC_ERROR_REF(error), "selected_changed"); + if (sd->curr_connectivity_state != GRPC_CHANNEL_SHUTDOWN) { + // Renew notification. + grpc_lb_subchannel_data_start_connectivity_watch(exec_ctx, sd); + } else { + grpc_lb_subchannel_data_stop_connectivity_watch(exec_ctx, sd); + grpc_lb_subchannel_list_unref_for_connectivity_watch( + exec_ctx, sd->subchannel_list, "pf_selected_shutdown"); + pf_shutdown_locked(exec_ctx, &p->base); + } } - } else { - loop: - switch (p->checking_connectivity) { + return; + } + // If we get here, there are two possible cases: + // 1. We do not currently have a selected subchannel, and the update is + // for a subchannel in p->subchannel_list that we're trying to + // connect to. The goal here is to find a subchannel that we can + // select. + // 2. We do currently have a selected subchannel, and the update is + // for a subchannel in p->latest_pending_subchannel_list. The + // goal here is to find a subchannel from the update that we can + // select in place of the current one. + while (true) { + switch (sd->curr_connectivity_state) { case GRPC_CHANNEL_INIT: GPR_UNREACHABLE_CODE(return ); - case GRPC_CHANNEL_READY: + case GRPC_CHANNEL_READY: { + // Case 2. Promote p->latest_pending_subchannel_list to + // p->subchannel_list. + if (sd->subchannel_list == p->latest_pending_subchannel_list) { + GPR_ASSERT(p->subchannel_list != NULL); + grpc_lb_subchannel_list_shutdown_and_unref( + exec_ctx, p->subchannel_list, "finish_update"); + p->subchannel_list = p->latest_pending_subchannel_list; + p->latest_pending_subchannel_list = NULL; + } + // Cases 1 and 2. grpc_connectivity_state_set(exec_ctx, &p->state_tracker, GRPC_CHANNEL_READY, GRPC_ERROR_NONE, "connecting_ready"); - selected_subchannel = p->subchannels[p->checking_subchannel]; - p->selected = GRPC_CONNECTED_SUBCHANNEL_REF( - grpc_subchannel_get_connected_subchannel(selected_subchannel), - "picked_first"); - + sd->connected_subchannel = GRPC_CONNECTED_SUBCHANNEL_REF( + grpc_subchannel_get_connected_subchannel(sd->subchannel), + "connected"); + p->selected = sd; if (GRPC_TRACER_ON(grpc_lb_pick_first_trace)) { - gpr_log(GPR_INFO, - "Pick First %p selected subchannel %p (connected %p)", - (void *)p, (void *)selected_subchannel, (void *)p->selected); + gpr_log(GPR_INFO, "Pick First %p selected subchannel %p", + (void *)p, (void *)sd->subchannel); } - p->selected_key = grpc_subchannel_get_key(selected_subchannel); - /* drop the pick list: we are connected now */ - GRPC_LB_POLICY_WEAK_REF(&p->base, "destroy_subchannels"); - destroy_subchannels_locked(exec_ctx, p); - /* update any calls that were waiting for a pick */ + // Drop all other subchannels, since we are now connected. + destroy_unselected_subchannels_locked(exec_ctx, p); + // Update any calls that were waiting for a pick. + pending_pick *pp; while ((pp = p->pending_picks)) { p->pending_picks = pp->next; - *pp->target = GRPC_CONNECTED_SUBCHANNEL_REF(p->selected, "picked"); + *pp->target = GRPC_CONNECTED_SUBCHANNEL_REF( + p->selected->connected_subchannel, "picked"); if (GRPC_TRACER_ON(grpc_lb_pick_first_trace)) { gpr_log(GPR_INFO, "Servicing pending pick with selected subchannel %p", @@ -589,76 +490,82 @@ static void pf_connectivity_changed_locked(grpc_exec_ctx *exec_ctx, void *arg, GRPC_CLOSURE_SCHED(exec_ctx, pp->on_complete, GRPC_ERROR_NONE); gpr_free(pp); } - grpc_connected_subchannel_notify_on_state_change( - exec_ctx, p->selected, p->base.interested_parties, - &p->checking_connectivity, &p->connectivity_changed); - break; - case GRPC_CHANNEL_TRANSIENT_FAILURE: - p->checking_subchannel = - (p->checking_subchannel + 1) % p->num_subchannels; - if (p->checking_subchannel == 0) { - /* only trigger transient failure when we've tried all alternatives - */ + // Renew notification. + grpc_lb_subchannel_data_start_connectivity_watch(exec_ctx, sd); + return; + } + case GRPC_CHANNEL_TRANSIENT_FAILURE: { + grpc_lb_subchannel_data_stop_connectivity_watch(exec_ctx, sd); + sd->subchannel_list->checking_subchannel = + (sd->subchannel_list->checking_subchannel + 1) + % sd->subchannel_list->num_subchannels; + // Case 1: Only set state to TRANSIENT_FAILURE if we've tried + // all subchannels. + if (sd->subchannel_list->checking_subchannel == 0 && + sd->subchannel_list == p->subchannel_list) { grpc_connectivity_state_set( exec_ctx, &p->state_tracker, GRPC_CHANNEL_TRANSIENT_FAILURE, GRPC_ERROR_REF(error), "connecting_transient_failure"); } - GRPC_ERROR_UNREF(error); - p->checking_connectivity = grpc_subchannel_check_connectivity( - p->subchannels[p->checking_subchannel], &error); - if (p->checking_connectivity == GRPC_CHANNEL_TRANSIENT_FAILURE) { - grpc_subchannel_notify_on_state_change( - exec_ctx, p->subchannels[p->checking_subchannel], - p->base.interested_parties, &p->checking_connectivity, - &p->connectivity_changed); - } else { - goto loop; + sd = &sd->subchannel_list->subchannels[ + sd->subchannel_list->checking_subchannel]; + sd->curr_connectivity_state = + grpc_subchannel_check_connectivity(sd->subchannel, &error); + if (sd->curr_connectivity_state == GRPC_CHANNEL_TRANSIENT_FAILURE) { + // Reuses the connectivity refs from the previous watch. + grpc_lb_subchannel_data_start_connectivity_watch(exec_ctx, sd); + return; } - break; + break; // Go back to top of loop. + } case GRPC_CHANNEL_CONNECTING: - case GRPC_CHANNEL_IDLE: - grpc_connectivity_state_set( - exec_ctx, &p->state_tracker, GRPC_CHANNEL_CONNECTING, - GRPC_ERROR_REF(error), "connecting_changed"); - grpc_subchannel_notify_on_state_change( - exec_ctx, p->subchannels[p->checking_subchannel], - p->base.interested_parties, &p->checking_connectivity, - &p->connectivity_changed); - break; - case GRPC_CHANNEL_SHUTDOWN: - p->num_subchannels--; - GPR_SWAP(grpc_subchannel *, p->subchannels[p->checking_subchannel], - p->subchannels[p->num_subchannels]); - GRPC_SUBCHANNEL_UNREF(exec_ctx, p->subchannels[p->num_subchannels], - "pick_first"); - if (p->num_subchannels == 0) { + case GRPC_CHANNEL_IDLE: { + // Only update connectivity state in case 1. + if (sd->subchannel_list == p->subchannel_list) { grpc_connectivity_state_set( - exec_ctx, &p->state_tracker, GRPC_CHANNEL_SHUTDOWN, - GRPC_ERROR_CREATE_REFERENCING_FROM_STATIC_STRING( - "Pick first exhausted channels", &error, 1), - "no_more_channels"); - while ((pp = p->pending_picks)) { - p->pending_picks = pp->next; - *pp->target = NULL; - GRPC_CLOSURE_SCHED(exec_ctx, pp->on_complete, GRPC_ERROR_NONE); - gpr_free(pp); - } - GRPC_LB_POLICY_WEAK_UNREF(exec_ctx, &p->base, - "pick_first_connectivity"); - } else { + exec_ctx, &p->state_tracker, GRPC_CHANNEL_CONNECTING, + GRPC_ERROR_REF(error), "connecting_changed"); + } + // Renew notification. + grpc_lb_subchannel_data_start_connectivity_watch(exec_ctx, sd); + return; + } + case GRPC_CHANNEL_SHUTDOWN: { + grpc_lb_subchannel_data_stop_connectivity_watch(exec_ctx, sd); + grpc_lb_subchannel_data_unref_subchannel(exec_ctx, sd, + "pf_candidate_shutdown"); + if (sd->subchannel_list->num_shutdown == + sd->subchannel_list->num_subchannels) { + grpc_lb_subchannel_list_unref_for_connectivity_watch( + exec_ctx, sd->subchannel_list, "pf_candidate_shutdown"); + shutdown_locked(exec_ctx, p, + GRPC_ERROR_CREATE_REFERENCING_FROM_STATIC_STRING( + "Pick first exhausted channels", &error, 1)); + return; + } + if (sd->subchannel_list == p->subchannel_list) { grpc_connectivity_state_set( exec_ctx, &p->state_tracker, GRPC_CHANNEL_TRANSIENT_FAILURE, GRPC_ERROR_REF(error), "subchannel_failed"); - p->checking_subchannel %= p->num_subchannels; - GRPC_ERROR_UNREF(error); - p->checking_connectivity = grpc_subchannel_check_connectivity( - p->subchannels[p->checking_subchannel], &error); - goto loop; } + // Advance to next subchannel and check its state. + sd->subchannel_list->checking_subchannel = + (sd->subchannel_list->checking_subchannel + 1) + % sd->subchannel_list->num_subchannels; + sd = &sd->subchannel_list->subchannels[ + sd->subchannel_list->checking_subchannel]; + sd->curr_connectivity_state = + grpc_subchannel_check_connectivity(sd->subchannel, &error); + if (sd->curr_connectivity_state == GRPC_CHANNEL_TRANSIENT_FAILURE) { + // Reuses the connectivity refs from the previous watch. + grpc_lb_subchannel_data_start_connectivity_watch(exec_ctx, sd); + return; + } + // For any other state, go back to top of loop. + // We will reuse the connectivity refs from the previous watch. + } } } - - GRPC_ERROR_UNREF(error); } static const grpc_lb_policy_vtable pick_first_lb_policy_vtable = { @@ -688,8 +595,6 @@ static grpc_lb_policy *create_pick_first(grpc_exec_ctx *exec_ctx, pf_update_locked(exec_ctx, &p->base, args); grpc_lb_policy_init(&p->base, &pick_first_lb_policy_vtable, args->combiner); grpc_subchannel_index_ref(); - GRPC_CLOSURE_INIT(&p->connectivity_changed, pf_connectivity_changed_locked, p, - grpc_combiner_scheduler(args->combiner)); return &p->base; } diff --git a/src/core/ext/filters/client_channel/lb_policy/round_robin/round_robin.cc b/src/core/ext/filters/client_channel/lb_policy/round_robin/round_robin.cc index 6812bb50cd9..b25b9b86d88 100644 --- a/src/core/ext/filters/client_channel/lb_policy/round_robin/round_robin.cc +++ b/src/core/ext/filters/client_channel/lb_policy/round_robin/round_robin.cc @@ -28,6 +28,7 @@ #include +#include "src/core/ext/filters/client_channel/lb_policy/subchannel_list.h" #include "src/core/ext/filters/client_channel/lb_policy_registry.h" #include "src/core/ext/filters/client_channel/subchannel.h" #include "src/core/ext/filters/client_channel/subchannel_index.h" @@ -64,12 +65,11 @@ typedef struct pending_pick { grpc_closure *on_complete; } pending_pick; -typedef struct rr_subchannel_list rr_subchannel_list; typedef struct round_robin_lb_policy { /** base policy: must be first */ grpc_lb_policy base; - rr_subchannel_list *subchannel_list; + grpc_lb_subchannel_list *subchannel_list; /** have we started picking? */ bool started_picking; @@ -89,157 +89,9 @@ typedef struct round_robin_lb_policy { * lists if they equal \a latest_pending_subchannel_list. In other words, * racing callbacks that reference outdated subchannel lists won't perform any * update. */ - rr_subchannel_list *latest_pending_subchannel_list; + grpc_lb_subchannel_list *latest_pending_subchannel_list; } round_robin_lb_policy; -typedef struct { - /** backpointer to owning subchannel list */ - rr_subchannel_list *subchannel_list; - /** subchannel itself */ - grpc_subchannel *subchannel; - /** notification that connectivity has changed on subchannel */ - grpc_closure connectivity_changed_closure; - /** last observed connectivity. Not updated by - * \a grpc_subchannel_notify_on_state_change. Used to determine the previous - * state while processing the new state in \a rr_connectivity_changed */ - grpc_connectivity_state prev_connectivity_state; - /** current connectivity state. Updated by \a - * grpc_subchannel_notify_on_state_change */ - grpc_connectivity_state curr_connectivity_state; - /** connectivity state to be updated by the watcher, not guarded by - * the combiner. Will be moved to curr_connectivity_state inside of - * the combiner by rr_connectivity_changed_locked(). */ - grpc_connectivity_state pending_connectivity_state_unsafe; - /** the subchannel's target user data */ - void *user_data; - /** vtable to operate over \a user_data */ - const grpc_lb_user_data_vtable *user_data_vtable; -} subchannel_data; - -struct rr_subchannel_list { - /** backpointer to owning policy */ - round_robin_lb_policy *policy; - - /** all our subchannels */ - size_t num_subchannels; - subchannel_data *subchannels; - - /** how many subchannels are in state READY */ - size_t num_ready; - /** how many subchannels are in state TRANSIENT_FAILURE */ - size_t num_transient_failures; - /** how many subchannels are in state SHUTDOWN */ - size_t num_shutdown; - /** how many subchannels are in state IDLE */ - size_t num_idle; - - /** There will be one ref for each entry in subchannels for which there is a - * pending connectivity state watcher callback. */ - gpr_refcount refcount; - - /** Is this list shutting down? This may be true due to the shutdown of the - * policy itself or because a newer update has arrived while this one hadn't - * finished processing. */ - bool shutting_down; -}; - -static rr_subchannel_list *rr_subchannel_list_create(round_robin_lb_policy *p, - size_t num_subchannels) { - rr_subchannel_list *subchannel_list = - (rr_subchannel_list *)gpr_zalloc(sizeof(*subchannel_list)); - subchannel_list->policy = p; - subchannel_list->subchannels = - (subchannel_data *)gpr_zalloc(sizeof(subchannel_data) * num_subchannels); - subchannel_list->num_subchannels = num_subchannels; - gpr_ref_init(&subchannel_list->refcount, 1); - if (GRPC_TRACER_ON(grpc_lb_round_robin_trace)) { - gpr_log(GPR_INFO, "[RR %p] Created subchannel list %p for %lu subchannels", - (void *)p, (void *)subchannel_list, (unsigned long)num_subchannels); - } - return subchannel_list; -} - -static void rr_subchannel_list_destroy(grpc_exec_ctx *exec_ctx, - rr_subchannel_list *subchannel_list) { - GPR_ASSERT(subchannel_list->shutting_down); - if (GRPC_TRACER_ON(grpc_lb_round_robin_trace)) { - gpr_log(GPR_INFO, "[RR %p] Destroying subchannel_list %p", - (void *)subchannel_list->policy, (void *)subchannel_list); - } - for (size_t i = 0; i < subchannel_list->num_subchannels; i++) { - subchannel_data *sd = &subchannel_list->subchannels[i]; - if (sd->subchannel != NULL) { - GRPC_SUBCHANNEL_UNREF(exec_ctx, sd->subchannel, - "rr_subchannel_list_destroy"); - } - sd->subchannel = NULL; - if (sd->user_data != NULL) { - GPR_ASSERT(sd->user_data_vtable != NULL); - sd->user_data_vtable->destroy(exec_ctx, sd->user_data); - sd->user_data = NULL; - } - } - gpr_free(subchannel_list->subchannels); - gpr_free(subchannel_list); -} - -static void rr_subchannel_list_ref(rr_subchannel_list *subchannel_list, - const char *reason) { - gpr_ref_non_zero(&subchannel_list->refcount); - if (GRPC_TRACER_ON(grpc_lb_round_robin_trace)) { - const gpr_atm count = gpr_atm_acq_load(&subchannel_list->refcount.count); - gpr_log(GPR_INFO, "[RR %p] subchannel_list %p REF %lu->%lu (%s)", - (void *)subchannel_list->policy, (void *)subchannel_list, - (unsigned long)(count - 1), (unsigned long)count, reason); - } -} - -static void rr_subchannel_list_unref(grpc_exec_ctx *exec_ctx, - rr_subchannel_list *subchannel_list, - const char *reason) { - const bool done = gpr_unref(&subchannel_list->refcount); - if (GRPC_TRACER_ON(grpc_lb_round_robin_trace)) { - const gpr_atm count = gpr_atm_acq_load(&subchannel_list->refcount.count); - gpr_log(GPR_INFO, "[RR %p] subchannel_list %p UNREF %lu->%lu (%s)", - (void *)subchannel_list->policy, (void *)subchannel_list, - (unsigned long)(count + 1), (unsigned long)count, reason); - } - if (done) { - rr_subchannel_list_destroy(exec_ctx, subchannel_list); - } -} - -/** Mark \a subchannel_list as discarded. Unsubscribes all its subchannels. The - * watcher's callback will ultimately unref \a subchannel_list. */ -static void rr_subchannel_list_shutdown_and_unref( - grpc_exec_ctx *exec_ctx, rr_subchannel_list *subchannel_list, - const char *reason) { - GPR_ASSERT(!subchannel_list->shutting_down); - if (GRPC_TRACER_ON(grpc_lb_round_robin_trace)) { - gpr_log(GPR_DEBUG, "[RR %p] Shutting down subchannel_list %p (%s)", - (void *)subchannel_list->policy, (void *)subchannel_list, reason); - } - GPR_ASSERT(!subchannel_list->shutting_down); - subchannel_list->shutting_down = true; - for (size_t i = 0; i < subchannel_list->num_subchannels; i++) { - subchannel_data *sd = &subchannel_list->subchannels[i]; - if (sd->subchannel != NULL) { // if subchannel isn't shutdown, unsubscribe. - if (GRPC_TRACER_ON(grpc_lb_round_robin_trace)) { - gpr_log( - GPR_DEBUG, - "[RR %p] Unsubscribing from subchannel %p as part of shutting down " - "subchannel_list %p", - (void *)subchannel_list->policy, (void *)sd->subchannel, - (void *)subchannel_list); - } - grpc_subchannel_notify_on_state_change(exec_ctx, sd->subchannel, NULL, - NULL, - &sd->connectivity_changed_closure); - } - } - rr_subchannel_list_unref(exec_ctx, subchannel_list, reason); -} - /** Returns the index into p->subchannel_list->subchannels of the next * subchannel in READY state, or p->subchannel_list->num_subchannels if no * subchannel is READY. @@ -299,8 +151,8 @@ static void update_last_ready_subchannel_index_locked(round_robin_lb_policy *p, "[RR %p] setting last_ready_subchannel_index=%lu (SC %p, CSC %p)", (void *)p, (unsigned long)last_ready_index, (void *)p->subchannel_list->subchannels[last_ready_index].subchannel, - (void *)grpc_subchannel_get_connected_subchannel( - p->subchannel_list->subchannels[last_ready_index].subchannel)); + (void *)p->subchannel_list->subchannels[last_ready_index] + .connected_subchannel); } } @@ -310,17 +162,18 @@ static void rr_destroy(grpc_exec_ctx *exec_ctx, grpc_lb_policy *pol) { gpr_log(GPR_DEBUG, "[RR %p] Destroying Round Robin policy at %p", (void *)pol, (void *)pol); } + GPR_ASSERT(p->subchannel_list == NULL); + GPR_ASSERT(p->latest_pending_subchannel_list == NULL); grpc_connectivity_state_destroy(exec_ctx, &p->state_tracker); grpc_subchannel_index_unref(); gpr_free(p); } static void rr_shutdown_locked(grpc_exec_ctx *exec_ctx, grpc_lb_policy *pol) { - round_robin_lb_policy *p = (round_robin_lb_policy *)pol; if (GRPC_TRACER_ON(grpc_lb_round_robin_trace)) { - gpr_log(GPR_DEBUG, "[RR %p] Shutting down Round Robin policy at %p", - (void *)pol, (void *)pol); + gpr_log(GPR_DEBUG, "[RR %p] Shutting down", (void *)pol); } + round_robin_lb_policy *p = (round_robin_lb_policy *)pol; p->shutdown = true; pending_pick *pp; while ((pp = p->pending_picks)) { @@ -336,14 +189,16 @@ static void rr_shutdown_locked(grpc_exec_ctx *exec_ctx, grpc_lb_policy *pol) { GRPC_ERROR_CREATE_FROM_STATIC_STRING("Channel Shutdown"), "rr_shutdown"); const bool latest_is_current = p->subchannel_list == p->latest_pending_subchannel_list; - rr_subchannel_list_shutdown_and_unref(exec_ctx, p->subchannel_list, - "sl_shutdown_rr_shutdown"); - p->subchannel_list = NULL; + if (p->subchannel_list != NULL) { + grpc_lb_subchannel_list_shutdown_and_unref(exec_ctx, p->subchannel_list, + "sl_shutdown_rr_shutdown"); + p->subchannel_list = NULL; + } if (!latest_is_current && p->latest_pending_subchannel_list != NULL && !p->latest_pending_subchannel_list->shutting_down) { - rr_subchannel_list_shutdown_and_unref(exec_ctx, - p->latest_pending_subchannel_list, - "sl_shutdown_pending_rr_shutdown"); + grpc_lb_subchannel_list_shutdown_and_unref( + exec_ctx, p->latest_pending_subchannel_list, + "sl_shutdown_pending_rr_shutdown"); p->latest_pending_subchannel_list = NULL; } } @@ -400,13 +255,10 @@ static void start_picking_locked(grpc_exec_ctx *exec_ctx, round_robin_lb_policy *p) { p->started_picking = true; for (size_t i = 0; i < p->subchannel_list->num_subchannels; i++) { - subchannel_data *sd = &p->subchannel_list->subchannels[i]; - GRPC_LB_POLICY_WEAK_REF(&p->base, "start_picking_locked"); - rr_subchannel_list_ref(sd->subchannel_list, "started_picking"); - grpc_subchannel_notify_on_state_change( - exec_ctx, sd->subchannel, p->base.interested_parties, - &sd->pending_connectivity_state_unsafe, - &sd->connectivity_changed_closure); + grpc_lb_subchannel_list_ref_for_connectivity_watch(p->subchannel_list, + "connectivity_watch"); + grpc_lb_subchannel_data_start_connectivity_watch( + exec_ctx, &p->subchannel_list->subchannels[i]); } } @@ -431,10 +283,10 @@ static int rr_pick_locked(grpc_exec_ctx *exec_ctx, grpc_lb_policy *pol, const size_t next_ready_index = get_next_ready_subchannel_index_locked(p); if (next_ready_index < p->subchannel_list->num_subchannels) { /* readily available, report right away */ - subchannel_data *sd = &p->subchannel_list->subchannels[next_ready_index]; - *target = GRPC_CONNECTED_SUBCHANNEL_REF( - grpc_subchannel_get_connected_subchannel(sd->subchannel), - "rr_picked"); + grpc_lb_subchannel_data *sd = + &p->subchannel_list->subchannels[next_ready_index]; + *target = GRPC_CONNECTED_SUBCHANNEL_REF(sd->connected_subchannel, + "rr_picked"); if (user_data != NULL) { *user_data = sd->user_data; } @@ -465,8 +317,8 @@ static int rr_pick_locked(grpc_exec_ctx *exec_ctx, grpc_lb_policy *pol, return 0; } -static void update_state_counters_locked(subchannel_data *sd) { - rr_subchannel_list *subchannel_list = sd->subchannel_list; +static void update_state_counters_locked(grpc_lb_subchannel_data *sd) { + grpc_lb_subchannel_list *subchannel_list = sd->subchannel_list; if (sd->prev_connectivity_state == GRPC_CHANNEL_READY) { GPR_ASSERT(subchannel_list->num_ready > 0); --subchannel_list->num_ready; @@ -492,12 +344,12 @@ static void update_state_counters_locked(subchannel_data *sd) { } /** Sets the policy's connectivity status based on that of the passed-in \a sd - * (the subchannel_data associted with the updated subchannel) and the + * (the grpc_lb_subchannel_data associted with the updated subchannel) and the * subchannel list \a sd belongs to (sd->subchannel_list). \a error will only be * used upon policy transition to TRANSIENT_FAILURE or SHUTDOWN. Returns the * connectivity status set. */ static grpc_connectivity_state update_lb_connectivity_status_locked( - grpc_exec_ctx *exec_ctx, subchannel_data *sd, grpc_error *error) { + grpc_exec_ctx *exec_ctx, grpc_lb_subchannel_data *sd, grpc_error *error) { /* In priority order. The first rule to match terminates the search (ie, if we * are on rule n, all previous rules were unfulfilled). * @@ -519,8 +371,8 @@ static grpc_connectivity_state update_lb_connectivity_status_locked( * CHECK: p->num_idle == p->subchannel_list->num_subchannels. */ grpc_connectivity_state new_state = sd->curr_connectivity_state; - rr_subchannel_list *subchannel_list = sd->subchannel_list; - round_robin_lb_policy *p = subchannel_list->policy; + grpc_lb_subchannel_list *subchannel_list = sd->subchannel_list; + round_robin_lb_policy *p = (round_robin_lb_policy *)subchannel_list->policy; if (subchannel_list->num_ready > 0) { /* 1) READY */ grpc_connectivity_state_set(exec_ctx, &p->state_tracker, GRPC_CHANNEL_READY, GRPC_ERROR_NONE, "rr_ready"); @@ -556,8 +408,9 @@ static grpc_connectivity_state update_lb_connectivity_status_locked( static void rr_connectivity_changed_locked(grpc_exec_ctx *exec_ctx, void *arg, grpc_error *error) { - subchannel_data *sd = (subchannel_data *)arg; - round_robin_lb_policy *p = sd->subchannel_list->policy; + grpc_lb_subchannel_data *sd = (grpc_lb_subchannel_data *)arg; + round_robin_lb_policy *p = + (round_robin_lb_policy *)sd->subchannel_list->policy; if (GRPC_TRACER_ON(grpc_lb_round_robin_trace)) { gpr_log( GPR_DEBUG, @@ -572,35 +425,24 @@ static void rr_connectivity_changed_locked(grpc_exec_ctx *exec_ctx, void *arg, } // If the policy is shutting down, unref and return. if (p->shutdown) { - rr_subchannel_list_unref(exec_ctx, sd->subchannel_list, - "pol_shutdown+started_picking"); - GRPC_LB_POLICY_WEAK_UNREF(exec_ctx, &p->base, "pol_shutdown"); + grpc_lb_subchannel_data_stop_connectivity_watch(exec_ctx, sd); + grpc_lb_subchannel_data_unref_subchannel(exec_ctx, sd, "rr_shutdown"); + grpc_lb_subchannel_list_unref_for_connectivity_watch( + exec_ctx, sd->subchannel_list, "rr_shutdown"); return; } - if (sd->subchannel_list->shutting_down && error == GRPC_ERROR_CANCELLED) { - // the subchannel list associated with sd has been discarded. This callback - // corresponds to the unsubscription. The unrefs correspond to the picking - // ref (start_picking_locked or update_started_picking). - rr_subchannel_list_unref(exec_ctx, sd->subchannel_list, - "sl_shutdown+started_picking"); - GRPC_LB_POLICY_WEAK_UNREF(exec_ctx, &p->base, "sl_shutdown+picking"); - return; - } - // Dispose of outdated subchannel lists. - if (sd->subchannel_list != p->subchannel_list && - sd->subchannel_list != p->latest_pending_subchannel_list) { - const char *reason = NULL; - if (sd->subchannel_list->shutting_down) { - reason = "sl_outdated_straggler"; - rr_subchannel_list_unref(exec_ctx, sd->subchannel_list, reason); - } else { - reason = "sl_outdated"; - rr_subchannel_list_shutdown_and_unref(exec_ctx, sd->subchannel_list, - reason); - } - GRPC_LB_POLICY_WEAK_UNREF(exec_ctx, &p->base, reason); + // If the subchannel list is shutting down, stop watching. + if (sd->subchannel_list->shutting_down || error == GRPC_ERROR_CANCELLED) { + grpc_lb_subchannel_data_stop_connectivity_watch(exec_ctx, sd); + grpc_lb_subchannel_data_unref_subchannel(exec_ctx, sd, "rr_sl_shutdown"); + grpc_lb_subchannel_list_unref_for_connectivity_watch( + exec_ctx, sd->subchannel_list, "rr_shutdown"); return; } + // If we're still here, the notification must be for a subchannel in + // either the current or latest pending subchannel lists. + GPR_ASSERT(sd->subchannel_list == p->subchannel_list || + sd->subchannel_list == p->latest_pending_subchannel_list); // Now that we're inside the combiner, copy the pending connectivity // state (which was set by the connectivity state watcher) to // curr_connectivity_state, which is what we use inside of the combiner. @@ -613,30 +455,21 @@ static void rr_connectivity_changed_locked(grpc_exec_ctx *exec_ctx, void *arg, // If the sd's new state is SHUTDOWN, unref the subchannel, and if the new // policy's state is SHUTDOWN, clean up. if (sd->curr_connectivity_state == GRPC_CHANNEL_SHUTDOWN) { - GRPC_SUBCHANNEL_UNREF(exec_ctx, sd->subchannel, "rr_subchannel_shutdown"); - sd->subchannel = NULL; - if (sd->user_data != NULL) { - GPR_ASSERT(sd->user_data_vtable != NULL); - sd->user_data_vtable->destroy(exec_ctx, sd->user_data); - sd->user_data = NULL; - } + grpc_lb_subchannel_data_stop_connectivity_watch(exec_ctx, sd); + grpc_lb_subchannel_data_unref_subchannel(exec_ctx, sd, + "rr_connectivity_shutdown"); + grpc_lb_subchannel_list_unref_for_connectivity_watch( + exec_ctx, sd->subchannel_list, "rr_connectivity_shutdown"); if (new_policy_connectivity_state == GRPC_CHANNEL_SHUTDOWN) { - // the policy is shutting down. Flush all the pending picks... - pending_pick *pp; - while ((pp = p->pending_picks)) { - p->pending_picks = pp->next; - *pp->target = NULL; - GRPC_CLOSURE_SCHED(exec_ctx, pp->on_complete, GRPC_ERROR_NONE); - gpr_free(pp); - } + rr_shutdown_locked(exec_ctx, &p->base); } - rr_subchannel_list_unref(exec_ctx, sd->subchannel_list, - "sd_shutdown+started_picking"); - // unref the "rr_connectivity_update" weak ref from start_picking. - GRPC_LB_POLICY_WEAK_UNREF(exec_ctx, &p->base, - "rr_connectivity_sd_shutdown"); } else { // sd not in SHUTDOWN if (sd->curr_connectivity_state == GRPC_CHANNEL_READY) { + if (sd->connected_subchannel == NULL) { + sd->connected_subchannel = GRPC_CONNECTED_SUBCHANNEL_REF( + grpc_subchannel_get_connected_subchannel(sd->subchannel), + "connected"); + } if (sd->subchannel_list != p->subchannel_list) { // promote sd->subchannel_list to p->subchannel_list. // sd->subchannel_list must be equal to @@ -657,8 +490,8 @@ static void rr_connectivity_changed_locked(grpc_exec_ctx *exec_ctx, void *arg, } if (p->subchannel_list != NULL) { // dispose of the current subchannel_list - rr_subchannel_list_shutdown_and_unref(exec_ctx, p->subchannel_list, - "sl_phase_out_shutdown"); + grpc_lb_subchannel_list_shutdown_and_unref( + exec_ctx, p->subchannel_list, "sl_phase_out_shutdown"); } p->subchannel_list = p->latest_pending_subchannel_list; p->latest_pending_subchannel_list = NULL; @@ -668,7 +501,7 @@ static void rr_connectivity_changed_locked(grpc_exec_ctx *exec_ctx, void *arg, * p->pending_picks. This preemtively replicates rr_pick()'s actions. */ const size_t next_ready_index = get_next_ready_subchannel_index_locked(p); GPR_ASSERT(next_ready_index < p->subchannel_list->num_subchannels); - subchannel_data *selected = + grpc_lb_subchannel_data *selected = &p->subchannel_list->subchannels[next_ready_index]; if (p->pending_picks != NULL) { // if the selected subchannel is going to be used for the pending @@ -679,8 +512,7 @@ static void rr_connectivity_changed_locked(grpc_exec_ctx *exec_ctx, void *arg, while ((pp = p->pending_picks)) { p->pending_picks = pp->next; *pp->target = GRPC_CONNECTED_SUBCHANNEL_REF( - grpc_subchannel_get_connected_subchannel(selected->subchannel), - "rr_picked"); + selected->connected_subchannel, "rr_picked"); if (pp->user_data != NULL) { *pp->user_data = selected->user_data; } @@ -695,12 +527,8 @@ static void rr_connectivity_changed_locked(grpc_exec_ctx *exec_ctx, void *arg, gpr_free(pp); } } - /* renew notification: reuses the "rr_connectivity_update" weak ref on the - * policy as well as the sd->subchannel_list ref. */ - grpc_subchannel_notify_on_state_change( - exec_ctx, sd->subchannel, p->base.interested_parties, - &sd->pending_connectivity_state_unsafe, - &sd->connectivity_changed_closure); + // Renew notification. + grpc_lb_subchannel_data_start_connectivity_watch(exec_ctx, sd); } } @@ -724,13 +552,12 @@ static void rr_ping_one_locked(grpc_exec_ctx *exec_ctx, grpc_lb_policy *pol, round_robin_lb_policy *p = (round_robin_lb_policy *)pol; const size_t next_ready_index = get_next_ready_subchannel_index_locked(p); if (next_ready_index < p->subchannel_list->num_subchannels) { - subchannel_data *selected = + grpc_lb_subchannel_data *selected = &p->subchannel_list->subchannels[next_ready_index]; grpc_connected_subchannel *target = GRPC_CONNECTED_SUBCHANNEL_REF( - grpc_subchannel_get_connected_subchannel(selected->subchannel), - "rr_picked"); + selected->connected_subchannel, "rr_ping"); grpc_connected_subchannel_ping(exec_ctx, target, closure); - GRPC_CONNECTED_SUBCHANNEL_UNREF(exec_ctx, target, "rr_picked"); + GRPC_CONNECTED_SUBCHANNEL_UNREF(exec_ctx, target, "rr_ping"); } else { GRPC_CLOSURE_SCHED(exec_ctx, closure, GRPC_ERROR_CREATE_FROM_STATIC_STRING( "Round Robin not connected")); @@ -758,115 +585,52 @@ static void rr_update_locked(grpc_exec_ctx *exec_ctx, grpc_lb_policy *policy, return; } grpc_lb_addresses *addresses = (grpc_lb_addresses *)arg->value.pointer.p; - rr_subchannel_list *subchannel_list = - rr_subchannel_list_create(p, addresses->num_addresses); - if (addresses->num_addresses == 0) { + grpc_lb_subchannel_list *subchannel_list = grpc_lb_subchannel_list_create( + exec_ctx, &p->base, addresses, args, rr_connectivity_changed_locked); + if (subchannel_list->num_subchannels == 0) { grpc_connectivity_state_set( exec_ctx, &p->state_tracker, GRPC_CHANNEL_TRANSIENT_FAILURE, GRPC_ERROR_CREATE_FROM_STATIC_STRING("Empty update"), "rr_update_empty"); if (p->subchannel_list != NULL) { - rr_subchannel_list_shutdown_and_unref(exec_ctx, p->subchannel_list, - "sl_shutdown_empty_update"); + grpc_lb_subchannel_list_shutdown_and_unref(exec_ctx, p->subchannel_list, + "sl_shutdown_empty_update"); } p->subchannel_list = subchannel_list; // empty list return; } - size_t subchannel_index = 0; - if (p->latest_pending_subchannel_list != NULL && p->started_picking) { - if (GRPC_TRACER_ON(grpc_lb_round_robin_trace)) { - gpr_log(GPR_DEBUG, - "[RR %p] Shutting down latest pending subchannel list %p, about " - "to be replaced by newer latest %p", - (void *)p, (void *)p->latest_pending_subchannel_list, - (void *)subchannel_list); - } - rr_subchannel_list_shutdown_and_unref( - exec_ctx, p->latest_pending_subchannel_list, "sl_outdated_dont_smash"); - } - p->latest_pending_subchannel_list = subchannel_list; - grpc_subchannel_args sc_args; - /* We need to remove the LB addresses in order to be able to compare the - * subchannel keys of subchannels from a different batch of addresses. */ - static const char *keys_to_remove[] = {GRPC_ARG_SUBCHANNEL_ADDRESS, - GRPC_ARG_LB_ADDRESSES}; - /* Create subchannels for addresses in the update. */ - for (size_t i = 0; i < addresses->num_addresses; i++) { - // If there were any balancer, we would have chosen grpclb policy instead. - GPR_ASSERT(!addresses->addresses[i].is_balancer); - memset(&sc_args, 0, sizeof(grpc_subchannel_args)); - grpc_arg addr_arg = - grpc_create_subchannel_address_arg(&addresses->addresses[i].address); - grpc_channel_args *new_args = grpc_channel_args_copy_and_add_and_remove( - args->args, keys_to_remove, GPR_ARRAY_SIZE(keys_to_remove), &addr_arg, - 1); - gpr_free(addr_arg.value.string); - sc_args.args = new_args; - grpc_subchannel *subchannel = grpc_client_channel_factory_create_subchannel( - exec_ctx, args->client_channel_factory, &sc_args); - grpc_channel_args_destroy(exec_ctx, new_args); - grpc_error *error; - // Get the connectivity state of the subchannel. Already existing ones may - // be in a state other than INIT. - const grpc_connectivity_state subchannel_connectivity_state = - grpc_subchannel_check_connectivity(subchannel, &error); - if (error != GRPC_ERROR_NONE) { - // The subchannel is in error (e.g. shutting down). Ignore it. - GRPC_SUBCHANNEL_UNREF(exec_ctx, subchannel, "new_sc_connectivity_error"); - GRPC_ERROR_UNREF(error); - continue; - } - if (GRPC_TRACER_ON(grpc_lb_round_robin_trace)) { - char *address_uri = - grpc_sockaddr_to_uri(&addresses->addresses[i].address); - gpr_log( - GPR_DEBUG, - "[RR %p] index %lu: Created subchannel %p for address uri %s into " - "subchannel_list %p. Connectivity state %s", - (void *)p, (unsigned long)subchannel_index, (void *)subchannel, - address_uri, (void *)subchannel_list, - grpc_connectivity_state_name(subchannel_connectivity_state)); - gpr_free(address_uri); - } - subchannel_data *sd = &subchannel_list->subchannels[subchannel_index++]; - sd->subchannel_list = subchannel_list; - sd->subchannel = subchannel; - GRPC_CLOSURE_INIT(&sd->connectivity_changed_closure, - rr_connectivity_changed_locked, sd, - grpc_combiner_scheduler(args->combiner)); - /* use some sentinel value outside of the range of - * grpc_connectivity_state to signal an undefined previous state. We - * won't be referring to this value again and it'll be overwritten after - * the first call to rr_connectivity_changed_locked */ - sd->prev_connectivity_state = GRPC_CHANNEL_INIT; - sd->curr_connectivity_state = subchannel_connectivity_state; - sd->user_data_vtable = addresses->user_data_vtable; - if (sd->user_data_vtable != NULL) { - sd->user_data = - sd->user_data_vtable->copy(addresses->addresses[i].user_data); + if (p->started_picking) { + if (p->latest_pending_subchannel_list != NULL && p->started_picking) { + if (GRPC_TRACER_ON(grpc_lb_round_robin_trace)) { + gpr_log(GPR_DEBUG, + "[RR %p] Shutting down latest pending subchannel list %p, " + "about to be replaced by newer latest %p", + (void *)p, (void *)p->latest_pending_subchannel_list, + (void *)subchannel_list); + } + grpc_lb_subchannel_list_shutdown_and_unref( + exec_ctx, p->latest_pending_subchannel_list, + "sl_outdated_dont_smash"); } - if (p->started_picking) { - rr_subchannel_list_ref(sd->subchannel_list, "update_started_picking"); - GRPC_LB_POLICY_WEAK_REF(&p->base, "rr_connectivity_update"); - /* 2. Watch every new subchannel. A subchannel list becomes active the + p->latest_pending_subchannel_list = subchannel_list; + for (size_t i = 0; i < subchannel_list->num_subchannels; ++i) { + /* Watch every new subchannel. A subchannel list becomes active the * moment one of its subchannels is READY. At that moment, we swap * p->subchannel_list for sd->subchannel_list, provided the subchannel * list is still valid (ie, isn't shutting down) */ - grpc_subchannel_notify_on_state_change( - exec_ctx, sd->subchannel, p->base.interested_parties, - &sd->pending_connectivity_state_unsafe, - &sd->connectivity_changed_closure); + grpc_lb_subchannel_list_ref_for_connectivity_watch(subchannel_list, + "connectivity_watch"); + grpc_lb_subchannel_data_start_connectivity_watch( + exec_ctx, &subchannel_list->subchannels[i]); } - } - if (!p->started_picking) { + } else { // The policy isn't picking yet. Save the update for later, disposing of // previous version if any. if (p->subchannel_list != NULL) { - rr_subchannel_list_shutdown_and_unref(exec_ctx, p->subchannel_list, - "rr_update_before_started_picking"); + grpc_lb_subchannel_list_shutdown_and_unref( + exec_ctx, p->subchannel_list, "rr_update_before_started_picking"); } p->subchannel_list = subchannel_list; - p->latest_pending_subchannel_list = NULL; } } diff --git a/src/core/ext/filters/client_channel/lb_policy/subchannel_list.cc b/src/core/ext/filters/client_channel/lb_policy/subchannel_list.cc new file mode 100644 index 00000000000..ad26316aac5 --- /dev/null +++ b/src/core/ext/filters/client_channel/lb_policy/subchannel_list.cc @@ -0,0 +1,282 @@ +/* + * + * 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 + +#include + +#include "src/core/ext/filters/client_channel/lb_policy/subchannel_list.h" +#include "src/core/lib/channel/channel_args.h" +#include "src/core/lib/debug/trace.h" +#include "src/core/lib/iomgr/closure.h" +#include "src/core/lib/iomgr/combiner.h" +#include "src/core/lib/iomgr/sockaddr_utils.h" +#include "src/core/lib/transport/connectivity_state.h" + +extern grpc_tracer_flag grpc_lb_round_robin_trace; +extern grpc_tracer_flag grpc_lb_pick_first_trace; + +void grpc_lb_subchannel_data_unref_subchannel(grpc_exec_ctx *exec_ctx, + grpc_lb_subchannel_data *sd, + const char *reason) { + if (sd->subchannel != NULL) { + if (GRPC_TRACER_ON(grpc_lb_round_robin_trace) || + GRPC_TRACER_ON(grpc_lb_pick_first_trace)) { + gpr_log(GPR_DEBUG, + "[LB %p] subchannel list %p index %" PRIdPTR " of %" PRIdPTR + " (subchannel %p): unreffing subchannel", + sd->subchannel_list->policy, sd->subchannel_list, + sd - sd->subchannel_list->subchannels, + sd->subchannel_list->num_subchannels, sd->subchannel); + } + GRPC_SUBCHANNEL_UNREF(exec_ctx, sd->subchannel, reason); + sd->subchannel = NULL; + if (sd->connected_subchannel != NULL) { + GRPC_CONNECTED_SUBCHANNEL_UNREF(exec_ctx, sd->connected_subchannel, + reason); + sd->connected_subchannel = NULL; + } + if (sd->user_data != NULL) { + GPR_ASSERT(sd->user_data_vtable != NULL); + sd->user_data_vtable->destroy(exec_ctx, sd->user_data); + sd->user_data = NULL; + } + } +} + +void grpc_lb_subchannel_data_start_connectivity_watch( + grpc_exec_ctx *exec_ctx, grpc_lb_subchannel_data *sd) { + if (GRPC_TRACER_ON(grpc_lb_round_robin_trace) || + GRPC_TRACER_ON(grpc_lb_pick_first_trace)) { + gpr_log(GPR_DEBUG, + "[LB %p] subchannel list %p index %" PRIdPTR " of %" PRIdPTR + " (subchannel %p): requesting connectivity change notification", + sd->subchannel_list->policy, sd->subchannel_list, + sd - sd->subchannel_list->subchannels, + sd->subchannel_list->num_subchannels, sd->subchannel); + } + sd->connectivity_notification_pending = true; + grpc_subchannel_notify_on_state_change( + exec_ctx, sd->subchannel, sd->subchannel_list->policy->interested_parties, + &sd->pending_connectivity_state_unsafe, + &sd->connectivity_changed_closure); +} + +void grpc_lb_subchannel_data_stop_connectivity_watch( + grpc_exec_ctx *exec_ctx, grpc_lb_subchannel_data *sd) { + GPR_ASSERT(sd->connectivity_notification_pending); + if (GRPC_TRACER_ON(grpc_lb_round_robin_trace) || + GRPC_TRACER_ON(grpc_lb_pick_first_trace)) { + gpr_log(GPR_DEBUG, + "[LB %p] subchannel list %p index %" PRIdPTR " of %" PRIdPTR + " (subchannel %p): stopping connectivity watch", + sd->subchannel_list->policy, sd->subchannel_list, + sd - sd->subchannel_list->subchannels, + sd->subchannel_list->num_subchannels, sd->subchannel); + } + sd->connectivity_notification_pending = false; +} + +grpc_lb_subchannel_list *grpc_lb_subchannel_list_create( + grpc_exec_ctx *exec_ctx, grpc_lb_policy *p, + const grpc_lb_addresses *addresses, const grpc_lb_policy_args *args, + grpc_iomgr_cb_func connectivity_changed_cb) { + grpc_lb_subchannel_list *subchannel_list = + (grpc_lb_subchannel_list *)gpr_zalloc(sizeof(*subchannel_list)); + if (GRPC_TRACER_ON(grpc_lb_round_robin_trace) || + GRPC_TRACER_ON(grpc_lb_pick_first_trace)) { + gpr_log(GPR_DEBUG, + "[LB %p] Creating subchannel list %p for %" PRIdPTR " subchannels", + p, subchannel_list, addresses->num_addresses); + } + subchannel_list->policy = p; + gpr_ref_init(&subchannel_list->refcount, 1); + subchannel_list->subchannels = (grpc_lb_subchannel_data *)gpr_zalloc( + sizeof(grpc_lb_subchannel_data) * addresses->num_addresses); + /* We need to remove the LB addresses in order to be able to compare the + * subchannel keys of subchannels from a different batch of addresses. */ + static const char *keys_to_remove[] = {GRPC_ARG_SUBCHANNEL_ADDRESS, + GRPC_ARG_LB_ADDRESSES}; + /* Create subchannels for addresses in the update. */ + grpc_subchannel_args sc_args; + size_t subchannel_index = 0; + for (size_t i = 0; i < addresses->num_addresses; i++) { + // If there were any balancer, we would have chosen grpclb policy instead. + GPR_ASSERT(!addresses->addresses[i].is_balancer); + memset(&sc_args, 0, sizeof(grpc_subchannel_args)); + grpc_arg addr_arg = + grpc_create_subchannel_address_arg(&addresses->addresses[i].address); + grpc_channel_args *new_args = grpc_channel_args_copy_and_add_and_remove( + args->args, keys_to_remove, GPR_ARRAY_SIZE(keys_to_remove), &addr_arg, + 1); + gpr_free(addr_arg.value.string); + sc_args.args = new_args; + grpc_subchannel *subchannel = grpc_client_channel_factory_create_subchannel( + exec_ctx, args->client_channel_factory, &sc_args); + grpc_channel_args_destroy(exec_ctx, new_args); + grpc_error *error; + // Get the connectivity state of the subchannel. Already existing ones may + // be in a state other than INIT. + const grpc_connectivity_state subchannel_connectivity_state = + grpc_subchannel_check_connectivity(subchannel, &error); + if (error != GRPC_ERROR_NONE) { + // The subchannel is in error (e.g. shutting down). Ignore it. + if (GRPC_TRACER_ON(grpc_lb_round_robin_trace) || + GRPC_TRACER_ON(grpc_lb_pick_first_trace)) { + char *address_uri = + grpc_sockaddr_to_uri(&addresses->addresses[i].address); + gpr_log(GPR_DEBUG, + "[LB %p] subchannel for address uri %s shutting down, ignoring", + subchannel_list->policy, address_uri); + gpr_free(address_uri); + } + GRPC_SUBCHANNEL_UNREF(exec_ctx, subchannel, "new_sc_connectivity_error"); + GRPC_ERROR_UNREF(error); + continue; + } + if (GRPC_TRACER_ON(grpc_lb_round_robin_trace) || + GRPC_TRACER_ON(grpc_lb_pick_first_trace)) { + char *address_uri = + grpc_sockaddr_to_uri(&addresses->addresses[i].address); + gpr_log( + GPR_DEBUG, + "[LB %p] subchannel list %p index %" PRIdPTR + ": Created subchannel %p for address uri %s; " + "initial connectivity state: %s", + p, subchannel_list, subchannel_index, subchannel, address_uri, + grpc_connectivity_state_name(subchannel_connectivity_state)); + gpr_free(address_uri); + } + grpc_lb_subchannel_data *sd = + &subchannel_list->subchannels[subchannel_index++]; + sd->subchannel_list = subchannel_list; + sd->subchannel = subchannel; + GRPC_CLOSURE_INIT(&sd->connectivity_changed_closure, + connectivity_changed_cb, sd, + grpc_combiner_scheduler(args->combiner)); + /* use some sentinel value outside of the range of + * grpc_connectivity_state to signal an undefined previous state. We + * won't be referring to this value again and it'll be overwritten after + * the first call to rr_connectivity_changed_locked */ + sd->prev_connectivity_state = GRPC_CHANNEL_INIT; + sd->curr_connectivity_state = subchannel_connectivity_state; + sd->user_data_vtable = addresses->user_data_vtable; + if (sd->user_data_vtable != NULL) { + sd->user_data = + sd->user_data_vtable->copy(addresses->addresses[i].user_data); + } + } + subchannel_list->num_subchannels = subchannel_index; + return subchannel_list; +} + +static void subchannel_list_destroy(grpc_exec_ctx *exec_ctx, + grpc_lb_subchannel_list *subchannel_list) { + if (GRPC_TRACER_ON(grpc_lb_round_robin_trace) || + GRPC_TRACER_ON(grpc_lb_pick_first_trace)) { + gpr_log(GPR_DEBUG, "[LB %p] Destroying subchannel_list %p", + subchannel_list->policy, subchannel_list); + } + for (size_t i = 0; i < subchannel_list->num_subchannels; i++) { + grpc_lb_subchannel_data *sd = &subchannel_list->subchannels[i]; + grpc_lb_subchannel_data_unref_subchannel(exec_ctx, sd, + "subchannel_list_destroy"); + } + gpr_free(subchannel_list->subchannels); + gpr_free(subchannel_list); +} + +void grpc_lb_subchannel_list_ref(grpc_lb_subchannel_list *subchannel_list, + const char *reason) { + gpr_ref_non_zero(&subchannel_list->refcount); + if (GRPC_TRACER_ON(grpc_lb_round_robin_trace) || + GRPC_TRACER_ON(grpc_lb_pick_first_trace)) { + const gpr_atm count = gpr_atm_acq_load(&subchannel_list->refcount.count); + gpr_log(GPR_DEBUG, "[LB %p] subchannel_list %p REF %lu->%lu (%s)", + subchannel_list->policy, subchannel_list, + (unsigned long)(count - 1), (unsigned long)count, reason); + } +} + +void grpc_lb_subchannel_list_unref(grpc_exec_ctx *exec_ctx, + grpc_lb_subchannel_list *subchannel_list, + const char *reason) { + const bool done = gpr_unref(&subchannel_list->refcount); + if (GRPC_TRACER_ON(grpc_lb_round_robin_trace) || + GRPC_TRACER_ON(grpc_lb_pick_first_trace)) { + const gpr_atm count = gpr_atm_acq_load(&subchannel_list->refcount.count); + gpr_log(GPR_DEBUG, "[LB %p] subchannel_list %p UNREF %lu->%lu (%s)", + subchannel_list->policy, subchannel_list, + (unsigned long)(count + 1), (unsigned long)count, reason); + } + if (done) { + subchannel_list_destroy(exec_ctx, subchannel_list); + } +} + +void grpc_lb_subchannel_list_ref_for_connectivity_watch( + grpc_lb_subchannel_list *subchannel_list, const char *reason) { + GRPC_LB_POLICY_WEAK_REF(subchannel_list->policy, reason); + grpc_lb_subchannel_list_ref(subchannel_list, reason); +} + +void grpc_lb_subchannel_list_unref_for_connectivity_watch( + grpc_exec_ctx *exec_ctx, grpc_lb_subchannel_list *subchannel_list, + const char *reason) { + GRPC_LB_POLICY_WEAK_UNREF(exec_ctx, subchannel_list->policy, reason); + grpc_lb_subchannel_list_unref(exec_ctx, subchannel_list, reason); +} + +static void grpc_lb_subchannel_data_cancel_connectivity_watch( + grpc_exec_ctx *exec_ctx, grpc_lb_subchannel_data *sd, const char *reason) { + if (GRPC_TRACER_ON(grpc_lb_round_robin_trace) || + GRPC_TRACER_ON(grpc_lb_pick_first_trace)) { + gpr_log(GPR_DEBUG, + "[LB %p] subchannel list %p index %" PRIdPTR " of %" PRIdPTR + " (subchannel %p): canceling connectivity watch (%s)", + sd->subchannel_list->policy, sd->subchannel_list, + sd - sd->subchannel_list->subchannels, + sd->subchannel_list->num_subchannels, sd->subchannel, reason); + } + grpc_subchannel_notify_on_state_change( + exec_ctx, sd->subchannel, NULL, NULL, &sd->connectivity_changed_closure); +} + +void grpc_lb_subchannel_list_shutdown_and_unref( + grpc_exec_ctx *exec_ctx, grpc_lb_subchannel_list *subchannel_list, + const char *reason) { + if (GRPC_TRACER_ON(grpc_lb_round_robin_trace) || + GRPC_TRACER_ON(grpc_lb_pick_first_trace)) { + gpr_log(GPR_DEBUG, "[LB %p] Shutting down subchannel_list %p (%s)", + subchannel_list->policy, subchannel_list, reason); + } + GPR_ASSERT(!subchannel_list->shutting_down); + subchannel_list->shutting_down = true; + for (size_t i = 0; i < subchannel_list->num_subchannels; i++) { + grpc_lb_subchannel_data *sd = &subchannel_list->subchannels[i]; + // If there's a pending notification for this subchannel, cancel it; + // the callback is responsible for unreffing the subchannel. + // Otherwise, unref the subchannel directly. + if (sd->connectivity_notification_pending) { + grpc_lb_subchannel_data_cancel_connectivity_watch(exec_ctx, sd, reason); + } else if (sd->subchannel != NULL) { + grpc_lb_subchannel_data_unref_subchannel(exec_ctx, sd, reason); + } + } + grpc_lb_subchannel_list_unref(exec_ctx, subchannel_list, reason); +} diff --git a/src/core/ext/filters/client_channel/lb_policy/subchannel_list.h b/src/core/ext/filters/client_channel/lb_policy/subchannel_list.h new file mode 100644 index 00000000000..1e3a921c65a --- /dev/null +++ b/src/core/ext/filters/client_channel/lb_policy/subchannel_list.h @@ -0,0 +1,149 @@ +/* + * + * 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_LB_POLICY_SUBCHANNEL_LIST_H +#define GRPC_CORE_EXT_FILTERS_CLIENT_CHANNEL_LB_POLICY_SUBCHANNEL_LIST_H + +#include "src/core/ext/filters/client_channel/lb_policy_registry.h" +#include "src/core/ext/filters/client_channel/subchannel.h" +#include "src/core/lib/transport/connectivity_state.h" + +// TODO(roth): This code is intended to be shared between pick_first and +// round_robin. However, the interface needs more work to provide clean +// encapsulation. For example, the structs here have some fields that are +// only used in one of the two (e.g., the state counters in +// grpc_lb_subchannel_list and the prev_connectivity_state field in +// grpc_lb_subchannel_data are only used in round_robin, and the +// checking_subchannel field in grpc_lb_subchannel_list is only used by +// pick_first). Also, there is probably some code duplication between the +// connectivity state notification callback code in both pick_first and +// round_robin that could be refactored and moved here. In a future PR, +// need to clean this up. + +#ifdef __cplusplus +extern "C" { +#endif + +typedef struct grpc_lb_subchannel_list grpc_lb_subchannel_list; + +typedef struct { + /** backpointer to owning subchannel list */ + grpc_lb_subchannel_list *subchannel_list; + /** subchannel itself */ + grpc_subchannel *subchannel; + grpc_connected_subchannel *connected_subchannel; + /** Is a connectivity notification pending? */ + bool connectivity_notification_pending; + /** notification that connectivity has changed on subchannel */ + grpc_closure connectivity_changed_closure; + /** previous and current connectivity states. Updated by \a + * \a connectivity_changed_closure based on + * \a pending_connectivity_state_unsafe. */ + grpc_connectivity_state prev_connectivity_state; + grpc_connectivity_state curr_connectivity_state; + /** connectivity state to be updated by + * grpc_subchannel_notify_on_state_change(), not guarded by + * the combiner. To be copied to \a curr_connectivity_state by + * \a connectivity_changed_closure. */ + grpc_connectivity_state pending_connectivity_state_unsafe; + /** the subchannel's target user data */ + void *user_data; + /** vtable to operate over \a user_data */ + const grpc_lb_user_data_vtable *user_data_vtable; +} grpc_lb_subchannel_data; + +// Unrefs the subchannel contained in sd. +void grpc_lb_subchannel_data_unref_subchannel( + grpc_exec_ctx *exec_ctx, grpc_lb_subchannel_data *sd, const char *reason); + +// Starts watching the connectivity state of the subchannel. +// The connectivity_changed_cb callback must invoke either +// grpc_lb_subchannel_data_stop_connectivity_watch() or again call +// grpc_lb_subchannel_data_start_connectivity_watch(). +void grpc_lb_subchannel_data_start_connectivity_watch( + grpc_exec_ctx *exec_ctx, grpc_lb_subchannel_data *sd); + +// Stops watching the connectivity state of the subchannel. +void grpc_lb_subchannel_data_stop_connectivity_watch( + grpc_exec_ctx *exec_ctx, grpc_lb_subchannel_data *sd); + +struct grpc_lb_subchannel_list { + /** backpointer to owning policy */ + grpc_lb_policy *policy; + + /** all our subchannels */ + size_t num_subchannels; + grpc_lb_subchannel_data *subchannels; + + /** Index into subchannels of the one we're currently checking. + * Used when connecting to subchannels serially instead of in parallel. */ + // TODO(roth): When we have time, we can probably make this go away + // and the index dynamically by subtracting + // subchannel_list->subchannels from the subchannel_data pointer. + size_t checking_subchannel; + + /** how many subchannels are in state READY */ + size_t num_ready; + /** how many subchannels are in state TRANSIENT_FAILURE */ + size_t num_transient_failures; + /** how many subchannels are in state SHUTDOWN */ + size_t num_shutdown; + /** how many subchannels are in state IDLE */ + size_t num_idle; + + /** There will be one ref for each entry in subchannels for which there is a + * pending connectivity state watcher callback. */ + gpr_refcount refcount; + + /** Is this list shutting down? This may be true due to the shutdown of the + * policy itself or because a newer update has arrived while this one hadn't + * finished processing. */ + bool shutting_down; +}; + +grpc_lb_subchannel_list *grpc_lb_subchannel_list_create( + grpc_exec_ctx *exec_ctx, grpc_lb_policy *p, + const grpc_lb_addresses *addresses, const grpc_lb_policy_args *args, + grpc_iomgr_cb_func connectivity_changed_cb); + +void grpc_lb_subchannel_list_ref(grpc_lb_subchannel_list *subchannel_list, + const char *reason); + +void grpc_lb_subchannel_list_unref(grpc_exec_ctx *exec_ctx, + grpc_lb_subchannel_list *subchannel_list, + const char *reason); + +// Takes and releases refs needed for a connectivity notification. +// This includes a ref to subchannel_list and a weak ref to the LB policy. +void grpc_lb_subchannel_list_ref_for_connectivity_watch( + grpc_lb_subchannel_list *subchannel_list, const char *reason); +void grpc_lb_subchannel_list_unref_for_connectivity_watch( + grpc_exec_ctx *exec_ctx, grpc_lb_subchannel_list *subchannel_list, + const char *reason); + +// Mark subchannel_list as discarded. Unsubscribes all its subchannels. The +// connectivity state notification callback will ultimately unref it. +void grpc_lb_subchannel_list_shutdown_and_unref( + grpc_exec_ctx *exec_ctx, grpc_lb_subchannel_list *subchannel_list, + const char *reason); + +#ifdef __cplusplus +} +#endif + +#endif /* GRPC_CORE_EXT_FILTERS_CLIENT_CHANNEL_LB_POLICY_SUBCHANNEL_LIST_H */ diff --git a/src/python/grpcio/grpc_core_dependencies.py b/src/python/grpcio/grpc_core_dependencies.py index 7b9fd6424da..68e27530262 100644 --- a/src/python/grpcio/grpc_core_dependencies.py +++ b/src/python/grpcio/grpc_core_dependencies.py @@ -293,6 +293,7 @@ CORE_SOURCE_FILES = [ 'third_party/nanopb/pb_encode.c', 'src/core/ext/filters/client_channel/resolver/fake/fake_resolver.cc', 'src/core/ext/filters/client_channel/lb_policy/pick_first/pick_first.cc', + 'src/core/ext/filters/client_channel/lb_policy/subchannel_list.cc', 'src/core/ext/filters/client_channel/lb_policy/round_robin/round_robin.cc', 'src/core/ext/filters/client_channel/resolver/dns/c_ares/dns_resolver_ares.cc', 'src/core/ext/filters/client_channel/resolver/dns/c_ares/grpc_ares_ev_driver_posix.cc', diff --git a/tools/doxygen/Doxyfile.core.internal b/tools/doxygen/Doxyfile.core.internal index ee593e3ea09..dc6df1decdc 100644 --- a/tools/doxygen/Doxyfile.core.internal +++ b/tools/doxygen/Doxyfile.core.internal @@ -934,6 +934,8 @@ src/core/ext/filters/client_channel/lb_policy/grpclb/proto/grpc/lb/v1/load_balan src/core/ext/filters/client_channel/lb_policy/grpclb/proto/grpc/lb/v1/load_balancer.pb.h \ src/core/ext/filters/client_channel/lb_policy/pick_first/pick_first.cc \ src/core/ext/filters/client_channel/lb_policy/round_robin/round_robin.cc \ +src/core/ext/filters/client_channel/lb_policy/subchannel_list.cc \ +src/core/ext/filters/client_channel/lb_policy/subchannel_list.h \ src/core/ext/filters/client_channel/lb_policy_factory.cc \ src/core/ext/filters/client_channel/lb_policy_factory.h \ src/core/ext/filters/client_channel/lb_policy_registry.cc \ diff --git a/tools/run_tests/generated/sources_and_headers.json b/tools/run_tests/generated/sources_and_headers.json index 95556b2e6f5..6c2a0cf4166 100644 --- a/tools/run_tests/generated/sources_and_headers.json +++ b/tools/run_tests/generated/sources_and_headers.json @@ -8628,7 +8628,8 @@ "deps": [ "gpr", "grpc_base", - "grpc_client_channel" + "grpc_client_channel", + "grpc_lb_subchannel_list" ], "headers": [], "is_filegroup": true, @@ -8644,7 +8645,8 @@ "deps": [ "gpr", "grpc_base", - "grpc_client_channel" + "grpc_client_channel", + "grpc_lb_subchannel_list" ], "headers": [], "is_filegroup": true, @@ -8656,6 +8658,25 @@ "third_party": false, "type": "filegroup" }, + { + "deps": [ + "gpr", + "grpc_base", + "grpc_client_channel" + ], + "headers": [ + "src/core/ext/filters/client_channel/lb_policy/subchannel_list.h" + ], + "is_filegroup": true, + "language": "c", + "name": "grpc_lb_subchannel_list", + "src": [ + "src/core/ext/filters/client_channel/lb_policy/subchannel_list.cc", + "src/core/ext/filters/client_channel/lb_policy/subchannel_list.h" + ], + "third_party": false, + "type": "filegroup" + }, { "deps": [ "gpr", From efea67438a18bcdfdcc4a96e7dbe98bfced9dab7 Mon Sep 17 00:00:00 2001 From: "Mark D. Roth" Date: Mon, 9 Oct 2017 12:17:52 -0700 Subject: [PATCH 02/47] Fix crash in trace logging. --- .../filters/client_channel/lb_policy/pick_first/pick_first.cc | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/core/ext/filters/client_channel/lb_policy/pick_first/pick_first.cc b/src/core/ext/filters/client_channel/lb_policy/pick_first/pick_first.cc index bbf05484052..22b6aea45da 100644 --- a/src/core/ext/filters/client_channel/lb_policy/pick_first/pick_first.cc +++ b/src/core/ext/filters/client_channel/lb_policy/pick_first/pick_first.cc @@ -369,7 +369,7 @@ static void pf_connectivity_changed_locked(grpc_exec_ctx *exec_ctx, void *arg, " of %" PRIdPTR "), subchannel_list %p: state=%s p->shutdown=%d " "sd->subchannel_list->shutting_down=%d error=%s", (void *)p, (void *)sd->subchannel, - p->subchannel_list->checking_subchannel, + sd->subchannel_list->checking_subchannel, sd->subchannel_list->num_subchannels, (void *)sd->subchannel_list, grpc_connectivity_state_name(sd->pending_connectivity_state_unsafe), p->shutdown, sd->subchannel_list->shutting_down, From bf6a86a293325b528dc10ee10ed9d1242b87a642 Mon Sep 17 00:00:00 2001 From: "Mark D. Roth" Date: Mon, 9 Oct 2017 12:23:37 -0700 Subject: [PATCH 03/47] Fix build portability problem. --- .../filters/client_channel/lb_policy/subchannel_list.cc | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/src/core/ext/filters/client_channel/lb_policy/subchannel_list.cc b/src/core/ext/filters/client_channel/lb_policy/subchannel_list.cc index ad26316aac5..d99fc48087e 100644 --- a/src/core/ext/filters/client_channel/lb_policy/subchannel_list.cc +++ b/src/core/ext/filters/client_channel/lb_policy/subchannel_list.cc @@ -41,7 +41,7 @@ void grpc_lb_subchannel_data_unref_subchannel(grpc_exec_ctx *exec_ctx, "[LB %p] subchannel list %p index %" PRIdPTR " of %" PRIdPTR " (subchannel %p): unreffing subchannel", sd->subchannel_list->policy, sd->subchannel_list, - sd - sd->subchannel_list->subchannels, + (size_t)(sd - sd->subchannel_list->subchannels), sd->subchannel_list->num_subchannels, sd->subchannel); } GRPC_SUBCHANNEL_UNREF(exec_ctx, sd->subchannel, reason); @@ -67,7 +67,7 @@ void grpc_lb_subchannel_data_start_connectivity_watch( "[LB %p] subchannel list %p index %" PRIdPTR " of %" PRIdPTR " (subchannel %p): requesting connectivity change notification", sd->subchannel_list->policy, sd->subchannel_list, - sd - sd->subchannel_list->subchannels, + (size_t)(sd - sd->subchannel_list->subchannels), sd->subchannel_list->num_subchannels, sd->subchannel); } sd->connectivity_notification_pending = true; @@ -86,7 +86,7 @@ void grpc_lb_subchannel_data_stop_connectivity_watch( "[LB %p] subchannel list %p index %" PRIdPTR " of %" PRIdPTR " (subchannel %p): stopping connectivity watch", sd->subchannel_list->policy, sd->subchannel_list, - sd - sd->subchannel_list->subchannels, + (size_t)(sd - sd->subchannel_list->subchannels), sd->subchannel_list->num_subchannels, sd->subchannel); } sd->connectivity_notification_pending = false; @@ -250,7 +250,7 @@ static void grpc_lb_subchannel_data_cancel_connectivity_watch( "[LB %p] subchannel list %p index %" PRIdPTR " of %" PRIdPTR " (subchannel %p): canceling connectivity watch (%s)", sd->subchannel_list->policy, sd->subchannel_list, - sd - sd->subchannel_list->subchannels, + (size_t)(sd - sd->subchannel_list->subchannels), sd->subchannel_list->num_subchannels, sd->subchannel, reason); } grpc_subchannel_notify_on_state_change( From 62ca6ced7c1a8b832980ac2637bfff1ee6505e60 Mon Sep 17 00:00:00 2001 From: "Mark D. Roth" Date: Tue, 10 Oct 2017 10:01:51 -0700 Subject: [PATCH 04/47] clang-format --- .../lb_policy/pick_first/pick_first.cc | 67 +++++++++---------- .../lb_policy/round_robin/round_robin.cc | 4 +- .../lb_policy/subchannel_list.cc | 16 ++--- .../lb_policy/subchannel_list.h | 5 +- 4 files changed, 45 insertions(+), 47 deletions(-) diff --git a/src/core/ext/filters/client_channel/lb_policy/pick_first/pick_first.cc b/src/core/ext/filters/client_channel/lb_policy/pick_first/pick_first.cc index 22b6aea45da..8119377504c 100644 --- a/src/core/ext/filters/client_channel/lb_policy/pick_first/pick_first.cc +++ b/src/core/ext/filters/client_channel/lb_policy/pick_first/pick_first.cc @@ -84,9 +84,9 @@ static void shutdown_locked(grpc_exec_ctx *exec_ctx, pick_first_lb_policy *p, GRPC_CLOSURE_SCHED(exec_ctx, pp->on_complete, GRPC_ERROR_REF(error)); gpr_free(pp); } - grpc_connectivity_state_set( - exec_ctx, &p->state_tracker, GRPC_CHANNEL_SHUTDOWN, - GRPC_ERROR_REF(error), "shutdown"); + grpc_connectivity_state_set(exec_ctx, &p->state_tracker, + GRPC_CHANNEL_SHUTDOWN, GRPC_ERROR_REF(error), + "shutdown"); if (p->subchannel_list != NULL) { grpc_lb_subchannel_list_shutdown_and_unref(exec_ctx, p->subchannel_list, "pf_shutdown"); @@ -285,8 +285,8 @@ static void pf_update_locked(grpc_exec_ctx *exec_ctx, grpc_lb_policy *policy, // We don't yet have a selected subchannel, so replace the current // subchannel list immediately. if (p->subchannel_list != NULL) { - grpc_lb_subchannel_list_shutdown_and_unref( - exec_ctx, p->subchannel_list, "pf_update_before_selected"); + grpc_lb_subchannel_list_shutdown_and_unref(exec_ctx, p->subchannel_list, + "pf_update_before_selected"); } p->subchannel_list = subchannel_list; } else { @@ -363,17 +363,17 @@ static void pf_connectivity_changed_locked(grpc_exec_ctx *exec_ctx, void *arg, grpc_lb_subchannel_data *sd = (grpc_lb_subchannel_data *)arg; pick_first_lb_policy *p = (pick_first_lb_policy *)sd->subchannel_list->policy; if (GRPC_TRACER_ON(grpc_lb_pick_first_trace)) { - gpr_log( - GPR_DEBUG, - "Pick First %p connectivity changed for subchannel %p (%" PRIdPTR - " of %" PRIdPTR "), subchannel_list %p: state=%s p->shutdown=%d " - "sd->subchannel_list->shutting_down=%d error=%s", - (void *)p, (void *)sd->subchannel, - sd->subchannel_list->checking_subchannel, - sd->subchannel_list->num_subchannels, (void *)sd->subchannel_list, - grpc_connectivity_state_name(sd->pending_connectivity_state_unsafe), - p->shutdown, sd->subchannel_list->shutting_down, - grpc_error_string(error)); + gpr_log(GPR_DEBUG, + "Pick First %p connectivity changed for subchannel %p (%" PRIdPTR + " of %" PRIdPTR + "), subchannel_list %p: state=%s p->shutdown=%d " + "sd->subchannel_list->shutting_down=%d error=%s", + (void *)p, (void *)sd->subchannel, + sd->subchannel_list->checking_subchannel, + sd->subchannel_list->num_subchannels, (void *)sd->subchannel_list, + grpc_connectivity_state_name(sd->pending_connectivity_state_unsafe), + p->shutdown, sd->subchannel_list->shutting_down, + grpc_error_string(error)); } // If the policy is shutting down, unref and return. if (p->shutdown) { @@ -412,15 +412,14 @@ static void pf_connectivity_changed_locked(grpc_exec_ctx *exec_ctx, void *arg, exec_ctx, p->subchannel_list, "selected_not_ready+switch_to_update"); p->subchannel_list = p->latest_pending_subchannel_list; p->latest_pending_subchannel_list = NULL; - grpc_lb_subchannel_data *new_sd = &p->subchannel_list->subchannels[ - p->subchannel_list->checking_subchannel]; - grpc_connectivity_state_set(exec_ctx, &p->state_tracker, - new_sd->curr_connectivity_state, - GRPC_ERROR_REF(error), - "selected_not_ready+switch_to_update"); + grpc_lb_subchannel_data *new_sd = + &p->subchannel_list + ->subchannels[p->subchannel_list->checking_subchannel]; + grpc_connectivity_state_set( + exec_ctx, &p->state_tracker, new_sd->curr_connectivity_state, + GRPC_ERROR_REF(error), "selected_not_ready+switch_to_update"); } else { - if (sd->curr_connectivity_state == - GRPC_CHANNEL_TRANSIENT_FAILURE) { + if (sd->curr_connectivity_state == GRPC_CHANNEL_TRANSIENT_FAILURE) { /* if the selected channel goes bad, we're done */ sd->curr_connectivity_state = GRPC_CHANNEL_SHUTDOWN; } @@ -471,8 +470,8 @@ static void pf_connectivity_changed_locked(grpc_exec_ctx *exec_ctx, void *arg, "connected"); p->selected = sd; if (GRPC_TRACER_ON(grpc_lb_pick_first_trace)) { - gpr_log(GPR_INFO, "Pick First %p selected subchannel %p", - (void *)p, (void *)sd->subchannel); + gpr_log(GPR_INFO, "Pick First %p selected subchannel %p", (void *)p, + (void *)sd->subchannel); } // Drop all other subchannels, since we are now connected. destroy_unselected_subchannels_locked(exec_ctx, p); @@ -497,8 +496,8 @@ static void pf_connectivity_changed_locked(grpc_exec_ctx *exec_ctx, void *arg, case GRPC_CHANNEL_TRANSIENT_FAILURE: { grpc_lb_subchannel_data_stop_connectivity_watch(exec_ctx, sd); sd->subchannel_list->checking_subchannel = - (sd->subchannel_list->checking_subchannel + 1) - % sd->subchannel_list->num_subchannels; + (sd->subchannel_list->checking_subchannel + 1) % + sd->subchannel_list->num_subchannels; // Case 1: Only set state to TRANSIENT_FAILURE if we've tried // all subchannels. if (sd->subchannel_list->checking_subchannel == 0 && @@ -507,8 +506,8 @@ static void pf_connectivity_changed_locked(grpc_exec_ctx *exec_ctx, void *arg, exec_ctx, &p->state_tracker, GRPC_CHANNEL_TRANSIENT_FAILURE, GRPC_ERROR_REF(error), "connecting_transient_failure"); } - sd = &sd->subchannel_list->subchannels[ - sd->subchannel_list->checking_subchannel]; + sd = &sd->subchannel_list + ->subchannels[sd->subchannel_list->checking_subchannel]; sd->curr_connectivity_state = grpc_subchannel_check_connectivity(sd->subchannel, &error); if (sd->curr_connectivity_state == GRPC_CHANNEL_TRANSIENT_FAILURE) { @@ -550,10 +549,10 @@ static void pf_connectivity_changed_locked(grpc_exec_ctx *exec_ctx, void *arg, } // Advance to next subchannel and check its state. sd->subchannel_list->checking_subchannel = - (sd->subchannel_list->checking_subchannel + 1) - % sd->subchannel_list->num_subchannels; - sd = &sd->subchannel_list->subchannels[ - sd->subchannel_list->checking_subchannel]; + (sd->subchannel_list->checking_subchannel + 1) % + sd->subchannel_list->num_subchannels; + sd = &sd->subchannel_list + ->subchannels[sd->subchannel_list->checking_subchannel]; sd->curr_connectivity_state = grpc_subchannel_check_connectivity(sd->subchannel, &error); if (sd->curr_connectivity_state == GRPC_CHANNEL_TRANSIENT_FAILURE) { diff --git a/src/core/ext/filters/client_channel/lb_policy/round_robin/round_robin.cc b/src/core/ext/filters/client_channel/lb_policy/round_robin/round_robin.cc index b25b9b86d88..1644fcc1bc2 100644 --- a/src/core/ext/filters/client_channel/lb_policy/round_robin/round_robin.cc +++ b/src/core/ext/filters/client_channel/lb_policy/round_robin/round_robin.cc @@ -285,8 +285,8 @@ static int rr_pick_locked(grpc_exec_ctx *exec_ctx, grpc_lb_policy *pol, /* readily available, report right away */ grpc_lb_subchannel_data *sd = &p->subchannel_list->subchannels[next_ready_index]; - *target = GRPC_CONNECTED_SUBCHANNEL_REF(sd->connected_subchannel, - "rr_picked"); + *target = + GRPC_CONNECTED_SUBCHANNEL_REF(sd->connected_subchannel, "rr_picked"); if (user_data != NULL) { *user_data = sd->user_data; } diff --git a/src/core/ext/filters/client_channel/lb_policy/subchannel_list.cc b/src/core/ext/filters/client_channel/lb_policy/subchannel_list.cc index d99fc48087e..8d7e084a2e0 100644 --- a/src/core/ext/filters/client_channel/lb_policy/subchannel_list.cc +++ b/src/core/ext/filters/client_channel/lb_policy/subchannel_list.cc @@ -153,13 +153,11 @@ grpc_lb_subchannel_list *grpc_lb_subchannel_list_create( GRPC_TRACER_ON(grpc_lb_pick_first_trace)) { char *address_uri = grpc_sockaddr_to_uri(&addresses->addresses[i].address); - gpr_log( - GPR_DEBUG, - "[LB %p] subchannel list %p index %" PRIdPTR - ": Created subchannel %p for address uri %s; " - "initial connectivity state: %s", - p, subchannel_list, subchannel_index, subchannel, address_uri, - grpc_connectivity_state_name(subchannel_connectivity_state)); + gpr_log(GPR_DEBUG, "[LB %p] subchannel list %p index %" PRIdPTR + ": Created subchannel %p for address uri %s; " + "initial connectivity state: %s", + p, subchannel_list, subchannel_index, subchannel, address_uri, + grpc_connectivity_state_name(subchannel_connectivity_state)); gpr_free(address_uri); } grpc_lb_subchannel_data *sd = @@ -253,8 +251,8 @@ static void grpc_lb_subchannel_data_cancel_connectivity_watch( (size_t)(sd - sd->subchannel_list->subchannels), sd->subchannel_list->num_subchannels, sd->subchannel, reason); } - grpc_subchannel_notify_on_state_change( - exec_ctx, sd->subchannel, NULL, NULL, &sd->connectivity_changed_closure); + grpc_subchannel_notify_on_state_change(exec_ctx, sd->subchannel, NULL, NULL, + &sd->connectivity_changed_closure); } void grpc_lb_subchannel_list_shutdown_and_unref( diff --git a/src/core/ext/filters/client_channel/lb_policy/subchannel_list.h b/src/core/ext/filters/client_channel/lb_policy/subchannel_list.h index 1e3a921c65a..cf872afbe24 100644 --- a/src/core/ext/filters/client_channel/lb_policy/subchannel_list.h +++ b/src/core/ext/filters/client_channel/lb_policy/subchannel_list.h @@ -68,8 +68,9 @@ typedef struct { } grpc_lb_subchannel_data; // Unrefs the subchannel contained in sd. -void grpc_lb_subchannel_data_unref_subchannel( - grpc_exec_ctx *exec_ctx, grpc_lb_subchannel_data *sd, const char *reason); +void grpc_lb_subchannel_data_unref_subchannel(grpc_exec_ctx *exec_ctx, + grpc_lb_subchannel_data *sd, + const char *reason); // Starts watching the connectivity state of the subchannel. // The connectivity_changed_cb callback must invoke either From 7ba40baeb1821fd312cb7d03c8e9e2383869120b Mon Sep 17 00:00:00 2001 From: "Mark D. Roth" Date: Tue, 10 Oct 2017 13:17:13 -0700 Subject: [PATCH 05/47] Fix crashes and asan bugs. --- .../lb_policy/pick_first/pick_first.cc | 42 ++++++++++--------- .../lb_policy/subchannel_list.cc | 2 +- 2 files changed, 24 insertions(+), 20 deletions(-) diff --git a/src/core/ext/filters/client_channel/lb_policy/pick_first/pick_first.cc b/src/core/ext/filters/client_channel/lb_policy/pick_first/pick_first.cc index 8119377504c..f321fec444c 100644 --- a/src/core/ext/filters/client_channel/lb_policy/pick_first/pick_first.cc +++ b/src/core/ext/filters/client_channel/lb_policy/pick_first/pick_first.cc @@ -397,10 +397,6 @@ static void pf_connectivity_changed_locked(grpc_exec_ctx *exec_ctx, void *arg, sd->subchannel_list == p->latest_pending_subchannel_list); // Update state counters. sd->curr_connectivity_state = sd->pending_connectivity_state_unsafe; - if (sd->curr_connectivity_state == GRPC_CHANNEL_SHUTDOWN) { - ++sd->subchannel_list->num_shutdown; - } - sd->prev_connectivity_state = sd->curr_connectivity_state; // Handle updates for the currently selected subchannel. if (p->selected == sd) { // If the new state is anything other than READY and there is a @@ -447,6 +443,10 @@ static void pf_connectivity_changed_locked(grpc_exec_ctx *exec_ctx, void *arg, // for a subchannel in p->latest_pending_subchannel_list. The // goal here is to find a subchannel from the update that we can // select in place of the current one. + if (sd->curr_connectivity_state == GRPC_CHANNEL_TRANSIENT_FAILURE || + sd->curr_connectivity_state == GRPC_CHANNEL_SHUTDOWN) { + grpc_lb_subchannel_data_stop_connectivity_watch(exec_ctx, sd); + } while (true) { switch (sd->curr_connectivity_state) { case GRPC_CHANNEL_INIT: @@ -494,10 +494,13 @@ static void pf_connectivity_changed_locked(grpc_exec_ctx *exec_ctx, void *arg, return; } case GRPC_CHANNEL_TRANSIENT_FAILURE: { - grpc_lb_subchannel_data_stop_connectivity_watch(exec_ctx, sd); - sd->subchannel_list->checking_subchannel = - (sd->subchannel_list->checking_subchannel + 1) % - sd->subchannel_list->num_subchannels; + do { + sd->subchannel_list->checking_subchannel = + (sd->subchannel_list->checking_subchannel + 1) % + sd->subchannel_list->num_subchannels; + sd = &sd->subchannel_list + ->subchannels[sd->subchannel_list->checking_subchannel]; + } while (sd->subchannel == NULL); // Case 1: Only set state to TRANSIENT_FAILURE if we've tried // all subchannels. if (sd->subchannel_list->checking_subchannel == 0 && @@ -506,10 +509,9 @@ static void pf_connectivity_changed_locked(grpc_exec_ctx *exec_ctx, void *arg, exec_ctx, &p->state_tracker, GRPC_CHANNEL_TRANSIENT_FAILURE, GRPC_ERROR_REF(error), "connecting_transient_failure"); } - sd = &sd->subchannel_list - ->subchannels[sd->subchannel_list->checking_subchannel]; sd->curr_connectivity_state = grpc_subchannel_check_connectivity(sd->subchannel, &error); + GRPC_ERROR_UNREF(error); if (sd->curr_connectivity_state == GRPC_CHANNEL_TRANSIENT_FAILURE) { // Reuses the connectivity refs from the previous watch. grpc_lb_subchannel_data_start_connectivity_watch(exec_ctx, sd); @@ -530,11 +532,18 @@ static void pf_connectivity_changed_locked(grpc_exec_ctx *exec_ctx, void *arg, return; } case GRPC_CHANNEL_SHUTDOWN: { - grpc_lb_subchannel_data_stop_connectivity_watch(exec_ctx, sd); grpc_lb_subchannel_data_unref_subchannel(exec_ctx, sd, "pf_candidate_shutdown"); - if (sd->subchannel_list->num_shutdown == - sd->subchannel_list->num_subchannels) { + // Advance to next subchannel and check its state. + grpc_lb_subchannel_data *original_sd = sd; + do { + sd->subchannel_list->checking_subchannel = + (sd->subchannel_list->checking_subchannel + 1) % + sd->subchannel_list->num_subchannels; + sd = &sd->subchannel_list + ->subchannels[sd->subchannel_list->checking_subchannel]; + } while (sd->subchannel == NULL && sd != original_sd); + if (sd == original_sd) { grpc_lb_subchannel_list_unref_for_connectivity_watch( exec_ctx, sd->subchannel_list, "pf_candidate_shutdown"); shutdown_locked(exec_ctx, p, @@ -547,14 +556,9 @@ static void pf_connectivity_changed_locked(grpc_exec_ctx *exec_ctx, void *arg, exec_ctx, &p->state_tracker, GRPC_CHANNEL_TRANSIENT_FAILURE, GRPC_ERROR_REF(error), "subchannel_failed"); } - // Advance to next subchannel and check its state. - sd->subchannel_list->checking_subchannel = - (sd->subchannel_list->checking_subchannel + 1) % - sd->subchannel_list->num_subchannels; - sd = &sd->subchannel_list - ->subchannels[sd->subchannel_list->checking_subchannel]; sd->curr_connectivity_state = grpc_subchannel_check_connectivity(sd->subchannel, &error); + GRPC_ERROR_UNREF(error); if (sd->curr_connectivity_state == GRPC_CHANNEL_TRANSIENT_FAILURE) { // Reuses the connectivity refs from the previous watch. grpc_lb_subchannel_data_start_connectivity_watch(exec_ctx, sd); diff --git a/src/core/ext/filters/client_channel/lb_policy/subchannel_list.cc b/src/core/ext/filters/client_channel/lb_policy/subchannel_list.cc index 8d7e084a2e0..c30416d1241 100644 --- a/src/core/ext/filters/client_channel/lb_policy/subchannel_list.cc +++ b/src/core/ext/filters/client_channel/lb_policy/subchannel_list.cc @@ -79,7 +79,6 @@ void grpc_lb_subchannel_data_start_connectivity_watch( void grpc_lb_subchannel_data_stop_connectivity_watch( grpc_exec_ctx *exec_ctx, grpc_lb_subchannel_data *sd) { - GPR_ASSERT(sd->connectivity_notification_pending); if (GRPC_TRACER_ON(grpc_lb_round_robin_trace) || GRPC_TRACER_ON(grpc_lb_pick_first_trace)) { gpr_log(GPR_DEBUG, @@ -89,6 +88,7 @@ void grpc_lb_subchannel_data_stop_connectivity_watch( (size_t)(sd - sd->subchannel_list->subchannels), sd->subchannel_list->num_subchannels, sd->subchannel); } + GPR_ASSERT(sd->connectivity_notification_pending); sd->connectivity_notification_pending = false; } From 0c11ebaa6c7e2cf0c1f49fc0f094ca9fe98c67e4 Mon Sep 17 00:00:00 2001 From: "Mark D. Roth" Date: Tue, 10 Oct 2017 15:02:43 -0700 Subject: [PATCH 06/47] Fix crash when not able to create subchannel. --- .../client_channel/lb_policy/subchannel_list.cc | 14 ++++++++++++++ 1 file changed, 14 insertions(+) diff --git a/src/core/ext/filters/client_channel/lb_policy/subchannel_list.cc b/src/core/ext/filters/client_channel/lb_policy/subchannel_list.cc index c30416d1241..df23a32f97f 100644 --- a/src/core/ext/filters/client_channel/lb_policy/subchannel_list.cc +++ b/src/core/ext/filters/client_channel/lb_policy/subchannel_list.cc @@ -129,6 +129,20 @@ grpc_lb_subchannel_list *grpc_lb_subchannel_list_create( grpc_subchannel *subchannel = grpc_client_channel_factory_create_subchannel( exec_ctx, args->client_channel_factory, &sc_args); grpc_channel_args_destroy(exec_ctx, new_args); + if (subchannel == NULL) { + // Subchannel could not be created. + if (GRPC_TRACER_ON(grpc_lb_round_robin_trace) || + GRPC_TRACER_ON(grpc_lb_pick_first_trace)) { + char *address_uri = + grpc_sockaddr_to_uri(&addresses->addresses[i].address); + gpr_log(GPR_DEBUG, + "[LB %p] could not create subchannel for address uri %s, " + "ignoring", + subchannel_list->policy, address_uri); + gpr_free(address_uri); + } + continue; + } grpc_error *error; // Get the connectivity state of the subchannel. Already existing ones may // be in a state other than INIT. From 901bb4f5bce2b924f8d75a710920aeb45221809c Mon Sep 17 00:00:00 2001 From: "Mark D. Roth" Date: Wed, 11 Oct 2017 08:49:07 -0700 Subject: [PATCH 07/47] Improve tracing of subchannel_list code. --- .../lb_policy/pick_first/pick_first.cc | 3 +- .../lb_policy/round_robin/round_robin.cc | 3 +- .../lb_policy/subchannel_list.cc | 103 +++++++++--------- .../lb_policy/subchannel_list.h | 5 +- 4 files changed, 57 insertions(+), 57 deletions(-) diff --git a/src/core/ext/filters/client_channel/lb_policy/pick_first/pick_first.cc b/src/core/ext/filters/client_channel/lb_policy/pick_first/pick_first.cc index f321fec444c..d861746999d 100644 --- a/src/core/ext/filters/client_channel/lb_policy/pick_first/pick_first.cc +++ b/src/core/ext/filters/client_channel/lb_policy/pick_first/pick_first.cc @@ -265,7 +265,8 @@ static void pf_update_locked(grpc_exec_ctx *exec_ctx, grpc_lb_policy *policy, (void *)p, (unsigned long)addresses->num_addresses); } grpc_lb_subchannel_list *subchannel_list = grpc_lb_subchannel_list_create( - exec_ctx, &p->base, addresses, args, pf_connectivity_changed_locked); + exec_ctx, &p->base, &grpc_lb_pick_first_trace, addresses, args, + pf_connectivity_changed_locked); if (subchannel_list->num_subchannels == 0) { // Empty update or no valid subchannels. Unsubscribe from all current // subchannels and put the channel in TRANSIENT_FAILURE. diff --git a/src/core/ext/filters/client_channel/lb_policy/round_robin/round_robin.cc b/src/core/ext/filters/client_channel/lb_policy/round_robin/round_robin.cc index 1644fcc1bc2..499631f1b18 100644 --- a/src/core/ext/filters/client_channel/lb_policy/round_robin/round_robin.cc +++ b/src/core/ext/filters/client_channel/lb_policy/round_robin/round_robin.cc @@ -586,7 +586,8 @@ static void rr_update_locked(grpc_exec_ctx *exec_ctx, grpc_lb_policy *policy, } grpc_lb_addresses *addresses = (grpc_lb_addresses *)arg->value.pointer.p; grpc_lb_subchannel_list *subchannel_list = grpc_lb_subchannel_list_create( - exec_ctx, &p->base, addresses, args, rr_connectivity_changed_locked); + exec_ctx, &p->base, &grpc_lb_round_robin_trace, addresses, args, + rr_connectivity_changed_locked); if (subchannel_list->num_subchannels == 0) { grpc_connectivity_state_set( exec_ctx, &p->state_tracker, GRPC_CHANNEL_TRANSIENT_FAILURE, diff --git a/src/core/ext/filters/client_channel/lb_policy/subchannel_list.cc b/src/core/ext/filters/client_channel/lb_policy/subchannel_list.cc index df23a32f97f..02c8460b277 100644 --- a/src/core/ext/filters/client_channel/lb_policy/subchannel_list.cc +++ b/src/core/ext/filters/client_channel/lb_policy/subchannel_list.cc @@ -28,19 +28,16 @@ #include "src/core/lib/iomgr/sockaddr_utils.h" #include "src/core/lib/transport/connectivity_state.h" -extern grpc_tracer_flag grpc_lb_round_robin_trace; -extern grpc_tracer_flag grpc_lb_pick_first_trace; - void grpc_lb_subchannel_data_unref_subchannel(grpc_exec_ctx *exec_ctx, grpc_lb_subchannel_data *sd, const char *reason) { if (sd->subchannel != NULL) { - if (GRPC_TRACER_ON(grpc_lb_round_robin_trace) || - GRPC_TRACER_ON(grpc_lb_pick_first_trace)) { + if (GRPC_TRACER_ON(*sd->subchannel_list->tracer)) { gpr_log(GPR_DEBUG, - "[LB %p] subchannel list %p index %" PRIdPTR " of %" PRIdPTR + "[%s %p] subchannel list %p index %" PRIdPTR " of %" PRIdPTR " (subchannel %p): unreffing subchannel", - sd->subchannel_list->policy, sd->subchannel_list, + sd->subchannel_list->tracer->name, sd->subchannel_list->policy, + sd->subchannel_list, (size_t)(sd - sd->subchannel_list->subchannels), sd->subchannel_list->num_subchannels, sd->subchannel); } @@ -61,12 +58,12 @@ void grpc_lb_subchannel_data_unref_subchannel(grpc_exec_ctx *exec_ctx, void grpc_lb_subchannel_data_start_connectivity_watch( grpc_exec_ctx *exec_ctx, grpc_lb_subchannel_data *sd) { - if (GRPC_TRACER_ON(grpc_lb_round_robin_trace) || - GRPC_TRACER_ON(grpc_lb_pick_first_trace)) { + if (GRPC_TRACER_ON(*sd->subchannel_list->tracer)) { gpr_log(GPR_DEBUG, - "[LB %p] subchannel list %p index %" PRIdPTR " of %" PRIdPTR + "[%s %p] subchannel list %p index %" PRIdPTR " of %" PRIdPTR " (subchannel %p): requesting connectivity change notification", - sd->subchannel_list->policy, sd->subchannel_list, + sd->subchannel_list->tracer->name, sd->subchannel_list->policy, + sd->subchannel_list, (size_t)(sd - sd->subchannel_list->subchannels), sd->subchannel_list->num_subchannels, sd->subchannel); } @@ -79,12 +76,12 @@ void grpc_lb_subchannel_data_start_connectivity_watch( void grpc_lb_subchannel_data_stop_connectivity_watch( grpc_exec_ctx *exec_ctx, grpc_lb_subchannel_data *sd) { - if (GRPC_TRACER_ON(grpc_lb_round_robin_trace) || - GRPC_TRACER_ON(grpc_lb_pick_first_trace)) { + if (GRPC_TRACER_ON(*sd->subchannel_list->tracer)) { gpr_log(GPR_DEBUG, - "[LB %p] subchannel list %p index %" PRIdPTR " of %" PRIdPTR + "[%s %p] subchannel list %p index %" PRIdPTR " of %" PRIdPTR " (subchannel %p): stopping connectivity watch", - sd->subchannel_list->policy, sd->subchannel_list, + sd->subchannel_list->tracer->name, sd->subchannel_list->policy, + sd->subchannel_list, (size_t)(sd - sd->subchannel_list->subchannels), sd->subchannel_list->num_subchannels, sd->subchannel); } @@ -93,18 +90,18 @@ void grpc_lb_subchannel_data_stop_connectivity_watch( } grpc_lb_subchannel_list *grpc_lb_subchannel_list_create( - grpc_exec_ctx *exec_ctx, grpc_lb_policy *p, + grpc_exec_ctx *exec_ctx, grpc_lb_policy *p, grpc_tracer_flag *tracer, const grpc_lb_addresses *addresses, const grpc_lb_policy_args *args, grpc_iomgr_cb_func connectivity_changed_cb) { grpc_lb_subchannel_list *subchannel_list = (grpc_lb_subchannel_list *)gpr_zalloc(sizeof(*subchannel_list)); - if (GRPC_TRACER_ON(grpc_lb_round_robin_trace) || - GRPC_TRACER_ON(grpc_lb_pick_first_trace)) { + if (GRPC_TRACER_ON(*tracer)) { gpr_log(GPR_DEBUG, - "[LB %p] Creating subchannel list %p for %" PRIdPTR " subchannels", - p, subchannel_list, addresses->num_addresses); + "[%s %p] Creating subchannel list %p for %" PRIdPTR " subchannels", + tracer->name, p, subchannel_list, addresses->num_addresses); } subchannel_list->policy = p; + subchannel_list->tracer = tracer; gpr_ref_init(&subchannel_list->refcount, 1); subchannel_list->subchannels = (grpc_lb_subchannel_data *)gpr_zalloc( sizeof(grpc_lb_subchannel_data) * addresses->num_addresses); @@ -131,14 +128,13 @@ grpc_lb_subchannel_list *grpc_lb_subchannel_list_create( grpc_channel_args_destroy(exec_ctx, new_args); if (subchannel == NULL) { // Subchannel could not be created. - if (GRPC_TRACER_ON(grpc_lb_round_robin_trace) || - GRPC_TRACER_ON(grpc_lb_pick_first_trace)) { + if (GRPC_TRACER_ON(*tracer)) { char *address_uri = grpc_sockaddr_to_uri(&addresses->addresses[i].address); gpr_log(GPR_DEBUG, - "[LB %p] could not create subchannel for address uri %s, " + "[%s %p] could not create subchannel for address uri %s, " "ignoring", - subchannel_list->policy, address_uri); + tracer->name, subchannel_list->policy, address_uri); gpr_free(address_uri); } continue; @@ -150,27 +146,26 @@ grpc_lb_subchannel_list *grpc_lb_subchannel_list_create( grpc_subchannel_check_connectivity(subchannel, &error); if (error != GRPC_ERROR_NONE) { // The subchannel is in error (e.g. shutting down). Ignore it. - if (GRPC_TRACER_ON(grpc_lb_round_robin_trace) || - GRPC_TRACER_ON(grpc_lb_pick_first_trace)) { + if (GRPC_TRACER_ON(*tracer)) { char *address_uri = grpc_sockaddr_to_uri(&addresses->addresses[i].address); gpr_log(GPR_DEBUG, - "[LB %p] subchannel for address uri %s shutting down, ignoring", - subchannel_list->policy, address_uri); + "[%s %p] subchannel for address uri %s shutting down, ignoring", + tracer->name, subchannel_list->policy, address_uri); gpr_free(address_uri); } GRPC_SUBCHANNEL_UNREF(exec_ctx, subchannel, "new_sc_connectivity_error"); GRPC_ERROR_UNREF(error); continue; } - if (GRPC_TRACER_ON(grpc_lb_round_robin_trace) || - GRPC_TRACER_ON(grpc_lb_pick_first_trace)) { + if (GRPC_TRACER_ON(*tracer)) { char *address_uri = grpc_sockaddr_to_uri(&addresses->addresses[i].address); - gpr_log(GPR_DEBUG, "[LB %p] subchannel list %p index %" PRIdPTR + gpr_log(GPR_DEBUG, "[%s %p] subchannel list %p index %" PRIdPTR ": Created subchannel %p for address uri %s; " "initial connectivity state: %s", - p, subchannel_list, subchannel_index, subchannel, address_uri, + tracer->name, p, subchannel_list, subchannel_index, subchannel, + address_uri, grpc_connectivity_state_name(subchannel_connectivity_state)); gpr_free(address_uri); } @@ -199,10 +194,10 @@ grpc_lb_subchannel_list *grpc_lb_subchannel_list_create( static void subchannel_list_destroy(grpc_exec_ctx *exec_ctx, grpc_lb_subchannel_list *subchannel_list) { - if (GRPC_TRACER_ON(grpc_lb_round_robin_trace) || - GRPC_TRACER_ON(grpc_lb_pick_first_trace)) { - gpr_log(GPR_DEBUG, "[LB %p] Destroying subchannel_list %p", - subchannel_list->policy, subchannel_list); + if (GRPC_TRACER_ON(*subchannel_list->tracer)) { + gpr_log(GPR_DEBUG, "[%s %p] Destroying subchannel_list %p", + subchannel_list->tracer->name, subchannel_list->policy, + subchannel_list); } for (size_t i = 0; i < subchannel_list->num_subchannels; i++) { grpc_lb_subchannel_data *sd = &subchannel_list->subchannels[i]; @@ -216,12 +211,12 @@ static void subchannel_list_destroy(grpc_exec_ctx *exec_ctx, void grpc_lb_subchannel_list_ref(grpc_lb_subchannel_list *subchannel_list, const char *reason) { gpr_ref_non_zero(&subchannel_list->refcount); - if (GRPC_TRACER_ON(grpc_lb_round_robin_trace) || - GRPC_TRACER_ON(grpc_lb_pick_first_trace)) { + if (GRPC_TRACER_ON(*subchannel_list->tracer)) { const gpr_atm count = gpr_atm_acq_load(&subchannel_list->refcount.count); - gpr_log(GPR_DEBUG, "[LB %p] subchannel_list %p REF %lu->%lu (%s)", - subchannel_list->policy, subchannel_list, - (unsigned long)(count - 1), (unsigned long)count, reason); + gpr_log(GPR_DEBUG, "[%s %p] subchannel_list %p REF %lu->%lu (%s)", + subchannel_list->tracer->name, subchannel_list->policy, + subchannel_list, (unsigned long)(count - 1), + (unsigned long)count, reason); } } @@ -229,12 +224,12 @@ void grpc_lb_subchannel_list_unref(grpc_exec_ctx *exec_ctx, grpc_lb_subchannel_list *subchannel_list, const char *reason) { const bool done = gpr_unref(&subchannel_list->refcount); - if (GRPC_TRACER_ON(grpc_lb_round_robin_trace) || - GRPC_TRACER_ON(grpc_lb_pick_first_trace)) { + if (GRPC_TRACER_ON(*subchannel_list->tracer)) { const gpr_atm count = gpr_atm_acq_load(&subchannel_list->refcount.count); - gpr_log(GPR_DEBUG, "[LB %p] subchannel_list %p UNREF %lu->%lu (%s)", - subchannel_list->policy, subchannel_list, - (unsigned long)(count + 1), (unsigned long)count, reason); + gpr_log(GPR_DEBUG, "[%s %p] subchannel_list %p UNREF %lu->%lu (%s)", + subchannel_list->tracer->name, subchannel_list->policy, + subchannel_list, (unsigned long)(count + 1), + (unsigned long)count, reason); } if (done) { subchannel_list_destroy(exec_ctx, subchannel_list); @@ -256,12 +251,12 @@ void grpc_lb_subchannel_list_unref_for_connectivity_watch( static void grpc_lb_subchannel_data_cancel_connectivity_watch( grpc_exec_ctx *exec_ctx, grpc_lb_subchannel_data *sd, const char *reason) { - if (GRPC_TRACER_ON(grpc_lb_round_robin_trace) || - GRPC_TRACER_ON(grpc_lb_pick_first_trace)) { + if (GRPC_TRACER_ON(*sd->subchannel_list->tracer)) { gpr_log(GPR_DEBUG, - "[LB %p] subchannel list %p index %" PRIdPTR " of %" PRIdPTR + "[%s %p] subchannel list %p index %" PRIdPTR " of %" PRIdPTR " (subchannel %p): canceling connectivity watch (%s)", - sd->subchannel_list->policy, sd->subchannel_list, + sd->subchannel_list->tracer->name, sd->subchannel_list->policy, + sd->subchannel_list, (size_t)(sd - sd->subchannel_list->subchannels), sd->subchannel_list->num_subchannels, sd->subchannel, reason); } @@ -272,10 +267,10 @@ static void grpc_lb_subchannel_data_cancel_connectivity_watch( void grpc_lb_subchannel_list_shutdown_and_unref( grpc_exec_ctx *exec_ctx, grpc_lb_subchannel_list *subchannel_list, const char *reason) { - if (GRPC_TRACER_ON(grpc_lb_round_robin_trace) || - GRPC_TRACER_ON(grpc_lb_pick_first_trace)) { - gpr_log(GPR_DEBUG, "[LB %p] Shutting down subchannel_list %p (%s)", - subchannel_list->policy, subchannel_list, reason); + if (GRPC_TRACER_ON(*subchannel_list->tracer)) { + gpr_log(GPR_DEBUG, "[%s %p] Shutting down subchannel_list %p (%s)", + subchannel_list->tracer->name, subchannel_list->policy, + subchannel_list, reason); } GPR_ASSERT(!subchannel_list->shutting_down); subchannel_list->shutting_down = true; diff --git a/src/core/ext/filters/client_channel/lb_policy/subchannel_list.h b/src/core/ext/filters/client_channel/lb_policy/subchannel_list.h index cf872afbe24..814180388dd 100644 --- a/src/core/ext/filters/client_channel/lb_policy/subchannel_list.h +++ b/src/core/ext/filters/client_channel/lb_policy/subchannel_list.h @@ -21,6 +21,7 @@ #include "src/core/ext/filters/client_channel/lb_policy_registry.h" #include "src/core/ext/filters/client_channel/subchannel.h" +#include "src/core/lib/debug/trace.h" #include "src/core/lib/transport/connectivity_state.h" // TODO(roth): This code is intended to be shared between pick_first and @@ -87,6 +88,8 @@ struct grpc_lb_subchannel_list { /** backpointer to owning policy */ grpc_lb_policy *policy; + grpc_tracer_flag *tracer; + /** all our subchannels */ size_t num_subchannels; grpc_lb_subchannel_data *subchannels; @@ -118,7 +121,7 @@ struct grpc_lb_subchannel_list { }; grpc_lb_subchannel_list *grpc_lb_subchannel_list_create( - grpc_exec_ctx *exec_ctx, grpc_lb_policy *p, + grpc_exec_ctx *exec_ctx, grpc_lb_policy *p, grpc_tracer_flag *tracer, const grpc_lb_addresses *addresses, const grpc_lb_policy_args *args, grpc_iomgr_cb_func connectivity_changed_cb); From 9843ec78a72cced1b304487c8eface166c6fc0a6 Mon Sep 17 00:00:00 2001 From: "Mark D. Roth" Date: Wed, 11 Oct 2017 13:00:04 -0700 Subject: [PATCH 08/47] clang-format --- .../lb_policy/subchannel_list.cc | 47 +++++++++---------- 1 file changed, 22 insertions(+), 25 deletions(-) diff --git a/src/core/ext/filters/client_channel/lb_policy/subchannel_list.cc b/src/core/ext/filters/client_channel/lb_policy/subchannel_list.cc index 02c8460b277..db057e295d0 100644 --- a/src/core/ext/filters/client_channel/lb_policy/subchannel_list.cc +++ b/src/core/ext/filters/client_channel/lb_policy/subchannel_list.cc @@ -33,13 +33,12 @@ void grpc_lb_subchannel_data_unref_subchannel(grpc_exec_ctx *exec_ctx, const char *reason) { if (sd->subchannel != NULL) { if (GRPC_TRACER_ON(*sd->subchannel_list->tracer)) { - gpr_log(GPR_DEBUG, - "[%s %p] subchannel list %p index %" PRIdPTR " of %" PRIdPTR - " (subchannel %p): unreffing subchannel", - sd->subchannel_list->tracer->name, sd->subchannel_list->policy, - sd->subchannel_list, - (size_t)(sd - sd->subchannel_list->subchannels), - sd->subchannel_list->num_subchannels, sd->subchannel); + gpr_log( + GPR_DEBUG, "[%s %p] subchannel list %p index %" PRIdPTR + " of %" PRIdPTR " (subchannel %p): unreffing subchannel", + sd->subchannel_list->tracer->name, sd->subchannel_list->policy, + sd->subchannel_list, (size_t)(sd - sd->subchannel_list->subchannels), + sd->subchannel_list->num_subchannels, sd->subchannel); } GRPC_SUBCHANNEL_UNREF(exec_ctx, sd->subchannel, reason); sd->subchannel = NULL; @@ -77,13 +76,12 @@ void grpc_lb_subchannel_data_start_connectivity_watch( void grpc_lb_subchannel_data_stop_connectivity_watch( grpc_exec_ctx *exec_ctx, grpc_lb_subchannel_data *sd) { if (GRPC_TRACER_ON(*sd->subchannel_list->tracer)) { - gpr_log(GPR_DEBUG, - "[%s %p] subchannel list %p index %" PRIdPTR " of %" PRIdPTR - " (subchannel %p): stopping connectivity watch", - sd->subchannel_list->tracer->name, sd->subchannel_list->policy, - sd->subchannel_list, - (size_t)(sd - sd->subchannel_list->subchannels), - sd->subchannel_list->num_subchannels, sd->subchannel); + gpr_log( + GPR_DEBUG, "[%s %p] subchannel list %p index %" PRIdPTR " of %" PRIdPTR + " (subchannel %p): stopping connectivity watch", + sd->subchannel_list->tracer->name, sd->subchannel_list->policy, + sd->subchannel_list, (size_t)(sd - sd->subchannel_list->subchannels), + sd->subchannel_list->num_subchannels, sd->subchannel); } GPR_ASSERT(sd->connectivity_notification_pending); sd->connectivity_notification_pending = false; @@ -215,8 +213,8 @@ void grpc_lb_subchannel_list_ref(grpc_lb_subchannel_list *subchannel_list, const gpr_atm count = gpr_atm_acq_load(&subchannel_list->refcount.count); gpr_log(GPR_DEBUG, "[%s %p] subchannel_list %p REF %lu->%lu (%s)", subchannel_list->tracer->name, subchannel_list->policy, - subchannel_list, (unsigned long)(count - 1), - (unsigned long)count, reason); + subchannel_list, (unsigned long)(count - 1), (unsigned long)count, + reason); } } @@ -228,8 +226,8 @@ void grpc_lb_subchannel_list_unref(grpc_exec_ctx *exec_ctx, const gpr_atm count = gpr_atm_acq_load(&subchannel_list->refcount.count); gpr_log(GPR_DEBUG, "[%s %p] subchannel_list %p UNREF %lu->%lu (%s)", subchannel_list->tracer->name, subchannel_list->policy, - subchannel_list, (unsigned long)(count + 1), - (unsigned long)count, reason); + subchannel_list, (unsigned long)(count + 1), (unsigned long)count, + reason); } if (done) { subchannel_list_destroy(exec_ctx, subchannel_list); @@ -252,13 +250,12 @@ void grpc_lb_subchannel_list_unref_for_connectivity_watch( static void grpc_lb_subchannel_data_cancel_connectivity_watch( grpc_exec_ctx *exec_ctx, grpc_lb_subchannel_data *sd, const char *reason) { if (GRPC_TRACER_ON(*sd->subchannel_list->tracer)) { - gpr_log(GPR_DEBUG, - "[%s %p] subchannel list %p index %" PRIdPTR " of %" PRIdPTR - " (subchannel %p): canceling connectivity watch (%s)", - sd->subchannel_list->tracer->name, sd->subchannel_list->policy, - sd->subchannel_list, - (size_t)(sd - sd->subchannel_list->subchannels), - sd->subchannel_list->num_subchannels, sd->subchannel, reason); + gpr_log( + GPR_DEBUG, "[%s %p] subchannel list %p index %" PRIdPTR " of %" PRIdPTR + " (subchannel %p): canceling connectivity watch (%s)", + sd->subchannel_list->tracer->name, sd->subchannel_list->policy, + sd->subchannel_list, (size_t)(sd - sd->subchannel_list->subchannels), + sd->subchannel_list->num_subchannels, sd->subchannel, reason); } grpc_subchannel_notify_on_state_change(exec_ctx, sd->subchannel, NULL, NULL, &sd->connectivity_changed_closure); From 5132d0e6092d34840e583dac0ef0dd01f4226a63 Mon Sep 17 00:00:00 2001 From: "Mark D. Roth" Date: Fri, 13 Oct 2017 13:20:52 -0700 Subject: [PATCH 09/47] Code review changes. --- .../lb_policy/pick_first/pick_first.cc | 8 ++++---- .../lb_policy/round_robin/round_robin.cc | 7 +++---- .../client_channel/lb_policy/subchannel_list.cc | 12 +++++------- 3 files changed, 12 insertions(+), 15 deletions(-) diff --git a/src/core/ext/filters/client_channel/lb_policy/pick_first/pick_first.cc b/src/core/ext/filters/client_channel/lb_policy/pick_first/pick_first.cc index d861746999d..025ee290813 100644 --- a/src/core/ext/filters/client_channel/lb_policy/pick_first/pick_first.cc +++ b/src/core/ext/filters/client_channel/lb_policy/pick_first/pick_first.cc @@ -44,9 +44,9 @@ typedef struct { grpc_lb_policy base; /** all our subchannels */ grpc_lb_subchannel_list *subchannel_list; - /** Latest pending subchannel list. */ + /** latest pending subchannel list */ grpc_lb_subchannel_list *latest_pending_subchannel_list; - /** Selected subchannel in \a subchannel_list. */ + /** selected subchannel in \a subchannel_list */ grpc_lb_subchannel_data *selected; /** have we started picking? */ bool started_picking; @@ -351,7 +351,7 @@ static void pf_update_locked(grpc_exec_ctx *exec_ctx, grpc_lb_policy *policy, } // If we've started picking, start trying to connect to the first // subchannel in the new list. - if (p->started_picking && subchannel_list->num_subchannels > 0) { + if (p->started_picking) { grpc_lb_subchannel_list_ref_for_connectivity_watch( subchannel_list, "connectivity_watch+update"); grpc_lb_subchannel_data_start_connectivity_watch( @@ -396,7 +396,7 @@ static void pf_connectivity_changed_locked(grpc_exec_ctx *exec_ctx, void *arg, // either the current or latest pending subchannel lists. GPR_ASSERT(sd->subchannel_list == p->subchannel_list || sd->subchannel_list == p->latest_pending_subchannel_list); - // Update state counters. + // Update state. sd->curr_connectivity_state = sd->pending_connectivity_state_unsafe; // Handle updates for the currently selected subchannel. if (p->selected == sd) { diff --git a/src/core/ext/filters/client_channel/lb_policy/round_robin/round_robin.cc b/src/core/ext/filters/client_channel/lb_policy/round_robin/round_robin.cc index 499631f1b18..67361bfe5d9 100644 --- a/src/core/ext/filters/client_channel/lb_policy/round_robin/round_robin.cc +++ b/src/core/ext/filters/client_channel/lb_policy/round_robin/round_robin.cc @@ -436,7 +436,7 @@ static void rr_connectivity_changed_locked(grpc_exec_ctx *exec_ctx, void *arg, grpc_lb_subchannel_data_stop_connectivity_watch(exec_ctx, sd); grpc_lb_subchannel_data_unref_subchannel(exec_ctx, sd, "rr_sl_shutdown"); grpc_lb_subchannel_list_unref_for_connectivity_watch( - exec_ctx, sd->subchannel_list, "rr_shutdown"); + exec_ctx, sd->subchannel_list, "rr_sl_shutdown"); return; } // If we're still here, the notification must be for a subchannel in @@ -601,7 +601,7 @@ static void rr_update_locked(grpc_exec_ctx *exec_ctx, grpc_lb_policy *policy, return; } if (p->started_picking) { - if (p->latest_pending_subchannel_list != NULL && p->started_picking) { + if (p->latest_pending_subchannel_list != NULL) { if (GRPC_TRACER_ON(grpc_lb_round_robin_trace)) { gpr_log(GPR_DEBUG, "[RR %p] Shutting down latest pending subchannel list %p, " @@ -610,8 +610,7 @@ static void rr_update_locked(grpc_exec_ctx *exec_ctx, grpc_lb_policy *policy, (void *)subchannel_list); } grpc_lb_subchannel_list_shutdown_and_unref( - exec_ctx, p->latest_pending_subchannel_list, - "sl_outdated_dont_smash"); + exec_ctx, p->latest_pending_subchannel_list, "sl_outdated"); } p->latest_pending_subchannel_list = subchannel_list; for (size_t i = 0; i < subchannel_list->num_subchannels; ++i) { diff --git a/src/core/ext/filters/client_channel/lb_policy/subchannel_list.cc b/src/core/ext/filters/client_channel/lb_policy/subchannel_list.cc index db057e295d0..9a7ccedac17 100644 --- a/src/core/ext/filters/client_channel/lb_policy/subchannel_list.cc +++ b/src/core/ext/filters/client_channel/lb_policy/subchannel_list.cc @@ -103,11 +103,11 @@ grpc_lb_subchannel_list *grpc_lb_subchannel_list_create( gpr_ref_init(&subchannel_list->refcount, 1); subchannel_list->subchannels = (grpc_lb_subchannel_data *)gpr_zalloc( sizeof(grpc_lb_subchannel_data) * addresses->num_addresses); - /* We need to remove the LB addresses in order to be able to compare the - * subchannel keys of subchannels from a different batch of addresses. */ + // We need to remove the LB addresses in order to be able to compare the + // subchannel keys of subchannels from a different batch of addresses. static const char *keys_to_remove[] = {GRPC_ARG_SUBCHANNEL_ADDRESS, GRPC_ARG_LB_ADDRESSES}; - /* Create subchannels for addresses in the update. */ + // Create a subchannels for each address. grpc_subchannel_args sc_args; size_t subchannel_index = 0; for (size_t i = 0; i < addresses->num_addresses; i++) { @@ -174,10 +174,8 @@ grpc_lb_subchannel_list *grpc_lb_subchannel_list_create( GRPC_CLOSURE_INIT(&sd->connectivity_changed_closure, connectivity_changed_cb, sd, grpc_combiner_scheduler(args->combiner)); - /* use some sentinel value outside of the range of - * grpc_connectivity_state to signal an undefined previous state. We - * won't be referring to this value again and it'll be overwritten after - * the first call to rr_connectivity_changed_locked */ + // Use some sentinel value outside of the range of + // grpc_connectivity_state to signal an undefined previous state. sd->prev_connectivity_state = GRPC_CHANNEL_INIT; sd->curr_connectivity_state = subchannel_connectivity_state; sd->user_data_vtable = addresses->user_data_vtable; From 99f54e1572d27a7e7b80918c0cf3cd9614751886 Mon Sep 17 00:00:00 2001 From: "Mark D. Roth" Date: Mon, 16 Oct 2017 09:55:53 -0700 Subject: [PATCH 10/47] Code review changes. --- .../client_channel/lb_policy/pick_first/pick_first.cc | 5 +---- .../ext/filters/client_channel/lb_policy/subchannel_list.cc | 6 +++--- 2 files changed, 4 insertions(+), 7 deletions(-) diff --git a/src/core/ext/filters/client_channel/lb_policy/pick_first/pick_first.cc b/src/core/ext/filters/client_channel/lb_policy/pick_first/pick_first.cc index 025ee290813..970751ce2c7 100644 --- a/src/core/ext/filters/client_channel/lb_policy/pick_first/pick_first.cc +++ b/src/core/ext/filters/client_channel/lb_policy/pick_first/pick_first.cc @@ -409,11 +409,8 @@ static void pf_connectivity_changed_locked(grpc_exec_ctx *exec_ctx, void *arg, exec_ctx, p->subchannel_list, "selected_not_ready+switch_to_update"); p->subchannel_list = p->latest_pending_subchannel_list; p->latest_pending_subchannel_list = NULL; - grpc_lb_subchannel_data *new_sd = - &p->subchannel_list - ->subchannels[p->subchannel_list->checking_subchannel]; grpc_connectivity_state_set( - exec_ctx, &p->state_tracker, new_sd->curr_connectivity_state, + exec_ctx, &p->state_tracker, GRPC_CHANNEL_TRANSIENT_FAILURE, GRPC_ERROR_REF(error), "selected_not_ready+switch_to_update"); } else { if (sd->curr_connectivity_state == GRPC_CHANNEL_TRANSIENT_FAILURE) { diff --git a/src/core/ext/filters/client_channel/lb_policy/subchannel_list.cc b/src/core/ext/filters/client_channel/lb_policy/subchannel_list.cc index 9a7ccedac17..1d2eb395f02 100644 --- a/src/core/ext/filters/client_channel/lb_policy/subchannel_list.cc +++ b/src/core/ext/filters/client_channel/lb_policy/subchannel_list.cc @@ -107,7 +107,7 @@ grpc_lb_subchannel_list *grpc_lb_subchannel_list_create( // subchannel keys of subchannels from a different batch of addresses. static const char *keys_to_remove[] = {GRPC_ARG_SUBCHANNEL_ADDRESS, GRPC_ARG_LB_ADDRESSES}; - // Create a subchannels for each address. + // Create a subchannel for each address. grpc_subchannel_args sc_args; size_t subchannel_index = 0; for (size_t i = 0; i < addresses->num_addresses; i++) { @@ -245,7 +245,7 @@ void grpc_lb_subchannel_list_unref_for_connectivity_watch( grpc_lb_subchannel_list_unref(exec_ctx, subchannel_list, reason); } -static void grpc_lb_subchannel_data_cancel_connectivity_watch( +static void subchannel_data_cancel_connectivity_watch( grpc_exec_ctx *exec_ctx, grpc_lb_subchannel_data *sd, const char *reason) { if (GRPC_TRACER_ON(*sd->subchannel_list->tracer)) { gpr_log( @@ -275,7 +275,7 @@ void grpc_lb_subchannel_list_shutdown_and_unref( // the callback is responsible for unreffing the subchannel. // Otherwise, unref the subchannel directly. if (sd->connectivity_notification_pending) { - grpc_lb_subchannel_data_cancel_connectivity_watch(exec_ctx, sd, reason); + subchannel_data_cancel_connectivity_watch(exec_ctx, sd, reason); } else if (sd->subchannel != NULL) { grpc_lb_subchannel_data_unref_subchannel(exec_ctx, sd, reason); } From aadf9f4b8459702e6976b8fc8c3bffa0f321a082 Mon Sep 17 00:00:00 2001 From: "Mark D. Roth" Date: Thu, 19 Oct 2017 07:53:53 -0700 Subject: [PATCH 11/47] Code review changes. --- .../lb_policy/pick_first/pick_first.cc | 2 +- .../lb_policy/round_robin/round_robin.cc | 5 +---- .../lb_policy/subchannel_list.h | 20 +++++++++---------- 3 files changed, 12 insertions(+), 15 deletions(-) diff --git a/src/core/ext/filters/client_channel/lb_policy/pick_first/pick_first.cc b/src/core/ext/filters/client_channel/lb_policy/pick_first/pick_first.cc index 970751ce2c7..b19616a48e3 100644 --- a/src/core/ext/filters/client_channel/lb_policy/pick_first/pick_first.cc +++ b/src/core/ext/filters/client_channel/lb_policy/pick_first/pick_first.cc @@ -427,7 +427,7 @@ static void pf_connectivity_changed_locked(grpc_exec_ctx *exec_ctx, void *arg, grpc_lb_subchannel_data_stop_connectivity_watch(exec_ctx, sd); grpc_lb_subchannel_list_unref_for_connectivity_watch( exec_ctx, sd->subchannel_list, "pf_selected_shutdown"); - pf_shutdown_locked(exec_ctx, &p->base); + shutdown_locked(exec_ctx, p, GRPC_ERROR_REF(error)); } } return; diff --git a/src/core/ext/filters/client_channel/lb_policy/round_robin/round_robin.cc b/src/core/ext/filters/client_channel/lb_policy/round_robin/round_robin.cc index 67361bfe5d9..279f80f8a35 100644 --- a/src/core/ext/filters/client_channel/lb_policy/round_robin/round_robin.cc +++ b/src/core/ext/filters/client_channel/lb_policy/round_robin/round_robin.cc @@ -187,15 +187,12 @@ static void rr_shutdown_locked(grpc_exec_ctx *exec_ctx, grpc_lb_policy *pol) { grpc_connectivity_state_set( exec_ctx, &p->state_tracker, GRPC_CHANNEL_SHUTDOWN, GRPC_ERROR_CREATE_FROM_STATIC_STRING("Channel Shutdown"), "rr_shutdown"); - const bool latest_is_current = - p->subchannel_list == p->latest_pending_subchannel_list; if (p->subchannel_list != NULL) { grpc_lb_subchannel_list_shutdown_and_unref(exec_ctx, p->subchannel_list, "sl_shutdown_rr_shutdown"); p->subchannel_list = NULL; } - if (!latest_is_current && p->latest_pending_subchannel_list != NULL && - !p->latest_pending_subchannel_list->shutting_down) { + if (p->latest_pending_subchannel_list != NULL) { grpc_lb_subchannel_list_shutdown_and_unref( exec_ctx, p->latest_pending_subchannel_list, "sl_shutdown_pending_rr_shutdown"); diff --git a/src/core/ext/filters/client_channel/lb_policy/subchannel_list.h b/src/core/ext/filters/client_channel/lb_policy/subchannel_list.h index 814180388dd..7ad22302ce2 100644 --- a/src/core/ext/filters/client_channel/lb_policy/subchannel_list.h +++ b/src/core/ext/filters/client_channel/lb_policy/subchannel_list.h @@ -68,19 +68,19 @@ typedef struct { const grpc_lb_user_data_vtable *user_data_vtable; } grpc_lb_subchannel_data; -// Unrefs the subchannel contained in sd. +/// Unrefs the subchannel contained in sd. void grpc_lb_subchannel_data_unref_subchannel(grpc_exec_ctx *exec_ctx, grpc_lb_subchannel_data *sd, const char *reason); -// Starts watching the connectivity state of the subchannel. -// The connectivity_changed_cb callback must invoke either -// grpc_lb_subchannel_data_stop_connectivity_watch() or again call -// grpc_lb_subchannel_data_start_connectivity_watch(). +/// Starts watching the connectivity state of the subchannel. +/// The connectivity_changed_cb callback must invoke either +/// grpc_lb_subchannel_data_stop_connectivity_watch() or again call +/// grpc_lb_subchannel_data_start_connectivity_watch(). void grpc_lb_subchannel_data_start_connectivity_watch( grpc_exec_ctx *exec_ctx, grpc_lb_subchannel_data *sd); -// Stops watching the connectivity state of the subchannel. +/// Stops watching the connectivity state of the subchannel. void grpc_lb_subchannel_data_stop_connectivity_watch( grpc_exec_ctx *exec_ctx, grpc_lb_subchannel_data *sd); @@ -132,16 +132,16 @@ void grpc_lb_subchannel_list_unref(grpc_exec_ctx *exec_ctx, grpc_lb_subchannel_list *subchannel_list, const char *reason); -// Takes and releases refs needed for a connectivity notification. -// This includes a ref to subchannel_list and a weak ref to the LB policy. +/// Takes and releases refs needed for a connectivity notification. +/// This includes a ref to subchannel_list and a weak ref to the LB policy. void grpc_lb_subchannel_list_ref_for_connectivity_watch( grpc_lb_subchannel_list *subchannel_list, const char *reason); void grpc_lb_subchannel_list_unref_for_connectivity_watch( grpc_exec_ctx *exec_ctx, grpc_lb_subchannel_list *subchannel_list, const char *reason); -// Mark subchannel_list as discarded. Unsubscribes all its subchannels. The -// connectivity state notification callback will ultimately unref it. +/// Mark subchannel_list as discarded. Unsubscribes all its subchannels. The +/// connectivity state notification callback will ultimately unref it. void grpc_lb_subchannel_list_shutdown_and_unref( grpc_exec_ctx *exec_ctx, grpc_lb_subchannel_list *subchannel_list, const char *reason); From 57cdb166590920c72604fe3597d8393d8cc26bb6 Mon Sep 17 00:00:00 2001 From: "Mark D. Roth" Date: Mon, 23 Oct 2017 12:37:07 -0700 Subject: [PATCH 12/47] Initialize subchannel_list->pending_connectivity_state_unsafe. --- src/core/ext/filters/client_channel/lb_policy/subchannel_list.cc | 1 + 1 file changed, 1 insertion(+) diff --git a/src/core/ext/filters/client_channel/lb_policy/subchannel_list.cc b/src/core/ext/filters/client_channel/lb_policy/subchannel_list.cc index 1d2eb395f02..af7a6acdff4 100644 --- a/src/core/ext/filters/client_channel/lb_policy/subchannel_list.cc +++ b/src/core/ext/filters/client_channel/lb_policy/subchannel_list.cc @@ -178,6 +178,7 @@ grpc_lb_subchannel_list *grpc_lb_subchannel_list_create( // grpc_connectivity_state to signal an undefined previous state. sd->prev_connectivity_state = GRPC_CHANNEL_INIT; sd->curr_connectivity_state = subchannel_connectivity_state; + sd->pending_connectivity_state_unsafe = subchannel_connectivity_state; sd->user_data_vtable = addresses->user_data_vtable; if (sd->user_data_vtable != NULL) { sd->user_data = From 61da0506931715dbc36ac1964bfc310d1738ecb6 Mon Sep 17 00:00:00 2001 From: "Mark D. Roth" Date: Wed, 25 Oct 2017 07:59:39 -0700 Subject: [PATCH 13/47] Fix bug from merge and improve logging. --- .../lb_policy/round_robin/round_robin.cc | 15 ++++++++------- 1 file changed, 8 insertions(+), 7 deletions(-) diff --git a/src/core/ext/filters/client_channel/lb_policy/round_robin/round_robin.cc b/src/core/ext/filters/client_channel/lb_policy/round_robin/round_robin.cc index 1defcb7959e..7d49c3ffe12 100644 --- a/src/core/ext/filters/client_channel/lb_policy/round_robin/round_robin.cc +++ b/src/core/ext/filters/client_channel/lb_policy/round_robin/round_robin.cc @@ -463,7 +463,7 @@ static void rr_connectivity_changed_locked(grpc_exec_ctx *exec_ctx, void *arg, grpc_lb_subchannel_list_unref_for_connectivity_watch( exec_ctx, sd->subchannel_list, "rr_connectivity_shutdown"); if (new_policy_connectivity_state == GRPC_CHANNEL_SHUTDOWN) { - shutdown_locked(exec_ctx, &p->base, GRPC_ERROR_REF(error)); + shutdown_locked(exec_ctx, p, GRPC_ERROR_REF(error)); } } else { // sd not in SHUTDOWN if (sd->curr_connectivity_state == GRPC_CHANNEL_READY) { @@ -572,21 +572,22 @@ static void rr_update_locked(grpc_exec_ctx *exec_ctx, grpc_lb_policy *policy, const grpc_arg *arg = grpc_channel_args_find(args->args, GRPC_ARG_LB_ADDRESSES); if (arg == NULL || arg->type != GRPC_ARG_POINTER) { + gpr_log(GPR_ERROR, "[RR %p] update provided no addresses; ignoring", p); + // If we don't have a current subchannel list, go into TRANSIENT_FAILURE. + // Otherwise, keep using the current subchannel list (ignore this update). if (p->subchannel_list == NULL) { - // If we don't have a current subchannel list, go into TRANSIENT FAILURE. grpc_connectivity_state_set( exec_ctx, &p->state_tracker, GRPC_CHANNEL_TRANSIENT_FAILURE, GRPC_ERROR_CREATE_FROM_STATIC_STRING("Missing update in args"), "rr_update_missing"); - } else { - // otherwise, keep using the current subchannel list (ignore this update). - gpr_log(GPR_ERROR, - "[RR %p] No valid LB addresses channel arg for update, ignoring.", - (void *)p); } return; } grpc_lb_addresses *addresses = (grpc_lb_addresses *)arg->value.pointer.p; + if (GRPC_TRACER_ON(grpc_lb_round_robin_trace)) { + gpr_log(GPR_DEBUG, "[RR %p] received update with %" PRIdPTR " addresses", + p, addresses->num_addresses); + } grpc_lb_subchannel_list *subchannel_list = grpc_lb_subchannel_list_create( exec_ctx, &p->base, &grpc_lb_round_robin_trace, addresses, args, rr_connectivity_changed_locked); From 6c5569167daf51503145ce791d0c5f6b99b016fd Mon Sep 17 00:00:00 2001 From: "Mark D. Roth" Date: Wed, 25 Oct 2017 07:59:51 -0700 Subject: [PATCH 14/47] Take ref to connected subchannel if subchannel starts in state READY. --- .../client_channel/lb_policy/pick_first/pick_first.cc | 5 ----- .../ext/filters/client_channel/lb_policy/subchannel_list.cc | 5 +++++ 2 files changed, 5 insertions(+), 5 deletions(-) diff --git a/src/core/ext/filters/client_channel/lb_policy/pick_first/pick_first.cc b/src/core/ext/filters/client_channel/lb_policy/pick_first/pick_first.cc index b19616a48e3..81f9bc5a989 100644 --- a/src/core/ext/filters/client_channel/lb_policy/pick_first/pick_first.cc +++ b/src/core/ext/filters/client_channel/lb_policy/pick_first/pick_first.cc @@ -312,11 +312,6 @@ static void pf_update_locked(grpc_exec_ctx *exec_ctx, grpc_lb_policy *policy, exec_ctx, p->subchannel_list, "pf_update_includes_selected"); } p->subchannel_list = subchannel_list; - if (p->selected->connected_subchannel != NULL) { - sd->connected_subchannel = GRPC_CONNECTED_SUBCHANNEL_REF( - grpc_subchannel_get_connected_subchannel(sd->subchannel), - "pf_update_includes_selected"); - } p->selected = sd; destroy_unselected_subchannels_locked(exec_ctx, p); // If there was a previously pending update (which may or may diff --git a/src/core/ext/filters/client_channel/lb_policy/subchannel_list.cc b/src/core/ext/filters/client_channel/lb_policy/subchannel_list.cc index af7a6acdff4..cf3e9525ef3 100644 --- a/src/core/ext/filters/client_channel/lb_policy/subchannel_list.cc +++ b/src/core/ext/filters/client_channel/lb_policy/subchannel_list.cc @@ -179,6 +179,11 @@ grpc_lb_subchannel_list *grpc_lb_subchannel_list_create( sd->prev_connectivity_state = GRPC_CHANNEL_INIT; sd->curr_connectivity_state = subchannel_connectivity_state; sd->pending_connectivity_state_unsafe = subchannel_connectivity_state; + if (sd->curr_connectivity_state == GRPC_CHANNEL_READY) { + sd->connected_subchannel = GRPC_CONNECTED_SUBCHANNEL_REF( + grpc_subchannel_get_connected_subchannel(sd->subchannel), + "ready_at_sl_creation"); + } sd->user_data_vtable = addresses->user_data_vtable; if (sd->user_data_vtable != NULL) { sd->user_data = From a5113563df94e35fd1d7318e48c8f260646cc685 Mon Sep 17 00:00:00 2001 From: Jan Tattermusch Date: Thu, 26 Oct 2017 15:35:43 +0200 Subject: [PATCH 15/47] limit concurrent jobs for build_only on linux --- tools/internal_ci/linux/grpc_build_submodule_at_head.sh | 2 +- tools/internal_ci/linux/grpc_portability_build_only.cfg | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/tools/internal_ci/linux/grpc_build_submodule_at_head.sh b/tools/internal_ci/linux/grpc_build_submodule_at_head.sh index b67b0303617..e203a62b08a 100755 --- a/tools/internal_ci/linux/grpc_build_submodule_at_head.sh +++ b/tools/internal_ci/linux/grpc_build_submodule_at_head.sh @@ -27,5 +27,5 @@ source tools/internal_ci/helper_scripts/prepare_build_linux_rc tools/buildgen/generate_projects.sh git -c user.name='foo' -c user.email='foo@google.com' commit -a -m 'Update submodule' -tools/run_tests/run_tests_matrix.py -f linux --internal_ci --build_only +tools/run_tests/run_tests_matrix.py -f linux --inner_jobs 4 -j 4 --internal_ci --build_only diff --git a/tools/internal_ci/linux/grpc_portability_build_only.cfg b/tools/internal_ci/linux/grpc_portability_build_only.cfg index 501223c0c73..4acd9353fb4 100644 --- a/tools/internal_ci/linux/grpc_portability_build_only.cfg +++ b/tools/internal_ci/linux/grpc_portability_build_only.cfg @@ -26,5 +26,5 @@ action { env_vars { key: "RUN_TESTS_FLAGS" - value: "-f portability linux --internal_ci --build_only" + value: "-f portability linux --inner_jobs 4 -j 4 --internal_ci --build_only" } From 69bd8f2d5d981dd646733f2fd030c93c4b23c58b Mon Sep 17 00:00:00 2001 From: Jan Tattermusch Date: Thu, 26 Oct 2017 16:48:09 +0200 Subject: [PATCH 16/47] print timing for docker pull --- tools/run_tests/dockerize/build_and_run_docker.sh | 4 ++-- tools/run_tests/dockerize/build_docker_and_run_tests.sh | 2 +- tools/run_tests/dockerize/build_interop_image.sh | 2 +- 3 files changed, 4 insertions(+), 4 deletions(-) diff --git a/tools/run_tests/dockerize/build_and_run_docker.sh b/tools/run_tests/dockerize/build_and_run_docker.sh index 80aec82c3d6..323c2f78af9 100755 --- a/tools/run_tests/dockerize/build_and_run_docker.sh +++ b/tools/run_tests/dockerize/build_and_run_docker.sh @@ -36,13 +36,13 @@ DOCKER_IMAGE_NAME=$(basename $DOCKERFILE_DIR)_$(sha1sum $DOCKERFILE_DIR/Dockerfi # Pull the base image to force an update if [ "$DOCKER_BASE_IMAGE" != "" ] then - docker pull $DOCKER_BASE_IMAGE + time docker pull $DOCKER_BASE_IMAGE fi if [ "$DOCKERHUB_ORGANIZATION" != "" ] then DOCKER_IMAGE_NAME=$DOCKERHUB_ORGANIZATION/$DOCKER_IMAGE_NAME - docker pull $DOCKER_IMAGE_NAME + time docker pull $DOCKER_IMAGE_NAME else # Make sure docker image has been built. Should be instantaneous if so. docker build -t $DOCKER_IMAGE_NAME $DOCKERFILE_DIR diff --git a/tools/run_tests/dockerize/build_docker_and_run_tests.sh b/tools/run_tests/dockerize/build_docker_and_run_tests.sh index eea00da821e..06a5dae6a5f 100755 --- a/tools/run_tests/dockerize/build_docker_and_run_tests.sh +++ b/tools/run_tests/dockerize/build_docker_and_run_tests.sh @@ -40,7 +40,7 @@ DOCKER_IMAGE_NAME=$(basename $DOCKERFILE_DIR)_$(sha1sum $DOCKERFILE_DIR/Dockerfi if [ "$DOCKERHUB_ORGANIZATION" != "" ] then DOCKER_IMAGE_NAME=$DOCKERHUB_ORGANIZATION/$DOCKER_IMAGE_NAME - docker pull $DOCKER_IMAGE_NAME + time docker pull $DOCKER_IMAGE_NAME else # Make sure docker image has been built. Should be instantaneous if so. docker build -t $DOCKER_IMAGE_NAME $DOCKERFILE_DIR diff --git a/tools/run_tests/dockerize/build_interop_image.sh b/tools/run_tests/dockerize/build_interop_image.sh index 09e062980d8..dbc6bdeea5c 100755 --- a/tools/run_tests/dockerize/build_interop_image.sh +++ b/tools/run_tests/dockerize/build_interop_image.sh @@ -78,7 +78,7 @@ fi if [ "$DOCKERHUB_ORGANIZATION" != "" ] then BASE_IMAGE=$DOCKERHUB_ORGANIZATION/$BASE_IMAGE - docker pull $BASE_IMAGE + time docker pull $BASE_IMAGE else # Make sure docker image has been built. Should be instantaneous if so. docker build -t $BASE_IMAGE --force-rm=true tools/dockerfile/interoptest/$BASE_NAME || exit $? From f568c0a07e965a34db3205a77e6a17826266261e Mon Sep 17 00:00:00 2001 From: Jan Tattermusch Date: Thu, 26 Oct 2017 17:25:29 +0200 Subject: [PATCH 17/47] use GCR mirror for pulling images --- tools/internal_ci/helper_scripts/prepare_build_linux_rc | 3 +++ 1 file changed, 3 insertions(+) diff --git a/tools/internal_ci/helper_scripts/prepare_build_linux_rc b/tools/internal_ci/helper_scripts/prepare_build_linux_rc index ea2a17f2bcf..8715d6c8e0d 100644 --- a/tools/internal_ci/helper_scripts/prepare_build_linux_rc +++ b/tools/internal_ci/helper_scripts/prepare_build_linux_rc @@ -22,6 +22,9 @@ ulimit -n 32768 # Move docker's storage location to scratch disk so we don't run out of space. echo 'DOCKER_OPTS="${DOCKER_OPTS} --graph=/tmpfs/docker"' | sudo tee --append /etc/default/docker +# Use container registry mirror for pulling docker images (should make downloads faster) +# See https://cloud.google.com/container-registry/docs/using-dockerhub-mirroring +echo 'DOCKER_OPTS="${DOCKER_OPTS} --registry-mirror=https://mirror.gcr.io"' | sudo tee --append /etc/default/docker sudo service docker restart # Populate xdg-cache-home to workaround https://github.com/grpc/grpc/issues/11968 From f06d42ad4c18b0783ddfafc039e90dd9d8435cf7 Mon Sep 17 00:00:00 2001 From: ncteisen Date: Thu, 26 Oct 2017 08:58:22 -0700 Subject: [PATCH 18/47] Fix test timing bug: --- test/core/transport/status_conversion_test.c | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/test/core/transport/status_conversion_test.c b/test/core/transport/status_conversion_test.c index de8fa4458a6..1a437046e8e 100644 --- a/test/core/transport/status_conversion_test.c +++ b/test/core/transport/status_conversion_test.c @@ -16,6 +16,8 @@ * */ +#include + #include "src/core/lib/transport/status_conversion.h" #include #include "test/core/util/test_config.h" @@ -38,6 +40,7 @@ int main(int argc, char **argv) { int i; grpc_test_init(argc, argv); + grpc_init(); GRPC_STATUS_TO_HTTP2_ERROR(GRPC_STATUS_OK, GRPC_HTTP2_NO_ERROR); GRPC_STATUS_TO_HTTP2_ERROR(GRPC_STATUS_CANCELLED, GRPC_HTTP2_CANCEL); @@ -129,6 +132,7 @@ int main(int argc, char **argv) { GRPC_STATUS_INTERNAL); HTTP2_ERROR_TO_GRPC_STATUS(GRPC_HTTP2_REFUSED_STREAM, after_deadline, GRPC_STATUS_UNAVAILABLE); + sleep(1); HTTP2_ERROR_TO_GRPC_STATUS(GRPC_HTTP2_CANCEL, after_deadline, GRPC_STATUS_DEADLINE_EXCEEDED); HTTP2_ERROR_TO_GRPC_STATUS(GRPC_HTTP2_COMPRESSION_ERROR, after_deadline, @@ -158,5 +162,7 @@ int main(int argc, char **argv) { grpc_http2_status_to_grpc_status(i); } + grpc_shutdown(); + return 0; } From cfcbab3d84b48b005ebd038feb02004344429b28 Mon Sep 17 00:00:00 2001 From: "Mark D. Roth" Date: Thu, 26 Oct 2017 09:48:30 -0700 Subject: [PATCH 19/47] clang-format --- .../lb_policy/round_robin/round_robin.cc | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/src/core/ext/filters/client_channel/lb_policy/round_robin/round_robin.cc b/src/core/ext/filters/client_channel/lb_policy/round_robin/round_robin.cc index 7d49c3ffe12..e3cfd1baa18 100644 --- a/src/core/ext/filters/client_channel/lb_policy/round_robin/round_robin.cc +++ b/src/core/ext/filters/client_channel/lb_policy/round_robin/round_robin.cc @@ -182,9 +182,9 @@ static void shutdown_locked(grpc_exec_ctx *exec_ctx, round_robin_lb_policy *p, GRPC_CLOSURE_SCHED(exec_ctx, pp->on_complete, GRPC_ERROR_REF(error)); gpr_free(pp); } - grpc_connectivity_state_set( - exec_ctx, &p->state_tracker, GRPC_CHANNEL_SHUTDOWN, - GRPC_ERROR_REF(error), "rr_shutdown"); + grpc_connectivity_state_set(exec_ctx, &p->state_tracker, + GRPC_CHANNEL_SHUTDOWN, GRPC_ERROR_REF(error), + "rr_shutdown"); if (p->subchannel_list != NULL) { grpc_lb_subchannel_list_shutdown_and_unref(exec_ctx, p->subchannel_list, "sl_shutdown_rr_shutdown"); @@ -585,8 +585,8 @@ static void rr_update_locked(grpc_exec_ctx *exec_ctx, grpc_lb_policy *policy, } grpc_lb_addresses *addresses = (grpc_lb_addresses *)arg->value.pointer.p; if (GRPC_TRACER_ON(grpc_lb_round_robin_trace)) { - gpr_log(GPR_DEBUG, "[RR %p] received update with %" PRIdPTR " addresses", - p, addresses->num_addresses); + gpr_log(GPR_DEBUG, "[RR %p] received update with %" PRIdPTR " addresses", p, + addresses->num_addresses); } grpc_lb_subchannel_list *subchannel_list = grpc_lb_subchannel_list_create( exec_ctx, &p->base, &grpc_lb_round_robin_trace, addresses, args, From e9b1083791873f2bc9e0bc33874911c49f05e923 Mon Sep 17 00:00:00 2001 From: "Mark D. Roth" Date: Thu, 26 Oct 2017 13:18:25 -0700 Subject: [PATCH 20/47] Change uses of PRIdPTR to PRIuPTR. --- .../ext/filters/client_channel/client_channel.cc | 4 ++-- .../lb_policy/pick_first/pick_first.cc | 6 +++--- .../lb_policy/round_robin/round_robin.cc | 2 +- .../client_channel/lb_policy/subchannel_list.cc | 14 +++++++------- 4 files changed, 13 insertions(+), 13 deletions(-) diff --git a/src/core/ext/filters/client_channel/client_channel.cc b/src/core/ext/filters/client_channel/client_channel.cc index ea5e076c3be..34ba5049494 100644 --- a/src/core/ext/filters/client_channel/client_channel.cc +++ b/src/core/ext/filters/client_channel/client_channel.cc @@ -898,7 +898,7 @@ static void waiting_for_pick_batches_fail(grpc_exec_ctx *exec_ctx, call_data *calld = (call_data *)elem->call_data; if (GRPC_TRACER_ON(grpc_client_channel_trace)) { gpr_log(GPR_DEBUG, - "chand=%p calld=%p: failing %" PRIdPTR " pending batches: %s", + "chand=%p calld=%p: failing %" PRIuPTR " pending batches: %s", elem->channel_data, calld, calld->waiting_for_pick_batches_count, grpc_error_string(error)); } @@ -940,7 +940,7 @@ static void waiting_for_pick_batches_resume(grpc_exec_ctx *exec_ctx, channel_data *chand = (channel_data *)elem->channel_data; call_data *calld = (call_data *)elem->call_data; if (GRPC_TRACER_ON(grpc_client_channel_trace)) { - gpr_log(GPR_DEBUG, "chand=%p calld=%p: sending %" PRIdPTR + gpr_log(GPR_DEBUG, "chand=%p calld=%p: sending %" PRIuPTR " pending batches to subchannel_call=%p", chand, calld, calld->waiting_for_pick_batches_count, calld->subchannel_call); diff --git a/src/core/ext/filters/client_channel/lb_policy/pick_first/pick_first.cc b/src/core/ext/filters/client_channel/lb_policy/pick_first/pick_first.cc index 81f9bc5a989..9b5b9217afe 100644 --- a/src/core/ext/filters/client_channel/lb_policy/pick_first/pick_first.cc +++ b/src/core/ext/filters/client_channel/lb_policy/pick_first/pick_first.cc @@ -300,7 +300,7 @@ static void pf_update_locked(grpc_exec_ctx *exec_ctx, grpc_lb_policy *policy, if (GRPC_TRACER_ON(grpc_lb_pick_first_trace)) { gpr_log(GPR_INFO, "Pick First %p found already selected subchannel %p " - "at update index %" PRIdPTR " of %" PRIdPTR "; update done", + "at update index %" PRIuPTR " of %" PRIuPTR "; update done", p, p->selected->subchannel, i, subchannel_list->num_subchannels); } @@ -360,8 +360,8 @@ static void pf_connectivity_changed_locked(grpc_exec_ctx *exec_ctx, void *arg, pick_first_lb_policy *p = (pick_first_lb_policy *)sd->subchannel_list->policy; if (GRPC_TRACER_ON(grpc_lb_pick_first_trace)) { gpr_log(GPR_DEBUG, - "Pick First %p connectivity changed for subchannel %p (%" PRIdPTR - " of %" PRIdPTR + "Pick First %p connectivity changed for subchannel %p (%" PRIuPTR + " of %" PRIuPTR "), subchannel_list %p: state=%s p->shutdown=%d " "sd->subchannel_list->shutting_down=%d error=%s", (void *)p, (void *)sd->subchannel, diff --git a/src/core/ext/filters/client_channel/lb_policy/round_robin/round_robin.cc b/src/core/ext/filters/client_channel/lb_policy/round_robin/round_robin.cc index e3cfd1baa18..488fd3c0ac9 100644 --- a/src/core/ext/filters/client_channel/lb_policy/round_robin/round_robin.cc +++ b/src/core/ext/filters/client_channel/lb_policy/round_robin/round_robin.cc @@ -585,7 +585,7 @@ static void rr_update_locked(grpc_exec_ctx *exec_ctx, grpc_lb_policy *policy, } grpc_lb_addresses *addresses = (grpc_lb_addresses *)arg->value.pointer.p; if (GRPC_TRACER_ON(grpc_lb_round_robin_trace)) { - gpr_log(GPR_DEBUG, "[RR %p] received update with %" PRIdPTR " addresses", p, + gpr_log(GPR_DEBUG, "[RR %p] received update with %" PRIuPTR " addresses", p, addresses->num_addresses); } grpc_lb_subchannel_list *subchannel_list = grpc_lb_subchannel_list_create( diff --git a/src/core/ext/filters/client_channel/lb_policy/subchannel_list.cc b/src/core/ext/filters/client_channel/lb_policy/subchannel_list.cc index cf3e9525ef3..831d8ac2556 100644 --- a/src/core/ext/filters/client_channel/lb_policy/subchannel_list.cc +++ b/src/core/ext/filters/client_channel/lb_policy/subchannel_list.cc @@ -34,8 +34,8 @@ void grpc_lb_subchannel_data_unref_subchannel(grpc_exec_ctx *exec_ctx, if (sd->subchannel != NULL) { if (GRPC_TRACER_ON(*sd->subchannel_list->tracer)) { gpr_log( - GPR_DEBUG, "[%s %p] subchannel list %p index %" PRIdPTR - " of %" PRIdPTR " (subchannel %p): unreffing subchannel", + GPR_DEBUG, "[%s %p] subchannel list %p index %" PRIuPTR + " of %" PRIuPTR " (subchannel %p): unreffing subchannel", sd->subchannel_list->tracer->name, sd->subchannel_list->policy, sd->subchannel_list, (size_t)(sd - sd->subchannel_list->subchannels), sd->subchannel_list->num_subchannels, sd->subchannel); @@ -59,7 +59,7 @@ void grpc_lb_subchannel_data_start_connectivity_watch( grpc_exec_ctx *exec_ctx, grpc_lb_subchannel_data *sd) { if (GRPC_TRACER_ON(*sd->subchannel_list->tracer)) { gpr_log(GPR_DEBUG, - "[%s %p] subchannel list %p index %" PRIdPTR " of %" PRIdPTR + "[%s %p] subchannel list %p index %" PRIuPTR " of %" PRIuPTR " (subchannel %p): requesting connectivity change notification", sd->subchannel_list->tracer->name, sd->subchannel_list->policy, sd->subchannel_list, @@ -77,7 +77,7 @@ void grpc_lb_subchannel_data_stop_connectivity_watch( grpc_exec_ctx *exec_ctx, grpc_lb_subchannel_data *sd) { if (GRPC_TRACER_ON(*sd->subchannel_list->tracer)) { gpr_log( - GPR_DEBUG, "[%s %p] subchannel list %p index %" PRIdPTR " of %" PRIdPTR + GPR_DEBUG, "[%s %p] subchannel list %p index %" PRIuPTR " of %" PRIuPTR " (subchannel %p): stopping connectivity watch", sd->subchannel_list->tracer->name, sd->subchannel_list->policy, sd->subchannel_list, (size_t)(sd - sd->subchannel_list->subchannels), @@ -95,7 +95,7 @@ grpc_lb_subchannel_list *grpc_lb_subchannel_list_create( (grpc_lb_subchannel_list *)gpr_zalloc(sizeof(*subchannel_list)); if (GRPC_TRACER_ON(*tracer)) { gpr_log(GPR_DEBUG, - "[%s %p] Creating subchannel list %p for %" PRIdPTR " subchannels", + "[%s %p] Creating subchannel list %p for %" PRIuPTR " subchannels", tracer->name, p, subchannel_list, addresses->num_addresses); } subchannel_list->policy = p; @@ -159,7 +159,7 @@ grpc_lb_subchannel_list *grpc_lb_subchannel_list_create( if (GRPC_TRACER_ON(*tracer)) { char *address_uri = grpc_sockaddr_to_uri(&addresses->addresses[i].address); - gpr_log(GPR_DEBUG, "[%s %p] subchannel list %p index %" PRIdPTR + gpr_log(GPR_DEBUG, "[%s %p] subchannel list %p index %" PRIuPTR ": Created subchannel %p for address uri %s; " "initial connectivity state: %s", tracer->name, p, subchannel_list, subchannel_index, subchannel, @@ -255,7 +255,7 @@ static void subchannel_data_cancel_connectivity_watch( grpc_exec_ctx *exec_ctx, grpc_lb_subchannel_data *sd, const char *reason) { if (GRPC_TRACER_ON(*sd->subchannel_list->tracer)) { gpr_log( - GPR_DEBUG, "[%s %p] subchannel list %p index %" PRIdPTR " of %" PRIdPTR + GPR_DEBUG, "[%s %p] subchannel list %p index %" PRIuPTR " of %" PRIuPTR " (subchannel %p): canceling connectivity watch (%s)", sd->subchannel_list->tracer->name, sd->subchannel_list->policy, sd->subchannel_list, (size_t)(sd - sd->subchannel_list->subchannels), From 06e174a088edadae2081ee5843c70cd4ba017f78 Mon Sep 17 00:00:00 2001 From: Vijay Pai Date: Fri, 20 Oct 2017 05:51:12 -0700 Subject: [PATCH 21/47] Separate public and internal C++ interfaces --- include/grpc++/alarm.h | 2 +- include/grpc++/channel.h | 16 +- include/grpc++/impl/codegen/async_stream.h | 264 ++++++++------- .../grpc++/impl/codegen/async_unary_call.h | 69 ++-- include/grpc++/impl/codegen/byte_buffer.h | 21 +- include/grpc++/impl/codegen/call.h | 17 +- include/grpc++/impl/codegen/call_hook.h | 2 + .../grpc++/impl/codegen/channel_interface.h | 29 +- include/grpc++/impl/codegen/client_context.h | 23 +- .../grpc++/impl/codegen/client_unary_call.h | 73 +++-- .../grpc++/impl/codegen/completion_queue.h | 51 +-- .../impl/codegen/completion_queue_tag.h | 2 + include/grpc++/impl/codegen/metadata_map.h | 2 + .../grpc++/impl/codegen/method_handler_impl.h | 2 + include/grpc++/impl/codegen/rpc_method.h | 3 +- .../grpc++/impl/codegen/rpc_service_method.h | 3 +- include/grpc++/impl/codegen/server_context.h | 27 +- .../grpc++/impl/codegen/server_interface.h | 42 +-- include/grpc++/impl/codegen/service_type.h | 46 +-- include/grpc++/impl/codegen/sync_stream.h | 301 +++++++++++------- include/grpc++/impl/codegen/time.h | 6 +- include/grpc++/server.h | 3 +- include/grpc++/server_builder.h | 1 - src/compiler/cpp_generator.cc | 151 ++++----- src/cpp/client/channel_cc.cc | 12 +- src/cpp/client/generic_stub.cc | 10 +- src/cpp/common/completion_queue_cc.cc | 4 +- .../health/default_health_check_service.cc | 9 +- .../health/default_health_check_service.h | 2 +- src/cpp/server/server_cc.cc | 69 ++-- src/cpp/server/server_context.cc | 8 +- test/cpp/codegen/compiler_test_golden | 17 +- test/cpp/microbenchmarks/bm_cq.cc | 2 +- 33 files changed, 732 insertions(+), 557 deletions(-) diff --git a/include/grpc++/alarm.h b/include/grpc++/alarm.h index 2d88d868e52..b43425e224b 100644 --- a/include/grpc++/alarm.h +++ b/include/grpc++/alarm.h @@ -92,7 +92,7 @@ class Alarm : private GrpcLibraryCodegen { } private: - class AlarmEntry : public CompletionQueueTag { + class AlarmEntry : public internal::CompletionQueueTag { public: AlarmEntry(void* tag) : tag_(tag) {} void Set(void* tag) { tag_ = tag; } diff --git a/include/grpc++/channel.h b/include/grpc++/channel.h index c50091d6ac1..e9fb5a5d097 100644 --- a/include/grpc++/channel.h +++ b/include/grpc++/channel.h @@ -32,7 +32,7 @@ struct grpc_channel; namespace grpc { /// Channels represent a connection to an endpoint. Created by \a CreateChannel. class Channel final : public ChannelInterface, - public CallHook, + public internal::CallHook, public std::enable_shared_from_this, private GrpcLibraryCodegen { public: @@ -51,18 +51,16 @@ class Channel final : public ChannelInterface, private: template - friend Status BlockingUnaryCall(ChannelInterface* channel, - const RpcMethod& method, - ClientContext* context, - const InputMessage& request, - OutputMessage* result); + friend class internal::BlockingUnaryCallImpl; friend std::shared_ptr CreateChannelInternal( const grpc::string& host, grpc_channel* c_channel); Channel(const grpc::string& host, grpc_channel* c_channel); - Call CreateCall(const RpcMethod& method, ClientContext* context, - CompletionQueue* cq) override; - void PerformOpsOnCall(CallOpSetInterface* ops, Call* call) override; + internal::Call CreateCall(const internal::RpcMethod& method, + ClientContext* context, + CompletionQueue* cq) override; + void PerformOpsOnCall(internal::CallOpSetInterface* ops, + internal::Call* call) override; void* RegisterMethod(const char* method) override; void NotifyOnStateChangeImpl(grpc_connectivity_state last_observed, diff --git a/include/grpc++/impl/codegen/async_stream.h b/include/grpc++/impl/codegen/async_stream.h index e60572fc939..2012b3170b3 100644 --- a/include/grpc++/impl/codegen/async_stream.h +++ b/include/grpc++/impl/codegen/async_stream.h @@ -30,6 +30,7 @@ namespace grpc { class CompletionQueue; +namespace internal { /// Common interface for all client side asynchronous streaming. class ClientAsyncStreamingInterface { public: @@ -151,9 +152,12 @@ class AsyncWriterInterface { } }; +} // namespace internal + template -class ClientAsyncReaderInterface : public ClientAsyncStreamingInterface, - public AsyncReaderInterface {}; +class ClientAsyncReaderInterface + : public internal::ClientAsyncStreamingInterface, + public internal::AsyncReaderInterface {}; /// Async client-side API for doing server-streaming RPCs, /// where the incoming message stream coming from the server has @@ -161,23 +165,26 @@ class ClientAsyncReaderInterface : public ClientAsyncStreamingInterface, template class ClientAsyncReader final : public ClientAsyncReaderInterface { public: - /// Create a stream object. - /// Write the first request out if \a start is set. - /// \a tag will be notified on \a cq when the call has been started and - /// \a request has been written out. If \a start is not set, \a tag must be - /// nullptr and the actual call must be initiated by StartCall - /// Note that \a context will be used to fill in custom initial metadata - /// used to send to the server when starting the call. - template - static ClientAsyncReader* Create(ChannelInterface* channel, - CompletionQueue* cq, const RpcMethod& method, - ClientContext* context, const W& request, - bool start, void* tag) { - Call call = channel->CreateCall(method, context, cq); - return new (g_core_codegen_interface->grpc_call_arena_alloc( - call.call(), sizeof(ClientAsyncReader))) - ClientAsyncReader(call, context, request, start, tag); - } + struct internal { + /// Create a stream object. + /// Write the first request out if \a start is set. + /// \a tag will be notified on \a cq when the call has been started and + /// \a request has been written out. If \a start is not set, \a tag must be + /// nullptr and the actual call must be initiated by StartCall + /// Note that \a context will be used to fill in custom initial metadata + /// used to send to the server when starting the call. + template + static ClientAsyncReader* Create(ChannelInterface* channel, + CompletionQueue* cq, + const ::grpc::internal::RpcMethod& method, + ClientContext* context, const W& request, + bool start, void* tag) { + ::grpc::internal::Call call = channel->CreateCall(method, context, cq); + return new (g_core_codegen_interface->grpc_call_arena_alloc( + call.call(), sizeof(ClientAsyncReader))) + ClientAsyncReader(call, context, request, start, tag); + } + }; // always allocated against a call arena, no memory free required static void operator delete(void* ptr, std::size_t size) { @@ -234,8 +241,8 @@ class ClientAsyncReader final : public ClientAsyncReaderInterface { private: template - ClientAsyncReader(Call call, ClientContext* context, const W& request, - bool start, void* tag) + ClientAsyncReader(::grpc::internal::Call call, ClientContext* context, + const W& request, bool start, void* tag) : context_(context), call_(call), started_(start) { // TODO(ctiller): don't assert GPR_CODEGEN_ASSERT(init_ops_.SendMessage(request).ok()); @@ -255,19 +262,27 @@ class ClientAsyncReader final : public ClientAsyncReaderInterface { } ClientContext* context_; - Call call_; + ::grpc::internal::Call call_; bool started_; - CallOpSet + ::grpc::internal::CallOpSet<::grpc::internal::CallOpSendInitialMetadata, + ::grpc::internal::CallOpSendMessage, + ::grpc::internal::CallOpClientSendClose> init_ops_; - CallOpSet meta_ops_; - CallOpSet> read_ops_; - CallOpSet finish_ops_; + ::grpc::internal::CallOpSet<::grpc::internal::CallOpRecvInitialMetadata> + meta_ops_; + ::grpc::internal::CallOpSet<::grpc::internal::CallOpRecvInitialMetadata, + ::grpc::internal::CallOpRecvMessage> + read_ops_; + ::grpc::internal::CallOpSet<::grpc::internal::CallOpRecvInitialMetadata, + ::grpc::internal::CallOpClientRecvStatus> + finish_ops_; }; /// Common interface for client side asynchronous writing. template -class ClientAsyncWriterInterface : public ClientAsyncStreamingInterface, - public AsyncWriterInterface { +class ClientAsyncWriterInterface + : public internal::ClientAsyncStreamingInterface, + public internal::AsyncWriterInterface { public: /// Signal the client is done with the writes (half-close the client stream). /// Thread-safe with respect to \a AsyncReaderInterface::Read @@ -282,27 +297,30 @@ class ClientAsyncWriterInterface : public ClientAsyncStreamingInterface, template class ClientAsyncWriter final : public ClientAsyncWriterInterface { public: - /// Create a stream object. - /// Start the RPC if \a start is set - /// \a tag will be notified on \a cq when the call has been started (i.e. - /// intitial metadata sent) and \a request has been written out. - /// If \a start is not set, \a tag must be nullptr and the actual call - /// must be initiated by StartCall - /// Note that \a context will be used to fill in custom initial metadata - /// used to send to the server when starting the call. - /// \a response will be filled in with the single expected response - /// message from the server upon a successful call to the \a Finish - /// method of this instance. - template - static ClientAsyncWriter* Create(ChannelInterface* channel, - CompletionQueue* cq, const RpcMethod& method, - ClientContext* context, R* response, - bool start, void* tag) { - Call call = channel->CreateCall(method, context, cq); - return new (g_core_codegen_interface->grpc_call_arena_alloc( - call.call(), sizeof(ClientAsyncWriter))) - ClientAsyncWriter(call, context, response, start, tag); - } + struct internal { + /// Create a stream object. + /// Start the RPC if \a start is set + /// \a tag will be notified on \a cq when the call has been started (i.e. + /// intitial metadata sent) and \a request has been written out. + /// If \a start is not set, \a tag must be nullptr and the actual call + /// must be initiated by StartCall + /// Note that \a context will be used to fill in custom initial metadata + /// used to send to the server when starting the call. + /// \a response will be filled in with the single expected response + /// message from the server upon a successful call to the \a Finish + /// method of this instance. + template + static ClientAsyncWriter* Create(ChannelInterface* channel, + CompletionQueue* cq, + const ::grpc::internal::RpcMethod& method, + ClientContext* context, R* response, + bool start, void* tag) { + ::grpc::internal::Call call = channel->CreateCall(method, context, cq); + return new (g_core_codegen_interface->grpc_call_arena_alloc( + call.call(), sizeof(ClientAsyncWriter))) + ClientAsyncWriter(call, context, response, start, tag); + } + }; // always allocated against a call arena, no memory free required static void operator delete(void* ptr, std::size_t size) { @@ -377,8 +395,8 @@ class ClientAsyncWriter final : public ClientAsyncWriterInterface { private: template - ClientAsyncWriter(Call call, ClientContext* context, R* response, bool start, - void* tag) + ClientAsyncWriter(::grpc::internal::Call call, ClientContext* context, + R* response, bool start, void* tag) : context_(context), call_(call), started_(start) { finish_ops_.RecvMessage(response); finish_ops_.AllowNoMessage(); @@ -401,13 +419,17 @@ class ClientAsyncWriter final : public ClientAsyncWriterInterface { } ClientContext* context_; - Call call_; + ::grpc::internal::Call call_; bool started_; - CallOpSet meta_ops_; - CallOpSet + ::grpc::internal::CallOpSet<::grpc::internal::CallOpRecvInitialMetadata> + meta_ops_; + ::grpc::internal::CallOpSet<::grpc::internal::CallOpSendInitialMetadata, + ::grpc::internal::CallOpSendMessage, + ::grpc::internal::CallOpClientSendClose> write_ops_; - CallOpSet + ::grpc::internal::CallOpSet<::grpc::internal::CallOpRecvInitialMetadata, + ::grpc::internal::CallOpGenericRecvMessage, + ::grpc::internal::CallOpClientRecvStatus> finish_ops_; }; @@ -415,9 +437,10 @@ class ClientAsyncWriter final : public ClientAsyncWriterInterface { /// where the client-to-server message stream has messages of type \a W, /// and the server-to-client message stream has messages of type \a R. template -class ClientAsyncReaderWriterInterface : public ClientAsyncStreamingInterface, - public AsyncWriterInterface, - public AsyncReaderInterface { +class ClientAsyncReaderWriterInterface + : public internal::ClientAsyncStreamingInterface, + public internal::AsyncWriterInterface, + public internal::AsyncReaderInterface { public: /// Signal the client is done with the writes (half-close the client stream). /// Thread-safe with respect to \a AsyncReaderInterface::Read @@ -434,24 +457,25 @@ template class ClientAsyncReaderWriter final : public ClientAsyncReaderWriterInterface { public: - /// Create a stream object. - /// Start the RPC request if \a start is set. - /// \a tag will be notified on \a cq when the call has been started (i.e. - /// intitial metadata sent). If \a start is not set, \a tag must be - /// nullptr and the actual call must be initiated by StartCall - /// Note that \a context will be used to fill in custom initial metadata - /// used to send to the server when starting the call. - static ClientAsyncReaderWriter* Create(ChannelInterface* channel, - CompletionQueue* cq, - const RpcMethod& method, - ClientContext* context, bool start, - void* tag) { - Call call = channel->CreateCall(method, context, cq); - - return new (g_core_codegen_interface->grpc_call_arena_alloc( - call.call(), sizeof(ClientAsyncReaderWriter))) - ClientAsyncReaderWriter(call, context, start, tag); - } + struct internal { + /// Create a stream object. + /// Start the RPC request if \a start is set. + /// \a tag will be notified on \a cq when the call has been started (i.e. + /// intitial metadata sent). If \a start is not set, \a tag must be + /// nullptr and the actual call must be initiated by StartCall + /// Note that \a context will be used to fill in custom initial metadata + /// used to send to the server when starting the call. + static ClientAsyncReaderWriter* Create( + ChannelInterface* channel, CompletionQueue* cq, + const ::grpc::internal::RpcMethod& method, ClientContext* context, + bool start, void* tag) { + ::grpc::internal::Call call = channel->CreateCall(method, context, cq); + + return new (g_core_codegen_interface->grpc_call_arena_alloc( + call.call(), sizeof(ClientAsyncReaderWriter))) + ClientAsyncReaderWriter(call, context, start, tag); + } + }; // always allocated against a call arena, no memory free required static void operator delete(void* ptr, std::size_t size) { @@ -532,8 +556,8 @@ class ClientAsyncReaderWriter final } private: - ClientAsyncReaderWriter(Call call, ClientContext* context, bool start, - void* tag) + ClientAsyncReaderWriter(::grpc::internal::Call call, ClientContext* context, + bool start, void* tag) : context_(context), call_(call), started_(start) { if (start) { StartCallInternal(tag); @@ -554,18 +578,26 @@ class ClientAsyncReaderWriter final } ClientContext* context_; - Call call_; + ::grpc::internal::Call call_; bool started_; - CallOpSet meta_ops_; - CallOpSet> read_ops_; - CallOpSet + ::grpc::internal::CallOpSet<::grpc::internal::CallOpRecvInitialMetadata> + meta_ops_; + ::grpc::internal::CallOpSet<::grpc::internal::CallOpRecvInitialMetadata, + ::grpc::internal::CallOpRecvMessage> + read_ops_; + ::grpc::internal::CallOpSet<::grpc::internal::CallOpSendInitialMetadata, + ::grpc::internal::CallOpSendMessage, + ::grpc::internal::CallOpClientSendClose> write_ops_; - CallOpSet finish_ops_; + ::grpc::internal::CallOpSet<::grpc::internal::CallOpRecvInitialMetadata, + ::grpc::internal::CallOpClientRecvStatus> + finish_ops_; }; template -class ServerAsyncReaderInterface : public ServerAsyncStreamingInterface, - public AsyncReaderInterface { +class ServerAsyncReaderInterface + : public internal::ServerAsyncStreamingInterface, + public internal::AsyncReaderInterface { public: /// Indicate that the stream is to be finished with a certain status code /// and also send out \a msg response to the client. @@ -692,20 +724,23 @@ class ServerAsyncReader final : public ServerAsyncReaderInterface { } private: - void BindCall(Call* call) override { call_ = *call; } + void BindCall(::grpc::internal::Call* call) override { call_ = *call; } - Call call_; + ::grpc::internal::Call call_; ServerContext* ctx_; - CallOpSet meta_ops_; - CallOpSet> read_ops_; - CallOpSet + ::grpc::internal::CallOpSet<::grpc::internal::CallOpSendInitialMetadata> + meta_ops_; + ::grpc::internal::CallOpSet<::grpc::internal::CallOpRecvMessage> read_ops_; + ::grpc::internal::CallOpSet<::grpc::internal::CallOpSendInitialMetadata, + ::grpc::internal::CallOpSendMessage, + ::grpc::internal::CallOpServerSendStatus> finish_ops_; }; template -class ServerAsyncWriterInterface : public ServerAsyncStreamingInterface, - public AsyncWriterInterface { +class ServerAsyncWriterInterface + : public internal::ServerAsyncStreamingInterface, + public internal::AsyncWriterInterface { public: /// Indicate that the stream is to be finished with a certain status code. /// Request notification for when the server has sent the appropriate @@ -823,7 +858,7 @@ class ServerAsyncWriter final : public ServerAsyncWriterInterface { } private: - void BindCall(Call* call) override { call_ = *call; } + void BindCall(::grpc::internal::Call* call) override { call_ = *call; } template void EnsureInitialMetadataSent(T* ops) { @@ -837,20 +872,25 @@ class ServerAsyncWriter final : public ServerAsyncWriterInterface { } } - Call call_; + ::grpc::internal::Call call_; ServerContext* ctx_; - CallOpSet meta_ops_; - CallOpSet + ::grpc::internal::CallOpSet<::grpc::internal::CallOpSendInitialMetadata> + meta_ops_; + ::grpc::internal::CallOpSet<::grpc::internal::CallOpSendInitialMetadata, + ::grpc::internal::CallOpSendMessage, + ::grpc::internal::CallOpServerSendStatus> write_ops_; - CallOpSet finish_ops_; + ::grpc::internal::CallOpSet<::grpc::internal::CallOpSendInitialMetadata, + ::grpc::internal::CallOpServerSendStatus> + finish_ops_; }; /// Server-side interface for asynchronous bi-directional streaming. template -class ServerAsyncReaderWriterInterface : public ServerAsyncStreamingInterface, - public AsyncWriterInterface, - public AsyncReaderInterface { +class ServerAsyncReaderWriterInterface + : public internal::ServerAsyncStreamingInterface, + public internal::AsyncWriterInterface, + public internal::AsyncReaderInterface { public: /// Indicate that the stream is to be finished with a certain status code. /// Request notification for when the server has sent the appropriate @@ -980,7 +1020,7 @@ class ServerAsyncReaderWriter final private: friend class ::grpc::Server; - void BindCall(Call* call) override { call_ = *call; } + void BindCall(::grpc::internal::Call* call) override { call_ = *call; } template void EnsureInitialMetadataSent(T* ops) { @@ -994,14 +1034,18 @@ class ServerAsyncReaderWriter final } } - Call call_; + ::grpc::internal::Call call_; ServerContext* ctx_; - CallOpSet meta_ops_; - CallOpSet> read_ops_; - CallOpSet + ::grpc::internal::CallOpSet<::grpc::internal::CallOpSendInitialMetadata> + meta_ops_; + ::grpc::internal::CallOpSet<::grpc::internal::CallOpRecvMessage> read_ops_; + ::grpc::internal::CallOpSet<::grpc::internal::CallOpSendInitialMetadata, + ::grpc::internal::CallOpSendMessage, + ::grpc::internal::CallOpServerSendStatus> write_ops_; - CallOpSet finish_ops_; + ::grpc::internal::CallOpSet<::grpc::internal::CallOpSendInitialMetadata, + ::grpc::internal::CallOpServerSendStatus> + finish_ops_; }; } // namespace grpc diff --git a/include/grpc++/impl/codegen/async_unary_call.h b/include/grpc++/impl/codegen/async_unary_call.h index e472f04f56e..8a3dfbc4db0 100644 --- a/include/grpc++/impl/codegen/async_unary_call.h +++ b/include/grpc++/impl/codegen/async_unary_call.h @@ -75,23 +75,24 @@ template class ClientAsyncResponseReader final : public ClientAsyncResponseReaderInterface { public: - /// Start a call and write the request out if \a start is set. - /// \a tag will be notified on \a cq when the call has been started (i.e. - /// intitial metadata sent) and \a request has been written out. - /// If \a start is not set, the actual call must be initiated by StartCall - /// Note that \a context will be used to fill in custom initial metadata - /// used to send to the server when starting the call. - template - static ClientAsyncResponseReader* Create(ChannelInterface* channel, - CompletionQueue* cq, - const RpcMethod& method, - ClientContext* context, - const W& request, bool start) { - Call call = channel->CreateCall(method, context, cq); - return new (g_core_codegen_interface->grpc_call_arena_alloc( - call.call(), sizeof(ClientAsyncResponseReader))) - ClientAsyncResponseReader(call, context, request, start); - } + struct internal { + /// Start a call and write the request out if \a start is set. + /// \a tag will be notified on \a cq when the call has been started (i.e. + /// intitial metadata sent) and \a request has been written out. + /// If \a start is not set, the actual call must be initiated by StartCall + /// Note that \a context will be used to fill in custom initial metadata + /// used to send to the server when starting the call. + template + static ClientAsyncResponseReader* Create( + ChannelInterface* channel, CompletionQueue* cq, + const ::grpc::internal::RpcMethod& method, ClientContext* context, + const W& request, bool start) { + ::grpc::internal::Call call = channel->CreateCall(method, context, cq); + return new (g_core_codegen_interface->grpc_call_arena_alloc( + call.call(), sizeof(ClientAsyncResponseReader))) + ClientAsyncResponseReader(call, context, request, start); + } + }; // always allocated against a call arena, no memory free required static void operator delete(void* ptr, std::size_t size) { @@ -138,12 +139,12 @@ class ClientAsyncResponseReader final private: ClientContext* const context_; - Call call_; + ::grpc::internal::Call call_; bool started_; template - ClientAsyncResponseReader(Call call, ClientContext* context, const W& request, - bool start) + ClientAsyncResponseReader(::grpc::internal::Call call, ClientContext* context, + const W& request, bool start) : context_(context), call_(call), started_(start) { // Bind the metadata at time of StartCallInternal but set up the rest here // TODO(ctiller): don't assert @@ -162,19 +163,23 @@ class ClientAsyncResponseReader final static void* operator new(std::size_t size); static void* operator new(std::size_t size, void* p) { return p; } - SneakyCallOpSet + ::grpc::internal::SneakyCallOpSet<::grpc::internal::CallOpSendInitialMetadata, + ::grpc::internal::CallOpSendMessage, + ::grpc::internal::CallOpClientSendClose> init_buf; - CallOpSet meta_buf; - CallOpSet, - CallOpClientRecvStatus> + ::grpc::internal::CallOpSet<::grpc::internal::CallOpRecvInitialMetadata> + meta_buf; + ::grpc::internal::CallOpSet<::grpc::internal::CallOpRecvInitialMetadata, + ::grpc::internal::CallOpRecvMessage, + ::grpc::internal::CallOpClientRecvStatus> finish_buf; }; /// Async server-side API for handling unary calls, where the single /// response message sent to the client is of type \a W. template -class ServerAsyncResponseWriter final : public ServerAsyncStreamingInterface { +class ServerAsyncResponseWriter final + : public internal::ServerAsyncStreamingInterface { public: explicit ServerAsyncResponseWriter(ServerContext* ctx) : call_(nullptr, nullptr, nullptr), ctx_(ctx) {} @@ -262,13 +267,15 @@ class ServerAsyncResponseWriter final : public ServerAsyncStreamingInterface { } private: - void BindCall(Call* call) override { call_ = *call; } + void BindCall(::grpc::internal::Call* call) override { call_ = *call; } - Call call_; + ::grpc::internal::Call call_; ServerContext* ctx_; - CallOpSet meta_buf_; - CallOpSet + ::grpc::internal::CallOpSet<::grpc::internal::CallOpSendInitialMetadata> + meta_buf_; + ::grpc::internal::CallOpSet<::grpc::internal::CallOpSendInitialMetadata, + ::grpc::internal::CallOpSendMessage, + ::grpc::internal::CallOpServerSendStatus> finish_buf_; }; diff --git a/include/grpc++/impl/codegen/byte_buffer.h b/include/grpc++/impl/codegen/byte_buffer.h index 57d731be182..fe73ce7a83d 100644 --- a/include/grpc++/impl/codegen/byte_buffer.h +++ b/include/grpc++/impl/codegen/byte_buffer.h @@ -31,18 +31,19 @@ namespace grpc { +namespace internal { +class CallOpSendMessage; template class CallOpRecvMessage; +class CallOpGenericRecvMessage; class MethodHandler; template class RpcMethodHandler; template class ServerStreamingHandler; -namespace CallOpGenericRecvMessageHelper { template class DeserializeFuncType; -} // namespace CallOpGenericRecvMessageHelper - +} // namespace internal /// A sequence of bytes. class ByteBuffer final { public: @@ -97,17 +98,17 @@ class ByteBuffer final { private: friend class SerializationTraits; - friend class CallOpSendMessage; + friend class internal::CallOpSendMessage; template - friend class CallOpRecvMessage; - friend class CallOpGenericRecvMessage; - friend class MethodHandler; + friend class internal::CallOpRecvMessage; + friend class internal::CallOpGenericRecvMessage; + friend class internal::MethodHandler; template - friend class RpcMethodHandler; + friend class internal::RpcMethodHandler; template - friend class ServerStreamingHandler; + friend class internal::ServerStreamingHandler; template - friend class CallOpGenericRecvMessageHelper::DeserializeFuncType; + friend class internal::DeserializeFuncType; grpc_byte_buffer* buffer_; diff --git a/include/grpc++/impl/codegen/call.h b/include/grpc++/impl/codegen/call.h index 06f107fa83a..1a988297dc4 100644 --- a/include/grpc++/impl/codegen/call.h +++ b/include/grpc++/impl/codegen/call.h @@ -43,11 +43,13 @@ namespace grpc { class ByteBuffer; -class Call; -class CallHook; class CompletionQueue; extern CoreCodegenInterface* g_core_codegen_interface; +namespace internal { +class Call; +class CallHook; + const char kBinaryErrorDetailsKey[] = "grpc-status-details-bin"; // TODO(yangg) if the map is changed before we send, the pointers will be a @@ -75,6 +77,7 @@ inline grpc_metadata* FillMetadataArray( } return metadata_array; } +} // namespace internal /// Per-message write options. class WriteOptions { @@ -199,6 +202,7 @@ class WriteOptions { bool last_message_; }; +namespace internal { /// Default argument for CallOpSet. I is unused by the class, but can be /// used for generating multiple names for the same thing. template @@ -387,7 +391,6 @@ class CallOpRecvMessage { bool allow_not_getting_message_; }; -namespace CallOpGenericRecvMessageHelper { class DeserializeFunc { public: virtual Status Deserialize(ByteBuffer* buf) = 0; @@ -407,7 +410,6 @@ class DeserializeFuncType final : public DeserializeFunc { private: R* message_; // Not a managed pointer because management is external to this }; -} // namespace CallOpGenericRecvMessageHelper class CallOpGenericRecvMessage { public: @@ -418,8 +420,7 @@ class CallOpGenericRecvMessage { void RecvMessage(R* message) { // Use an explicit base class pointer to avoid resolution error in the // following unique_ptr::reset for some old implementations. - CallOpGenericRecvMessageHelper::DeserializeFunc* func = - new CallOpGenericRecvMessageHelper::DeserializeFuncType(message); + DeserializeFunc* func = new DeserializeFuncType(message); deserialize_.reset(func); } @@ -459,7 +460,7 @@ class CallOpGenericRecvMessage { } private: - std::unique_ptr deserialize_; + std::unique_ptr deserialize_; ByteBuffer recv_buf_; bool allow_not_getting_message_; }; @@ -714,7 +715,7 @@ class Call final { grpc_call* call_; int max_receive_message_size_; }; - +} // namespace internal } // namespace grpc #endif // GRPCXX_IMPL_CODEGEN_CALL_H diff --git a/include/grpc++/impl/codegen/call_hook.h b/include/grpc++/impl/codegen/call_hook.h index d026cc8b583..44e9de220ed 100644 --- a/include/grpc++/impl/codegen/call_hook.h +++ b/include/grpc++/impl/codegen/call_hook.h @@ -21,6 +21,7 @@ namespace grpc { +namespace internal { class CallOpSetInterface; class Call; @@ -31,6 +32,7 @@ class CallHook { virtual ~CallHook() {} virtual void PerformOpsOnCall(CallOpSetInterface* ops, Call* call) = 0; }; +} // namespace internal } // namespace grpc diff --git a/include/grpc++/impl/codegen/channel_interface.h b/include/grpc++/impl/codegen/channel_interface.h index 1b7590bf0c3..41c213f64a9 100644 --- a/include/grpc++/impl/codegen/channel_interface.h +++ b/include/grpc++/impl/codegen/channel_interface.h @@ -24,10 +24,8 @@ #include namespace grpc { -class Call; +class ChannelInterface; class ClientContext; -class RpcMethod; -class CallOpSetInterface; class CompletionQueue; template @@ -45,6 +43,14 @@ class ClientAsyncReaderWriter; template class ClientAsyncResponseReader; +namespace internal { +class Call; +class CallOpSetInterface; +class RpcMethod; +template +class BlockingUnaryCallImpl; +} // namespace internal + /// Codegen interface for \a grpc::Channel. class ChannelInterface { public: @@ -96,15 +102,13 @@ class ChannelInterface { template friend class ::grpc::ClientAsyncResponseReader; template - friend Status BlockingUnaryCall(ChannelInterface* channel, - const RpcMethod& method, - ClientContext* context, - const InputMessage& request, - OutputMessage* result); - friend class ::grpc::RpcMethod; - virtual Call CreateCall(const RpcMethod& method, ClientContext* context, - CompletionQueue* cq) = 0; - virtual void PerformOpsOnCall(CallOpSetInterface* ops, Call* call) = 0; + friend class ::grpc::internal::BlockingUnaryCallImpl; + friend class ::grpc::internal::RpcMethod; + virtual internal::Call CreateCall(const internal::RpcMethod& method, + ClientContext* context, + CompletionQueue* cq) = 0; + virtual void PerformOpsOnCall(internal::CallOpSetInterface* ops, + internal::Call* call) = 0; virtual void* RegisterMethod(const char* method) = 0; virtual void NotifyOnStateChangeImpl(grpc_connectivity_state last_observed, gpr_timespec deadline, @@ -112,7 +116,6 @@ class ChannelInterface { virtual bool WaitForStateChangeImpl(grpc_connectivity_state last_observed, gpr_timespec deadline) = 0; }; - } // namespace grpc #endif // GRPCXX_IMPL_CODEGEN_CHANNEL_INTERFACE_H diff --git a/include/grpc++/impl/codegen/client_context.h b/include/grpc++/impl/codegen/client_context.h index 6d7e13bbf29..22b581cbc55 100644 --- a/include/grpc++/impl/codegen/client_context.h +++ b/include/grpc++/impl/codegen/client_context.h @@ -60,7 +60,16 @@ class Channel; class ChannelInterface; class CompletionQueue; class CallCredentials; +class ClientContext; + +namespace internal { class RpcMethod; +class CallOpClientRecvStatus; +class CallOpRecvInitialMetadata; +template +class BlockingUnaryCallImpl; +} // namespace internal + template class ClientReader; template @@ -345,8 +354,8 @@ class ClientContext { ClientContext& operator=(const ClientContext&); friend class ::grpc::testing::InteropClientContextInspector; - friend class CallOpClientRecvStatus; - friend class CallOpRecvInitialMetadata; + friend class ::grpc::internal::CallOpClientRecvStatus; + friend class ::grpc::internal::CallOpRecvInitialMetadata; friend class Channel; template friend class ::grpc::ClientReader; @@ -363,11 +372,7 @@ class ClientContext { template friend class ::grpc::ClientAsyncResponseReader; template - friend Status BlockingUnaryCall(ChannelInterface* channel, - const RpcMethod& method, - ClientContext* context, - const InputMessage& request, - OutputMessage* result); + friend class ::grpc::internal::BlockingUnaryCallImpl; grpc_call* call() const { return call_; } void set_call(grpc_call* call, const std::shared_ptr& channel); @@ -399,8 +404,8 @@ class ClientContext { mutable std::shared_ptr auth_context_; struct census_context* census_context_; std::multimap send_initial_metadata_; - MetadataMap recv_initial_metadata_; - MetadataMap trailing_metadata_; + internal::MetadataMap recv_initial_metadata_; + internal::MetadataMap trailing_metadata_; grpc_call* propagate_from_call_; PropagationOptions propagation_options_; diff --git a/include/grpc++/impl/codegen/client_unary_call.h b/include/grpc++/impl/codegen/client_unary_call.h index 7c540fade9d..170c562cf3b 100644 --- a/include/grpc++/impl/codegen/client_unary_call.h +++ b/include/grpc++/impl/codegen/client_unary_call.h @@ -30,43 +30,60 @@ namespace grpc { class Channel; class ClientContext; class CompletionQueue; -class RpcMethod; +namespace internal { +class RpcMethod; /// Wrapper that performs a blocking unary call template Status BlockingUnaryCall(ChannelInterface* channel, const RpcMethod& method, ClientContext* context, const InputMessage& request, OutputMessage* result) { - CompletionQueue cq(grpc_completion_queue_attributes{ - GRPC_CQ_CURRENT_VERSION, GRPC_CQ_PLUCK, - GRPC_CQ_DEFAULT_POLLING}); // Pluckable completion queue - Call call(channel->CreateCall(method, context, &cq)); - CallOpSet, - CallOpClientSendClose, CallOpClientRecvStatus> - ops; - Status status = ops.SendMessage(request); - if (!status.ok()) { - return status; - } - ops.SendInitialMetadata(context->send_initial_metadata_, - context->initial_metadata_flags()); - ops.RecvInitialMetadata(context); - ops.RecvMessage(result); - ops.ClientSendClose(); - ops.ClientRecvStatus(context, &status); - call.PerformOps(&ops); - if (cq.Pluck(&ops)) { - if (!ops.got_message && status.ok()) { - return Status(StatusCode::UNIMPLEMENTED, - "No message returned for unary request"); + return BlockingUnaryCallImpl( + channel, method, context, request, result) + .status(); +}; + +template +class BlockingUnaryCallImpl { + public: + BlockingUnaryCallImpl(ChannelInterface* channel, const RpcMethod& method, + ClientContext* context, const InputMessage& request, + OutputMessage* result) { + CompletionQueue cq(grpc_completion_queue_attributes{ + GRPC_CQ_CURRENT_VERSION, GRPC_CQ_PLUCK, + GRPC_CQ_DEFAULT_POLLING}); // Pluckable completion queue + Call call(channel->CreateCall(method, context, &cq)); + CallOpSet, + CallOpClientSendClose, CallOpClientRecvStatus> + ops; + status_ = ops.SendMessage(request); + if (!status_.ok()) { + return; + } + ops.SendInitialMetadata(context->send_initial_metadata_, + context->initial_metadata_flags()); + ops.RecvInitialMetadata(context); + ops.RecvMessage(result); + ops.ClientSendClose(); + ops.ClientRecvStatus(context, &status_); + call.PerformOps(&ops); + if (cq.Pluck(&ops)) { + if (!ops.got_message && status_.ok()) { + status_ = Status(StatusCode::UNIMPLEMENTED, + "No message returned for unary request"); + } + } else { + GPR_CODEGEN_ASSERT(!status_.ok()); } - } else { - GPR_CODEGEN_ASSERT(!status.ok()); } - return status; -} + Status status() { return status_; } + + private: + Status status_; +}; +} // namespace internal } // namespace grpc #endif // GRPCXX_IMPL_CODEGEN_CLIENT_UNARY_CALL_H diff --git a/include/grpc++/impl/codegen/completion_queue.h b/include/grpc++/impl/codegen/completion_queue.h index e2c0c29dca4..14de30a62e6 100644 --- a/include/grpc++/impl/codegen/completion_queue.h +++ b/include/grpc++/impl/codegen/completion_queue.h @@ -56,7 +56,19 @@ class ServerWriter; namespace internal { template class ServerReaderWriterBody; -} +} // namespace internal + +class Channel; +class ChannelInterface; +class ClientContext; +class CompletionQueue; +class Server; +class ServerBuilder; +class ServerContext; + +namespace internal { +class CompletionQueueTag; +class RpcMethod; template class RpcMethodHandler; template @@ -66,16 +78,11 @@ class ServerStreamingHandler; template class BidiStreamingHandler; class UnknownMethodHandler; - -class Channel; -class ChannelInterface; -class ClientContext; -class CompletionQueueTag; -class CompletionQueue; -class RpcMethod; -class Server; -class ServerBuilder; -class ServerContext; +template +class TemplatedBidiStreamingHandler; +template +class BlockingUnaryCallImpl; +} // namespace internal extern CoreCodegenInterface* g_core_codegen_interface; @@ -220,22 +227,18 @@ class CompletionQueue : private GrpcLibraryCodegen { template friend class ::grpc::internal::ServerReaderWriterBody; template - friend class RpcMethodHandler; + friend class ::grpc::internal::RpcMethodHandler; template - friend class ClientStreamingHandler; + friend class ::grpc::internal::ClientStreamingHandler; template - friend class ServerStreamingHandler; + friend class ::grpc::internal::ServerStreamingHandler; template - friend class TemplatedBidiStreamingHandler; - friend class UnknownMethodHandler; + friend class ::grpc::internal::TemplatedBidiStreamingHandler; + friend class ::grpc::internal::UnknownMethodHandler; friend class ::grpc::Server; friend class ::grpc::ServerContext; template - friend Status BlockingUnaryCall(ChannelInterface* channel, - const RpcMethod& method, - ClientContext* context, - const InputMessage& request, - OutputMessage* result); + friend class ::grpc::internal::BlockingUnaryCallImpl; /// EXPERIMENTAL /// Creates a Thread Local cache to store the first event @@ -256,7 +259,7 @@ class CompletionQueue : private GrpcLibraryCodegen { /// Wraps \a grpc_completion_queue_pluck. /// \warning Must not be mixed with calls to \a Next. - bool Pluck(CompletionQueueTag* tag) { + bool Pluck(internal::CompletionQueueTag* tag) { auto deadline = g_core_codegen_interface->gpr_inf_future(GPR_CLOCK_REALTIME); auto ev = g_core_codegen_interface->grpc_completion_queue_pluck( @@ -277,7 +280,7 @@ class CompletionQueue : private GrpcLibraryCodegen { /// implementation to simple call the other TryPluck function with a zero /// timeout. i.e: /// TryPluck(tag, gpr_time_0(GPR_CLOCK_REALTIME)) - void TryPluck(CompletionQueueTag* tag) { + void TryPluck(internal::CompletionQueueTag* tag) { auto deadline = g_core_codegen_interface->gpr_time_0(GPR_CLOCK_REALTIME); auto ev = g_core_codegen_interface->grpc_completion_queue_pluck( cq_, tag, deadline, nullptr); @@ -293,7 +296,7 @@ class CompletionQueue : private GrpcLibraryCodegen { /// /// This exects tag->FinalizeResult (if called) to return 'false' i.e expects /// that the tag is internal not something that is returned to the user. - void TryPluck(CompletionQueueTag* tag, gpr_timespec deadline) { + void TryPluck(internal::CompletionQueueTag* tag, gpr_timespec deadline) { auto ev = g_core_codegen_interface->grpc_completion_queue_pluck( cq_, tag, deadline, nullptr); if (ev.type == GRPC_QUEUE_TIMEOUT || ev.type == GRPC_QUEUE_SHUTDOWN) { diff --git a/include/grpc++/impl/codegen/completion_queue_tag.h b/include/grpc++/impl/codegen/completion_queue_tag.h index 4d7d3a98dd8..cb16bcf9ff5 100644 --- a/include/grpc++/impl/codegen/completion_queue_tag.h +++ b/include/grpc++/impl/codegen/completion_queue_tag.h @@ -21,6 +21,7 @@ namespace grpc { +namespace internal { /// An interface allowing implementors to process and filter event tags. class CompletionQueueTag { public: @@ -31,6 +32,7 @@ class CompletionQueueTag { /// queue virtual bool FinalizeResult(void** tag, bool* status) = 0; }; +} // namespace internal } // namespace grpc diff --git a/include/grpc++/impl/codegen/metadata_map.h b/include/grpc++/impl/codegen/metadata_map.h index b73985967d3..fd4750efdd1 100644 --- a/include/grpc++/impl/codegen/metadata_map.h +++ b/include/grpc++/impl/codegen/metadata_map.h @@ -23,6 +23,7 @@ namespace grpc { +namespace internal { class MetadataMap { public: MetadataMap() { memset(&arr_, 0, sizeof(arr_)); } @@ -50,6 +51,7 @@ class MetadataMap { grpc_metadata_array arr_; std::multimap map_; }; +} // namespace internal } // namespace grpc diff --git a/include/grpc++/impl/codegen/method_handler_impl.h b/include/grpc++/impl/codegen/method_handler_impl.h index e14cb0e9265..c0af4ca1307 100644 --- a/include/grpc++/impl/codegen/method_handler_impl.h +++ b/include/grpc++/impl/codegen/method_handler_impl.h @@ -26,6 +26,7 @@ namespace grpc { +namespace internal { /// A wrapper class of an application provided rpc method handler. template class RpcMethodHandler : public MethodHandler { @@ -266,6 +267,7 @@ class UnknownMethodHandler : public MethodHandler { } }; +} // namespace internal } // namespace grpc #endif // GRPCXX_IMPL_CODEGEN_METHOD_HANDLER_IMPL_H diff --git a/include/grpc++/impl/codegen/rpc_method.h b/include/grpc++/impl/codegen/rpc_method.h index ac13ac56c7a..54e52364ef3 100644 --- a/include/grpc++/impl/codegen/rpc_method.h +++ b/include/grpc++/impl/codegen/rpc_method.h @@ -24,7 +24,7 @@ #include namespace grpc { - +namespace internal { /// Descriptor of an RPC method class RpcMethod { public: @@ -55,6 +55,7 @@ class RpcMethod { void* const channel_tag_; }; +} // namespace internal } // namespace grpc #endif // GRPCXX_IMPL_CODEGEN_RPC_METHOD_H diff --git a/include/grpc++/impl/codegen/rpc_service_method.h b/include/grpc++/impl/codegen/rpc_service_method.h index d356012ad60..5ba11e8559b 100644 --- a/include/grpc++/impl/codegen/rpc_service_method.h +++ b/include/grpc++/impl/codegen/rpc_service_method.h @@ -32,8 +32,8 @@ namespace grpc { class ServerContext; -class StreamContextInterface; +namespace internal { /// Base class for running an RPC handler. class MethodHandler { public: @@ -71,6 +71,7 @@ class RpcServiceMethod : public RpcMethod { void* server_tag_; std::unique_ptr handler_; }; +} // namespace internal } // namespace grpc diff --git a/include/grpc++/impl/codegen/server_context.h b/include/grpc++/impl/codegen/server_context.h index b5e37fd12b1..a2d6967bf84 100644 --- a/include/grpc++/impl/codegen/server_context.h +++ b/include/grpc++/impl/codegen/server_context.h @@ -55,7 +55,6 @@ class ServerWriter; namespace internal { template class ServerReaderWriterBody; -} template class RpcMethodHandler; template @@ -65,9 +64,11 @@ class ServerStreamingHandler; template class BidiStreamingHandler; class UnknownMethodHandler; - +template +class TemplatedBidiStreamingHandler; class Call; -class CallOpBuffer; +} // namespace internal + class CompletionQueue; class Server; class ServerInterface; @@ -247,14 +248,14 @@ class ServerContext { template friend class ::grpc::internal::ServerReaderWriterBody; template - friend class RpcMethodHandler; + friend class ::grpc::internal::RpcMethodHandler; template - friend class ClientStreamingHandler; + friend class ::grpc::internal::ClientStreamingHandler; template - friend class ServerStreamingHandler; + friend class ::grpc::internal::ServerStreamingHandler; template - friend class TemplatedBidiStreamingHandler; - friend class UnknownMethodHandler; + friend class ::grpc::internal::TemplatedBidiStreamingHandler; + friend class ::grpc::internal::UnknownMethodHandler; friend class ::grpc::ClientContext; /// Prevent copying. @@ -263,9 +264,9 @@ class ServerContext { class CompletionOp; - void BeginCompletionOp(Call* call); + void BeginCompletionOp(internal::Call* call); /// Return the tag queued by BeginCompletionOp() - CompletionQueueTag* GetCompletionOpTag(); + internal::CompletionQueueTag* GetCompletionOpTag(); ServerContext(gpr_timespec deadline, grpc_metadata_array* arr); @@ -282,7 +283,7 @@ class ServerContext { CompletionQueue* cq_; bool sent_initial_metadata_; mutable std::shared_ptr auth_context_; - MetadataMap client_metadata_; + internal::MetadataMap client_metadata_; std::multimap initial_metadata_; std::multimap trailing_metadata_; @@ -290,7 +291,9 @@ class ServerContext { grpc_compression_level compression_level_; grpc_compression_algorithm compression_algorithm_; - CallOpSet pending_ops_; + internal::CallOpSet + pending_ops_; bool has_pending_ops_; }; diff --git a/include/grpc++/impl/codegen/server_interface.h b/include/grpc++/impl/codegen/server_interface.h index 55937f19d7c..3bcf4c87e7c 100644 --- a/include/grpc++/impl/codegen/server_interface.h +++ b/include/grpc++/impl/codegen/server_interface.h @@ -30,20 +30,21 @@ namespace grpc { class AsyncGenericService; class Channel; class GenericServerContext; -class RpcService; -class ServerAsyncStreamingInterface; class ServerCompletionQueue; class ServerContext; class ServerCredentials; class Service; -class ThreadPoolInterface; extern CoreCodegenInterface* g_core_codegen_interface; /// Models a gRPC server. /// /// Servers are configured and started via \a grpc::ServerBuilder. -class ServerInterface : public CallHook { +namespace internal { +class ServerAsyncStreamingInterface; +} // namespace internal + +class ServerInterface : public internal::CallHook { public: virtual ~ServerInterface() {} @@ -78,7 +79,7 @@ class ServerInterface : public CallHook { virtual void Wait() = 0; protected: - friend class Service; + friend class ::grpc::Service; /// Register a service. This call does not take ownership of the service. /// The service must exist for the lifetime of the Server instance. @@ -116,12 +117,13 @@ class ServerInterface : public CallHook { virtual grpc_server* server() = 0; - virtual void PerformOpsOnCall(CallOpSetInterface* ops, Call* call) = 0; + virtual void PerformOpsOnCall(internal::CallOpSetInterface* ops, + internal::Call* call) = 0; - class BaseAsyncRequest : public CompletionQueueTag { + class BaseAsyncRequest : public internal::CompletionQueueTag { public: BaseAsyncRequest(ServerInterface* server, ServerContext* context, - ServerAsyncStreamingInterface* stream, + internal::ServerAsyncStreamingInterface* stream, CompletionQueue* call_cq, void* tag, bool delete_on_finalize); virtual ~BaseAsyncRequest(); @@ -131,7 +133,7 @@ class ServerInterface : public CallHook { protected: ServerInterface* const server_; ServerContext* const context_; - ServerAsyncStreamingInterface* const stream_; + internal::ServerAsyncStreamingInterface* const stream_; CompletionQueue* const call_cq_; void* const tag_; const bool delete_on_finalize_; @@ -141,7 +143,7 @@ class ServerInterface : public CallHook { class RegisteredAsyncRequest : public BaseAsyncRequest { public: RegisteredAsyncRequest(ServerInterface* server, ServerContext* context, - ServerAsyncStreamingInterface* stream, + internal::ServerAsyncStreamingInterface* stream, CompletionQueue* call_cq, void* tag); // uses BaseAsyncRequest::FinalizeResult @@ -155,7 +157,7 @@ class ServerInterface : public CallHook { public: NoPayloadAsyncRequest(void* registered_method, ServerInterface* server, ServerContext* context, - ServerAsyncStreamingInterface* stream, + internal::ServerAsyncStreamingInterface* stream, CompletionQueue* call_cq, ServerCompletionQueue* notification_cq, void* tag) : RegisteredAsyncRequest(server, context, stream, call_cq, tag) { @@ -170,7 +172,7 @@ class ServerInterface : public CallHook { public: PayloadAsyncRequest(void* registered_method, ServerInterface* server, ServerContext* context, - ServerAsyncStreamingInterface* stream, + internal::ServerAsyncStreamingInterface* stream, CompletionQueue* call_cq, ServerCompletionQueue* notification_cq, void* tag, Message* request) @@ -212,7 +214,7 @@ class ServerInterface : public CallHook { void* const registered_method_; ServerInterface* const server_; ServerContext* const context_; - ServerAsyncStreamingInterface* const stream_; + internal::ServerAsyncStreamingInterface* const stream_; CompletionQueue* const call_cq_; ServerCompletionQueue* const notification_cq_; void* const tag_; @@ -223,7 +225,7 @@ class ServerInterface : public CallHook { class GenericAsyncRequest : public BaseAsyncRequest { public: GenericAsyncRequest(ServerInterface* server, GenericServerContext* context, - ServerAsyncStreamingInterface* stream, + internal::ServerAsyncStreamingInterface* stream, CompletionQueue* call_cq, ServerCompletionQueue* notification_cq, void* tag, bool delete_on_finalize); @@ -235,8 +237,9 @@ class ServerInterface : public CallHook { }; template - void RequestAsyncCall(RpcServiceMethod* method, ServerContext* context, - ServerAsyncStreamingInterface* stream, + void RequestAsyncCall(internal::RpcServiceMethod* method, + ServerContext* context, + internal::ServerAsyncStreamingInterface* stream, CompletionQueue* call_cq, ServerCompletionQueue* notification_cq, void* tag, Message* message) { @@ -246,8 +249,9 @@ class ServerInterface : public CallHook { message); } - void RequestAsyncCall(RpcServiceMethod* method, ServerContext* context, - ServerAsyncStreamingInterface* stream, + void RequestAsyncCall(internal::RpcServiceMethod* method, + ServerContext* context, + internal::ServerAsyncStreamingInterface* stream, CompletionQueue* call_cq, ServerCompletionQueue* notification_cq, void* tag) { GPR_CODEGEN_ASSERT(method); @@ -256,7 +260,7 @@ class ServerInterface : public CallHook { } void RequestAsyncGenericCall(GenericServerContext* context, - ServerAsyncStreamingInterface* stream, + internal::ServerAsyncStreamingInterface* stream, CompletionQueue* call_cq, ServerCompletionQueue* notification_cq, void* tag) { diff --git a/include/grpc++/impl/codegen/service_type.h b/include/grpc++/impl/codegen/service_type.h index 2dc4ea0ea65..71c3d99d5c5 100644 --- a/include/grpc++/impl/codegen/service_type.h +++ b/include/grpc++/impl/codegen/service_type.h @@ -28,13 +28,14 @@ namespace grpc { -class Call; class CompletionQueue; class Server; class ServerInterface; class ServerCompletionQueue; class ServerContext; +namespace internal { +class Call; class ServerAsyncStreamingInterface { public: virtual ~ServerAsyncStreamingInterface() {} @@ -48,9 +49,10 @@ class ServerAsyncStreamingInterface { virtual void SendInitialMetadata(void* tag) = 0; private: - friend class ServerInterface; + friend class ::grpc::ServerInterface; virtual void BindCall(Call* call) = 0; }; +} // namespace internal /// Desriptor of an RPC service and its various RPC methods class Service { @@ -88,40 +90,38 @@ class Service { protected: template void RequestAsyncUnary(int index, ServerContext* context, Message* request, - ServerAsyncStreamingInterface* stream, + internal::ServerAsyncStreamingInterface* stream, CompletionQueue* call_cq, ServerCompletionQueue* notification_cq, void* tag) { server_->RequestAsyncCall(methods_[index].get(), context, stream, call_cq, notification_cq, tag, request); } - void RequestAsyncClientStreaming(int index, ServerContext* context, - ServerAsyncStreamingInterface* stream, - CompletionQueue* call_cq, - ServerCompletionQueue* notification_cq, - void* tag) { + void RequestAsyncClientStreaming( + int index, ServerContext* context, + internal::ServerAsyncStreamingInterface* stream, CompletionQueue* call_cq, + ServerCompletionQueue* notification_cq, void* tag) { server_->RequestAsyncCall(methods_[index].get(), context, stream, call_cq, notification_cq, tag); } template - void RequestAsyncServerStreaming(int index, ServerContext* context, - Message* request, - ServerAsyncStreamingInterface* stream, - CompletionQueue* call_cq, - ServerCompletionQueue* notification_cq, - void* tag) { + void RequestAsyncServerStreaming( + int index, ServerContext* context, Message* request, + internal::ServerAsyncStreamingInterface* stream, CompletionQueue* call_cq, + ServerCompletionQueue* notification_cq, void* tag) { server_->RequestAsyncCall(methods_[index].get(), context, stream, call_cq, notification_cq, tag, request); } - void RequestAsyncBidiStreaming(int index, ServerContext* context, - ServerAsyncStreamingInterface* stream, - CompletionQueue* call_cq, - ServerCompletionQueue* notification_cq, - void* tag) { + void RequestAsyncBidiStreaming( + int index, ServerContext* context, + internal::ServerAsyncStreamingInterface* stream, CompletionQueue* call_cq, + ServerCompletionQueue* notification_cq, void* tag) { server_->RequestAsyncCall(methods_[index].get(), context, stream, call_cq, notification_cq, tag); } - void AddMethod(RpcServiceMethod* method) { methods_.emplace_back(method); } + void AddMethod(internal::RpcServiceMethod* method) { + methods_.emplace_back(method); + } void MarkMethodAsync(int index) { GPR_CODEGEN_ASSERT( @@ -139,7 +139,7 @@ class Service { methods_[index].reset(); } - void MarkMethodStreamed(int index, MethodHandler* streamed_method) { + void MarkMethodStreamed(int index, internal::MethodHandler* streamed_method) { GPR_CODEGEN_ASSERT(methods_[index] && methods_[index]->handler() && "Cannot mark an async or generic method Streamed"); methods_[index]->SetHandler(streamed_method); @@ -148,14 +148,14 @@ class Service { // case of BIDI_STREAMING that has 1 read and 1 write, in that order, // and split server-side streaming is BIDI_STREAMING with 1 read and // any number of writes, in that order. - methods_[index]->SetMethodType(::grpc::RpcMethod::BIDI_STREAMING); + methods_[index]->SetMethodType(internal::RpcMethod::BIDI_STREAMING); } private: friend class Server; friend class ServerInterface; ServerInterface* server_; - std::vector> methods_; + std::vector> methods_; }; } // namespace grpc diff --git a/include/grpc++/impl/codegen/sync_stream.h b/include/grpc++/impl/codegen/sync_stream.h index c1784f1820a..49ace0beeb6 100644 --- a/include/grpc++/impl/codegen/sync_stream.h +++ b/include/grpc++/impl/codegen/sync_stream.h @@ -30,6 +30,7 @@ namespace grpc { +namespace internal { /// Common interface for all synchronous client side streaming. class ClientStreamingInterface { public: @@ -141,10 +142,12 @@ class WriterInterface { } }; +} // namespace internal + /// Client-side interface for streaming reads of message of type \a R. template -class ClientReaderInterface : public ClientStreamingInterface, - public ReaderInterface { +class ClientReaderInterface : public internal::ClientStreamingInterface, + public internal::ReaderInterface { public: /// Block to wait for initial metadata from server. The received metadata /// can only be accessed after this call returns. Should only be called before @@ -159,28 +162,14 @@ class ClientReaderInterface : public ClientStreamingInterface, template class ClientReader final : public ClientReaderInterface { public: - /// Block to create a stream and write the initial metadata and \a request - /// out. Note that \a context will be used to fill in custom initial - /// metadata used to send to the server when starting the call. - template - ClientReader(ChannelInterface* channel, const RpcMethod& method, - ClientContext* context, const W& request) - : context_(context), - cq_(grpc_completion_queue_attributes{ - GRPC_CQ_CURRENT_VERSION, GRPC_CQ_PLUCK, - GRPC_CQ_DEFAULT_POLLING}), // Pluckable cq - call_(channel->CreateCall(method, context, &cq_)) { - CallOpSet - ops; - ops.SendInitialMetadata(context->send_initial_metadata_, - context->initial_metadata_flags()); - // TODO(ctiller): don't assert - GPR_CODEGEN_ASSERT(ops.SendMessage(request).ok()); - ops.ClientSendClose(); - call_.PerformOps(&ops); - cq_.Pluck(&ops); - } + struct internal { + template + static ClientReader* Create(ChannelInterface* channel, + const ::grpc::internal::RpcMethod& method, + ClientContext* context, const W& request) { + return new ClientReader(channel, method, context, request); + } + }; /// See the \a ClientStreamingInterface.WaitForInitialMetadata method for /// semantics. @@ -192,7 +181,8 @@ class ClientReader final : public ClientReaderInterface { void WaitForInitialMetadata() override { GPR_CODEGEN_ASSERT(!context_->initial_metadata_received_); - CallOpSet ops; + ::grpc::internal::CallOpSet<::grpc::internal::CallOpRecvInitialMetadata> + ops; ops.RecvInitialMetadata(context_); call_.PerformOps(&ops); cq_.Pluck(&ops); /// status ignored @@ -209,7 +199,9 @@ class ClientReader final : public ClientReaderInterface { /// already received (if initial metadata is received, it can be then /// accessed through the \a ClientContext associated with this call). bool Read(R* msg) override { - CallOpSet> ops; + ::grpc::internal::CallOpSet<::grpc::internal::CallOpRecvInitialMetadata, + ::grpc::internal::CallOpRecvMessage> + ops; if (!context_->initial_metadata_received_) { ops.RecvInitialMetadata(context_); } @@ -224,7 +216,7 @@ class ClientReader final : public ClientReaderInterface { /// The \a ClientContext associated with this call is updated with /// possible metadata received from the server. Status Finish() override { - CallOpSet ops; + ::grpc::internal::CallOpSet<::grpc::internal::CallOpClientRecvStatus> ops; Status status; ops.ClientRecvStatus(context_, &status); call_.PerformOps(&ops); @@ -235,13 +227,38 @@ class ClientReader final : public ClientReaderInterface { private: ClientContext* context_; CompletionQueue cq_; - Call call_; + ::grpc::internal::Call call_; + + /// Block to create a stream and write the initial metadata and \a request + /// out. Note that \a context will be used to fill in custom initial + /// metadata used to send to the server when starting the call. + template + ClientReader(::grpc::ChannelInterface* channel, + const ::grpc::internal::RpcMethod& method, + ClientContext* context, const W& request) + : context_(context), + cq_(grpc_completion_queue_attributes{ + GRPC_CQ_CURRENT_VERSION, GRPC_CQ_PLUCK, + GRPC_CQ_DEFAULT_POLLING}), // Pluckable cq + call_(channel->CreateCall(method, context, &cq_)) { + ::grpc::internal::CallOpSet<::grpc::internal::CallOpSendInitialMetadata, + ::grpc::internal::CallOpSendMessage, + ::grpc::internal::CallOpClientSendClose> + ops; + ops.SendInitialMetadata(context->send_initial_metadata_, + context->initial_metadata_flags()); + // TODO(ctiller): don't assert + GPR_CODEGEN_ASSERT(ops.SendMessage(request).ok()); + ops.ClientSendClose(); + call_.PerformOps(&ops); + cq_.Pluck(&ops); + } }; /// Client-side interface for streaming writes of message type \a W. template -class ClientWriterInterface : public ClientStreamingInterface, - public WriterInterface { +class ClientWriterInterface : public internal::ClientStreamingInterface, + public internal::WriterInterface { public: /// Half close writing from the client. (signal that the stream of messages /// coming from the client is complete). @@ -258,30 +275,14 @@ class ClientWriterInterface : public ClientStreamingInterface, template class ClientWriter : public ClientWriterInterface { public: - /// Block to create a stream (i.e. send request headers and other initial - /// metadata to the server). Note that \a context will be used to fill - /// in custom initial metadata. \a response will be filled in with the - /// single expected response message from the server upon a successful - /// call to the \a Finish method of this instance. - template - ClientWriter(ChannelInterface* channel, const RpcMethod& method, - ClientContext* context, R* response) - : context_(context), - cq_(grpc_completion_queue_attributes{ - GRPC_CQ_CURRENT_VERSION, GRPC_CQ_PLUCK, - GRPC_CQ_DEFAULT_POLLING}), // Pluckable cq - call_(channel->CreateCall(method, context, &cq_)) { - finish_ops_.RecvMessage(response); - finish_ops_.AllowNoMessage(); - - if (!context_->initial_metadata_corked_) { - CallOpSet ops; - ops.SendInitialMetadata(context->send_initial_metadata_, - context->initial_metadata_flags()); - call_.PerformOps(&ops); - cq_.Pluck(&ops); + struct internal { + template + static ClientWriter* Create(::grpc::ChannelInterface* channel, + const ::grpc::internal::RpcMethod& method, + ClientContext* context, R* response) { + return new ClientWriter(channel, method, context, response); } - } + }; /// See the \a ClientStreamingInterface.WaitForInitialMetadata method for /// semantics. @@ -292,7 +293,8 @@ class ClientWriter : public ClientWriterInterface { void WaitForInitialMetadata() { GPR_CODEGEN_ASSERT(!context_->initial_metadata_received_); - CallOpSet ops; + ::grpc::internal::CallOpSet<::grpc::internal::CallOpRecvInitialMetadata> + ops; ops.RecvInitialMetadata(context_); call_.PerformOps(&ops); cq_.Pluck(&ops); // status ignored @@ -304,10 +306,11 @@ class ClientWriter : public ClientWriterInterface { /// Side effect: /// Also sends initial metadata if not already sent (using the /// \a ClientContext associated with this call). - using WriterInterface::Write; + using ::grpc::internal::WriterInterface::Write; bool Write(const W& msg, WriteOptions options) override { - CallOpSet + ::grpc::internal::CallOpSet<::grpc::internal::CallOpSendInitialMetadata, + ::grpc::internal::CallOpSendMessage, + ::grpc::internal::CallOpClientSendClose> ops; if (options.is_last_message()) { @@ -328,7 +331,7 @@ class ClientWriter : public ClientWriterInterface { } bool WritesDone() override { - CallOpSet ops; + ::grpc::internal::CallOpSet<::grpc::internal::CallOpClientSendClose> ops; ops.ClientSendClose(); call_.PerformOps(&ops); return cq_.Pluck(&ops); @@ -352,21 +355,50 @@ class ClientWriter : public ClientWriterInterface { } private: + /// Block to create a stream (i.e. send request headers and other initial + /// metadata to the server). Note that \a context will be used to fill + /// in custom initial metadata. \a response will be filled in with the + /// single expected response message from the server upon a successful + /// call to the \a Finish method of this instance. + + template + ClientWriter(ChannelInterface* channel, + const ::grpc::internal::RpcMethod& method, + ClientContext* context, R* response) + : context_(context), + cq_(grpc_completion_queue_attributes{ + GRPC_CQ_CURRENT_VERSION, GRPC_CQ_PLUCK, + GRPC_CQ_DEFAULT_POLLING}), // Pluckable cq + call_(channel->CreateCall(method, context, &cq_)) { + finish_ops_.RecvMessage(response); + finish_ops_.AllowNoMessage(); + + if (!context_->initial_metadata_corked_) { + ::grpc::internal::CallOpSet<::grpc::internal::CallOpSendInitialMetadata> + ops; + ops.SendInitialMetadata(context->send_initial_metadata_, + context->initial_metadata_flags()); + call_.PerformOps(&ops); + cq_.Pluck(&ops); + } + } + ClientContext* context_; - CallOpSet + ::grpc::internal::CallOpSet<::grpc::internal::CallOpRecvInitialMetadata, + ::grpc::internal::CallOpGenericRecvMessage, + ::grpc::internal::CallOpClientRecvStatus> finish_ops_; CompletionQueue cq_; - Call call_; + ::grpc::internal::Call call_; }; /// Client-side interface for bi-directional streaming with /// client-to-server stream messages of type \a W and /// server-to-client stream messages of type \a R. template -class ClientReaderWriterInterface : public ClientStreamingInterface, - public WriterInterface, - public ReaderInterface { +class ClientReaderWriterInterface : public internal::ClientStreamingInterface, + public internal::WriterInterface, + public internal::ReaderInterface { public: /// Block to wait for initial metadata from server. The received metadata /// can only be accessed after this call returns. Should only be called before @@ -375,7 +407,7 @@ class ClientReaderWriterInterface : public ClientStreamingInterface, virtual void WaitForInitialMetadata() = 0; /// Half close writing from the client. (signal that the stream of messages - /// coming from the client is complete). + /// coming from the clinet is complete). /// Blocks until currently-pending writes are completed. /// Thread-safe with respect to \a ReaderInterface::Read /// @@ -390,24 +422,13 @@ class ClientReaderWriterInterface : public ClientStreamingInterface, template class ClientReaderWriter final : public ClientReaderWriterInterface { public: - /// Block to create a stream and write the initial metadata and \a request - /// out. Note that \a context will be used to fill in custom initial metadata - /// used to send to the server when starting the call. - ClientReaderWriter(ChannelInterface* channel, const RpcMethod& method, - ClientContext* context) - : context_(context), - cq_(grpc_completion_queue_attributes{ - GRPC_CQ_CURRENT_VERSION, GRPC_CQ_PLUCK, - GRPC_CQ_DEFAULT_POLLING}), // Pluckable cq - call_(channel->CreateCall(method, context, &cq_)) { - if (!context_->initial_metadata_corked_) { - CallOpSet ops; - ops.SendInitialMetadata(context->send_initial_metadata_, - context->initial_metadata_flags()); - call_.PerformOps(&ops); - cq_.Pluck(&ops); + struct internal { + static ClientReaderWriter* Create(::grpc::ChannelInterface* channel, + const ::grpc::internal::RpcMethod& method, + ClientContext* context) { + return new ClientReaderWriter(channel, method, context); } - } + }; /// Block waiting to read initial metadata from the server. /// This call is optional, but if it is used, it cannot be used concurrently @@ -418,7 +439,8 @@ class ClientReaderWriter final : public ClientReaderWriterInterface { void WaitForInitialMetadata() override { GPR_CODEGEN_ASSERT(!context_->initial_metadata_received_); - CallOpSet ops; + ::grpc::internal::CallOpSet<::grpc::internal::CallOpRecvInitialMetadata> + ops; ops.RecvInitialMetadata(context_); call_.PerformOps(&ops); cq_.Pluck(&ops); // status ignored @@ -434,7 +456,9 @@ class ClientReaderWriter final : public ClientReaderWriterInterface { /// Also receives initial metadata if not already received (updates the \a /// ClientContext associated with this call in that case). bool Read(R* msg) override { - CallOpSet> ops; + ::grpc::internal::CallOpSet<::grpc::internal::CallOpRecvInitialMetadata, + ::grpc::internal::CallOpRecvMessage> + ops; if (!context_->initial_metadata_received_) { ops.RecvInitialMetadata(context_); } @@ -448,10 +472,11 @@ class ClientReaderWriter final : public ClientReaderWriterInterface { /// Side effect: /// Also sends initial metadata if not already sent (using the /// \a ClientContext associated with this call to fill in values). - using WriterInterface::Write; + using ::grpc::internal::WriterInterface::Write; bool Write(const W& msg, WriteOptions options) override { - CallOpSet + ::grpc::internal::CallOpSet<::grpc::internal::CallOpSendInitialMetadata, + ::grpc::internal::CallOpSendMessage, + ::grpc::internal::CallOpClientSendClose> ops; if (options.is_last_message()) { @@ -472,7 +497,7 @@ class ClientReaderWriter final : public ClientReaderWriterInterface { } bool WritesDone() override { - CallOpSet ops; + ::grpc::internal::CallOpSet<::grpc::internal::CallOpClientSendClose> ops; ops.ClientSendClose(); call_.PerformOps(&ops); return cq_.Pluck(&ops); @@ -484,7 +509,9 @@ class ClientReaderWriter final : public ClientReaderWriterInterface { /// - the \a ClientContext associated with this call is updated with /// possible trailing metadata sent from the server. Status Finish() override { - CallOpSet ops; + ::grpc::internal::CallOpSet<::grpc::internal::CallOpRecvInitialMetadata, + ::grpc::internal::CallOpClientRecvStatus> + ops; if (!context_->initial_metadata_received_) { ops.RecvInitialMetadata(context_); } @@ -498,13 +525,34 @@ class ClientReaderWriter final : public ClientReaderWriterInterface { private: ClientContext* context_; CompletionQueue cq_; - Call call_; + ::grpc::internal::Call call_; + + /// Block to create a stream and write the initial metadata and \a request + /// out. Note that \a context will be used to fill in custom initial metadata + /// used to send to the server when starting the call. + ClientReaderWriter(::grpc::ChannelInterface* channel, + const ::grpc::internal::RpcMethod& method, + ClientContext* context) + : context_(context), + cq_(grpc_completion_queue_attributes{ + GRPC_CQ_CURRENT_VERSION, GRPC_CQ_PLUCK, + GRPC_CQ_DEFAULT_POLLING}), // Pluckable cq + call_(channel->CreateCall(method, context, &cq_)) { + if (!context_->initial_metadata_corked_) { + ::grpc::internal::CallOpSet<::grpc::internal::CallOpSendInitialMetadata> + ops; + ops.SendInitialMetadata(context->send_initial_metadata_, + context->initial_metadata_flags()); + call_.PerformOps(&ops); + cq_.Pluck(&ops); + } + } }; /// Server-side interface for streaming reads of message of type \a R. template -class ServerReaderInterface : public ServerStreamingInterface, - public ReaderInterface {}; +class ServerReaderInterface : public internal::ServerStreamingInterface, + public internal::ReaderInterface {}; /// Synchronous (blocking) server-side API for doing client-streaming RPCs, /// where the incoming message stream coming from the client has messages of @@ -512,15 +560,13 @@ class ServerReaderInterface : public ServerStreamingInterface, template class ServerReader final : public ServerReaderInterface { public: - ServerReader(Call* call, ServerContext* ctx) : call_(call), ctx_(ctx) {} - /// See the \a ServerStreamingInterface.SendInitialMetadata method /// for semantics. Note that initial metadata will be affected by the /// \a ServerContext associated with this call. void SendInitialMetadata() override { GPR_CODEGEN_ASSERT(!ctx_->sent_initial_metadata_); - CallOpSet ops; + internal::CallOpSet ops; ops.SendInitialMetadata(ctx_->initial_metadata_, ctx_->initial_metadata_flags()); if (ctx_->compression_level_set()) { @@ -537,21 +583,27 @@ class ServerReader final : public ServerReaderInterface { } bool Read(R* msg) override { - CallOpSet> ops; + internal::CallOpSet> ops; ops.RecvMessage(msg); call_->PerformOps(&ops); return call_->cq()->Pluck(&ops) && ops.got_message; } private: - Call* const call_; + internal::Call* const call_; ServerContext* const ctx_; + + template + friend class internal::ClientStreamingHandler; + + ServerReader(internal::Call* call, ServerContext* ctx) + : call_(call), ctx_(ctx) {} }; /// Server-side interface for streaming writes of message of type \a W. template -class ServerWriterInterface : public ServerStreamingInterface, - public WriterInterface {}; +class ServerWriterInterface : public internal::ServerStreamingInterface, + public internal::WriterInterface {}; /// Synchronous (blocking) server-side API for doing for doing a /// server-streaming RPCs, where the outgoing message stream coming from the @@ -559,8 +611,6 @@ class ServerWriterInterface : public ServerStreamingInterface, template class ServerWriter final : public ServerWriterInterface { public: - ServerWriter(Call* call, ServerContext* ctx) : call_(call), ctx_(ctx) {} - /// See the \a ServerStreamingInterface.SendInitialMetadata method /// for semantics. /// Note that initial metadata will be affected by the @@ -568,7 +618,7 @@ class ServerWriter final : public ServerWriterInterface { void SendInitialMetadata() override { GPR_CODEGEN_ASSERT(!ctx_->sent_initial_metadata_); - CallOpSet ops; + internal::CallOpSet ops; ops.SendInitialMetadata(ctx_->initial_metadata_, ctx_->initial_metadata_flags()); if (ctx_->compression_level_set()) { @@ -584,11 +634,12 @@ class ServerWriter final : public ServerWriterInterface { /// Side effect: /// Also sends initial metadata if not already sent (using the /// \a ClientContext associated with this call to fill in values). - using WriterInterface::Write; + using internal::WriterInterface::Write; bool Write(const W& msg, WriteOptions options) override { if (options.is_last_message()) { options.set_buffer_hint(); } + if (!ctx_->pending_ops_.SendMessage(msg, options).ok()) { return false; } @@ -613,15 +664,21 @@ class ServerWriter final : public ServerWriterInterface { } private: - Call* const call_; + internal::Call* const call_; ServerContext* const ctx_; + + template + friend class internal::ServerStreamingHandler; + + ServerWriter(internal::Call* call, ServerContext* ctx) + : call_(call), ctx_(ctx) {} }; /// Server-side interface for bi-directional streaming. template -class ServerReaderWriterInterface : public ServerStreamingInterface, - public WriterInterface, - public ReaderInterface {}; +class ServerReaderWriterInterface : public internal::ServerStreamingInterface, + public internal::WriterInterface, + public internal::ReaderInterface {}; /// Actual implementation of bi-directional streaming namespace internal { @@ -688,6 +745,7 @@ class ServerReaderWriterBody final { Call* const call_; ServerContext* const ctx_; }; + } // namespace internal /// Synchronous (blocking) server-side API for a bidirectional @@ -697,8 +755,6 @@ class ServerReaderWriterBody final { template class ServerReaderWriter final : public ServerReaderWriterInterface { public: - ServerReaderWriter(Call* call, ServerContext* ctx) : body_(call, ctx) {} - /// See the \a ServerStreamingInterface.SendInitialMetadata method /// for semantics. Note that initial metadata will be affected by the /// \a ServerContext associated with this call. @@ -715,13 +771,18 @@ class ServerReaderWriter final : public ServerReaderWriterInterface { /// Side effect: /// Also sends initial metadata if not already sent (using the \a /// ServerContext associated with this call). - using WriterInterface::Write; + using internal::WriterInterface::Write; bool Write(const W& msg, WriteOptions options) override { return body_.Write(msg, options); } private: internal::ServerReaderWriterBody body_; + + friend class internal::TemplatedBidiStreamingHandler, + false>; + ServerReaderWriter(internal::Call* call, ServerContext* ctx) + : body_(call, ctx) {} }; /// A class to represent a flow-controlled unary call. This is something @@ -736,9 +797,6 @@ template class ServerUnaryStreamer final : public ServerReaderWriterInterface { public: - ServerUnaryStreamer(Call* call, ServerContext* ctx) - : body_(call, ctx), read_done_(false), write_done_(false) {} - /// Block to send initial metadata to client. /// Implicit input parameter: /// - the \a ServerContext associated with this call will be used for @@ -775,7 +833,7 @@ class ServerUnaryStreamer final /// \param options The WriteOptions affecting the write operation. /// /// \return \a true on success, \a false when the stream has been closed. - using WriterInterface::Write; + using internal::WriterInterface::Write; bool Write(const ResponseType& response, WriteOptions options) override { if (write_done_ || !read_done_) { return false; @@ -788,6 +846,11 @@ class ServerUnaryStreamer final internal::ServerReaderWriterBody body_; bool read_done_; bool write_done_; + + friend class internal::TemplatedBidiStreamingHandler< + ServerUnaryStreamer, true>; + ServerUnaryStreamer(internal::Call* call, ServerContext* ctx) + : body_(call, ctx), read_done_(false), write_done_(false) {} }; /// A class to represent a flow-controlled server-side streaming call. @@ -799,9 +862,6 @@ template class ServerSplitStreamer final : public ServerReaderWriterInterface { public: - ServerSplitStreamer(Call* call, ServerContext* ctx) - : body_(call, ctx), read_done_(false) {} - /// Block to send initial metadata to client. /// Implicit input parameter: /// - the \a ServerContext associated with this call will be used for @@ -838,7 +898,7 @@ class ServerSplitStreamer final /// \param options The WriteOptions affecting the write operation. /// /// \return \a true on success, \a false when the stream has been closed. - using WriterInterface::Write; + using internal::WriterInterface::Write; bool Write(const ResponseType& response, WriteOptions options) override { return read_done_ && body_.Write(response, options); } @@ -846,6 +906,11 @@ class ServerSplitStreamer final private: internal::ServerReaderWriterBody body_; bool read_done_; + + friend class internal::TemplatedBidiStreamingHandler< + ServerSplitStreamer, false>; + ServerSplitStreamer(internal::Call* call, ServerContext* ctx) + : body_(call, ctx), read_done_(false) {} }; } // namespace grpc diff --git a/include/grpc++/impl/codegen/time.h b/include/grpc++/impl/codegen/time.h index 589deb4f03d..d464d6ea136 100644 --- a/include/grpc++/impl/codegen/time.h +++ b/include/grpc++/impl/codegen/time.h @@ -19,6 +19,8 @@ #ifndef GRPCXX_IMPL_CODEGEN_TIME_H #define GRPCXX_IMPL_CODEGEN_TIME_H +#include + #include #include @@ -59,10 +61,6 @@ class TimePoint { } // namespace grpc -#include - -#include - namespace grpc { // from and to should be absolute time. diff --git a/include/grpc++/server.h b/include/grpc++/server.h index 0a3aae8241c..01c4a60d216 100644 --- a/include/grpc++/server.h +++ b/include/grpc++/server.h @@ -175,7 +175,8 @@ class Server final : public ServerInterface, private GrpcLibraryCodegen { /// \param num_cqs How many completion queues does \a cqs hold. void Start(ServerCompletionQueue** cqs, size_t num_cqs) override; - void PerformOpsOnCall(CallOpSetInterface* ops, Call* call) override; + void PerformOpsOnCall(internal::CallOpSetInterface* ops, + internal::Call* call) override; void ShutdownInternal(gpr_timespec deadline) override; diff --git a/include/grpc++/server_builder.h b/include/grpc++/server_builder.h index a948abedb58..0888bef0d95 100644 --- a/include/grpc++/server_builder.h +++ b/include/grpc++/server_builder.h @@ -40,7 +40,6 @@ namespace grpc { class AsyncGenericService; class ResourceQuota; class CompletionQueue; -class RpcService; class Server; class ServerCompletionQueue; class ServerCredentials; diff --git a/src/compiler/cpp_generator.cc b/src/compiler/cpp_generator.cc index c2db8eff714..9efd6208b0e 100644 --- a/src/compiler/cpp_generator.cc +++ b/src/compiler/cpp_generator.cc @@ -140,7 +140,6 @@ grpc::string GetHeaderIncludes(grpc_generator::File *file, printer->Print(vars, "namespace grpc {\n"); printer->Print(vars, "class CompletionQueue;\n"); printer->Print(vars, "class Channel;\n"); - printer->Print(vars, "class RpcService;\n"); printer->Print(vars, "class ServerCompletionQueue;\n"); printer->Print(vars, "class ServerContext;\n"); printer->Print(vars, "} // namespace grpc\n\n"); @@ -324,7 +323,8 @@ void PrintHeaderClientMethodInterfaces( } else if (ServerOnlyStreaming(method)) { printer->Print( *vars, - "virtual ::grpc::ClientReaderInterface< $Response$>* $Method$Raw(" + "virtual ::grpc::ClientReaderInterface< $Response$>* " + "$Method$Raw(" "::grpc::ClientContext* context, const $Request$& request) = 0;\n"); for (auto async_prefix : async_prefixes) { (*vars)["AsyncPrefix"] = async_prefix.prefix; @@ -546,7 +546,8 @@ void PrintHeaderClientMethodData(grpc_generator::Printer *printer, const grpc_generator::Method *method, std::map *vars) { (*vars)["Method"] = method->name(); - printer->Print(*vars, "const ::grpc::RpcMethod rpcmethod_$Method$_;\n"); + printer->Print(*vars, + "const ::grpc::internal::RpcMethod rpcmethod_$Method$_;\n"); } void PrintHeaderServerMethodSync(grpc_generator::Printer *printer, @@ -718,7 +719,7 @@ void PrintHeaderServerMethodStreamedUnary( printer->Print(*vars, "WithStreamedUnaryMethod_$Method$() {\n" " ::grpc::Service::MarkMethodStreamed($Idx$,\n" - " new ::grpc::StreamedUnaryHandler< $Request$, " + " new ::grpc::internal::StreamedUnaryHandler< $Request$, " "$Response$>(std::bind" "(&WithStreamedUnaryMethod_$Method$::" "Streamed$Method$, this, std::placeholders::_1, " @@ -766,15 +767,16 @@ void PrintHeaderServerMethodSplitStreaming( "{}\n"); printer->Print(" public:\n"); printer->Indent(); - printer->Print(*vars, - "WithSplitStreamingMethod_$Method$() {\n" - " ::grpc::Service::MarkMethodStreamed($Idx$,\n" - " new ::grpc::SplitServerStreamingHandler< $Request$, " - "$Response$>(std::bind" - "(&WithSplitStreamingMethod_$Method$::" - "Streamed$Method$, this, std::placeholders::_1, " - "std::placeholders::_2)));\n" - "}\n"); + printer->Print( + *vars, + "WithSplitStreamingMethod_$Method$() {\n" + " ::grpc::Service::MarkMethodStreamed($Idx$,\n" + " new ::grpc::internal::SplitServerStreamingHandler< $Request$, " + "$Response$>(std::bind" + "(&WithSplitStreamingMethod_$Method$::" + "Streamed$Method$, this, std::placeholders::_1, " + "std::placeholders::_2)));\n" + "}\n"); printer->Print(*vars, "~WithSplitStreamingMethod_$Method$() override {\n" " BaseClassMustBeDerivedFromService(this);\n" @@ -914,7 +916,8 @@ void PrintHeaderService(grpc_generator::Printer *printer, " {\n public:\n"); printer->Indent(); printer->Print( - "Stub(const std::shared_ptr< ::grpc::ChannelInterface>& channel);\n"); + "Stub(const std::shared_ptr< ::grpc::ChannelInterface>& " + "channel);\n"); for (int i = 0; i < service->method_count(); ++i) { PrintHeaderClientMethod(printer, service->method(i).get(), vars, true); } @@ -1185,10 +1188,9 @@ void PrintSourceClientMethod(grpc_generator::Printer *printer, "::grpc::ClientContext* context, " "const $Request$& request, $Response$* response) {\n"); printer->Print(*vars, - " return ::grpc::BlockingUnaryCall(channel_.get(), " - "rpcmethod_$Method$_, " - "context, request, response);\n" - "}\n\n"); + " return ::grpc::internal::BlockingUnaryCall" + "(channel_.get(), rpcmethod_$Method$_, " + "context, request, response);\n}\n\n"); for (auto async_prefix : async_prefixes) { (*vars)["AsyncPrefix"] = async_prefix.prefix; (*vars)["AsyncStart"] = async_prefix.start; @@ -1198,25 +1200,27 @@ void PrintSourceClientMethod(grpc_generator::Printer *printer, "ClientContext* context, " "const $Request$& request, " "::grpc::CompletionQueue* cq) {\n"); - printer->Print(*vars, - " return " - "::grpc::ClientAsyncResponseReader< $Response$>::Create(" - "channel_.get(), cq, " - "rpcmethod_$Method$_, " - "context, request, $AsyncStart$);\n" - "}\n\n"); + printer->Print( + *vars, + " return " + "::grpc::ClientAsyncResponseReader< $Response$>::internal::Create(" + "channel_.get(), cq, " + "rpcmethod_$Method$_, " + "context, request, $AsyncStart$);\n" + "}\n\n"); } } else if (ClientOnlyStreaming(method)) { printer->Print(*vars, "::grpc::ClientWriter< $Request$>* " "$ns$$Service$::Stub::$Method$Raw(" "::grpc::ClientContext* context, $Response$* response) {\n"); - printer->Print(*vars, - " return new ::grpc::ClientWriter< $Request$>(" - "channel_.get(), " - "rpcmethod_$Method$_, " - "context, response);\n" - "}\n\n"); + printer->Print( + *vars, + " return ::grpc::ClientWriter< $Request$>::internal::Create(" + "channel_.get(), " + "rpcmethod_$Method$_, " + "context, response);\n" + "}\n\n"); for (auto async_prefix : async_prefixes) { (*vars)["AsyncPrefix"] = async_prefix.prefix; (*vars)["AsyncStart"] = async_prefix.start; @@ -1227,12 +1231,13 @@ void PrintSourceClientMethod(grpc_generator::Printer *printer, "$ns$$Service$::Stub::$AsyncPrefix$$Method$Raw(" "::grpc::ClientContext* context, $Response$* response, " "::grpc::CompletionQueue* cq$AsyncMethodParams$) {\n"); - printer->Print(*vars, - " return ::grpc::ClientAsyncWriter< $Request$>::Create(" - "channel_.get(), cq, " - "rpcmethod_$Method$_, " - "context, response, $AsyncStart$$AsyncCreateArgs$);\n" - "}\n\n"); + printer->Print( + *vars, + " return ::grpc::ClientAsyncWriter< $Request$>::internal::Create(" + "channel_.get(), cq, " + "rpcmethod_$Method$_, " + "context, response, $AsyncStart$$AsyncCreateArgs$);\n" + "}\n\n"); } } else if (ServerOnlyStreaming(method)) { printer->Print( @@ -1240,12 +1245,13 @@ void PrintSourceClientMethod(grpc_generator::Printer *printer, "::grpc::ClientReader< $Response$>* " "$ns$$Service$::Stub::$Method$Raw(" "::grpc::ClientContext* context, const $Request$& request) {\n"); - printer->Print(*vars, - " return new ::grpc::ClientReader< $Response$>(" - "channel_.get(), " - "rpcmethod_$Method$_, " - "context, request);\n" - "}\n\n"); + printer->Print( + *vars, + " return ::grpc::ClientReader< $Response$>::internal::Create(" + "channel_.get(), " + "rpcmethod_$Method$_, " + "context, request);\n" + "}\n\n"); for (auto async_prefix : async_prefixes) { (*vars)["AsyncPrefix"] = async_prefix.prefix; (*vars)["AsyncStart"] = async_prefix.start; @@ -1257,12 +1263,13 @@ void PrintSourceClientMethod(grpc_generator::Printer *printer, "$ns$$Service$::Stub::$AsyncPrefix$$Method$Raw(" "::grpc::ClientContext* context, const $Request$& request, " "::grpc::CompletionQueue* cq$AsyncMethodParams$) {\n"); - printer->Print(*vars, - " return ::grpc::ClientAsyncReader< $Response$>::Create(" - "channel_.get(), cq, " - "rpcmethod_$Method$_, " - "context, request, $AsyncStart$$AsyncCreateArgs$);\n" - "}\n\n"); + printer->Print( + *vars, + " return ::grpc::ClientAsyncReader< $Response$>::internal::Create(" + "channel_.get(), cq, " + "rpcmethod_$Method$_, " + "context, request, $AsyncStart$$AsyncCreateArgs$);\n" + "}\n\n"); } } else if (method->BidiStreaming()) { printer->Print( @@ -1270,8 +1277,8 @@ void PrintSourceClientMethod(grpc_generator::Printer *printer, "::grpc::ClientReaderWriter< $Request$, $Response$>* " "$ns$$Service$::Stub::$Method$Raw(::grpc::ClientContext* context) {\n"); printer->Print(*vars, - " return new ::grpc::ClientReaderWriter< " - "$Request$, $Response$>(" + " return ::grpc::ClientReaderWriter< " + "$Request$, $Response$>::internal::Create(" "channel_.get(), " "rpcmethod_$Method$_, " "context);\n" @@ -1286,14 +1293,14 @@ void PrintSourceClientMethod(grpc_generator::Printer *printer, "$ns$$Service$::Stub::$AsyncPrefix$$Method$Raw(::grpc::" "ClientContext* context, " "::grpc::CompletionQueue* cq$AsyncMethodParams$) {\n"); - printer->Print( - *vars, - " return " - "::grpc::ClientAsyncReaderWriter< $Request$, $Response$>::Create(" - "channel_.get(), cq, " - "rpcmethod_$Method$_, " - "context, $AsyncStart$$AsyncCreateArgs$);\n" - "}\n\n"); + printer->Print(*vars, + " return " + "::grpc::ClientAsyncReaderWriter< $Request$, " + "$Response$>::internal::Create(" + "channel_.get(), cq, " + "rpcmethod_$Method$_, " + "context, $AsyncStart$$AsyncCreateArgs$);\n" + "}\n\n"); } } } @@ -1404,7 +1411,7 @@ void PrintSourceService(grpc_generator::Printer *printer, printer->Print(*vars, ", rpcmethod_$Method$_(" "$prefix$$Service$_method_names[$Idx$], " - "::grpc::RpcMethod::$StreamingType$, " + "::grpc::internal::RpcMethod::$StreamingType$, " "channel" ")\n"); } @@ -1427,38 +1434,38 @@ void PrintSourceService(grpc_generator::Printer *printer, if (method->NoStreaming()) { printer->Print( *vars, - "AddMethod(new ::grpc::RpcServiceMethod(\n" + "AddMethod(new ::grpc::internal::RpcServiceMethod(\n" " $prefix$$Service$_method_names[$Idx$],\n" - " ::grpc::RpcMethod::NORMAL_RPC,\n" - " new ::grpc::RpcMethodHandler< $ns$$Service$::Service, " + " ::grpc::internal::RpcMethod::NORMAL_RPC,\n" + " new ::grpc::internal::RpcMethodHandler< $ns$$Service$::Service, " "$Request$, " "$Response$>(\n" " std::mem_fn(&$ns$$Service$::Service::$Method$), this)));\n"); } else if (ClientOnlyStreaming(method.get())) { printer->Print( *vars, - "AddMethod(new ::grpc::RpcServiceMethod(\n" + "AddMethod(new ::grpc::internal::RpcServiceMethod(\n" " $prefix$$Service$_method_names[$Idx$],\n" - " ::grpc::RpcMethod::CLIENT_STREAMING,\n" - " new ::grpc::ClientStreamingHandler< " + " ::grpc::internal::RpcMethod::CLIENT_STREAMING,\n" + " new ::grpc::internal::ClientStreamingHandler< " "$ns$$Service$::Service, $Request$, $Response$>(\n" " std::mem_fn(&$ns$$Service$::Service::$Method$), this)));\n"); } else if (ServerOnlyStreaming(method.get())) { printer->Print( *vars, - "AddMethod(new ::grpc::RpcServiceMethod(\n" + "AddMethod(new ::grpc::internal::RpcServiceMethod(\n" " $prefix$$Service$_method_names[$Idx$],\n" - " ::grpc::RpcMethod::SERVER_STREAMING,\n" - " new ::grpc::ServerStreamingHandler< " + " ::grpc::internal::RpcMethod::SERVER_STREAMING,\n" + " new ::grpc::internal::ServerStreamingHandler< " "$ns$$Service$::Service, $Request$, $Response$>(\n" " std::mem_fn(&$ns$$Service$::Service::$Method$), this)));\n"); } else if (method->BidiStreaming()) { printer->Print( *vars, - "AddMethod(new ::grpc::RpcServiceMethod(\n" + "AddMethod(new ::grpc::internal::RpcServiceMethod(\n" " $prefix$$Service$_method_names[$Idx$],\n" - " ::grpc::RpcMethod::BIDI_STREAMING,\n" - " new ::grpc::BidiStreamingHandler< " + " ::grpc::internal::RpcMethod::BIDI_STREAMING,\n" + " new ::grpc::internal::BidiStreamingHandler< " "$ns$$Service$::Service, $Request$, $Response$>(\n" " std::mem_fn(&$ns$$Service$::Service::$Method$), this)));\n"); } diff --git a/src/cpp/client/channel_cc.cc b/src/cpp/client/channel_cc.cc index 19a25c838fb..4049fc846b9 100644 --- a/src/cpp/client/channel_cc.cc +++ b/src/cpp/client/channel_cc.cc @@ -52,7 +52,7 @@ namespace { int kConnectivityCheckIntervalMsec = 500; void WatchStateChange(void* arg); -class TagSaver final : public CompletionQueueTag { +class TagSaver final : public internal::CompletionQueueTag { public: explicit TagSaver(void* tag) : tag_(tag) {} ~TagSaver() override {} @@ -259,8 +259,9 @@ grpc::string Channel::GetServiceConfigJSON() const { &channel_info.service_config_json); } -Call Channel::CreateCall(const RpcMethod& method, ClientContext* context, - CompletionQueue* cq) { +internal::Call Channel::CreateCall(const internal::RpcMethod& method, + ClientContext* context, + CompletionQueue* cq) { const bool kRegistered = method.channel_tag() && context->authority().empty(); grpc_call* c_call = NULL; if (kRegistered) { @@ -292,10 +293,11 @@ Call Channel::CreateCall(const RpcMethod& method, ClientContext* context, } grpc_census_call_set_context(c_call, context->census_context()); context->set_call(c_call, shared_from_this()); - return Call(c_call, this, cq); + return internal::Call(c_call, this, cq); } -void Channel::PerformOpsOnCall(CallOpSetInterface* ops, Call* call) { +void Channel::PerformOpsOnCall(internal::CallOpSetInterface* ops, + internal::Call* call) { static const size_t MAX_OPS = 8; size_t nops = 0; grpc_op cops[MAX_OPS]; diff --git a/src/cpp/client/generic_stub.cc b/src/cpp/client/generic_stub.cc index 693b8bea568..452a8a7501c 100644 --- a/src/cpp/client/generic_stub.cc +++ b/src/cpp/client/generic_stub.cc @@ -27,8 +27,9 @@ std::unique_ptr CallInternal( ChannelInterface* channel, ClientContext* context, const grpc::string& method, CompletionQueue* cq, bool start, void* tag) { return std::unique_ptr( - GenericClientAsyncReaderWriter::Create( - channel, cq, RpcMethod(method.c_str(), RpcMethod::BIDI_STREAMING), + GenericClientAsyncReaderWriter::internal::Create( + channel, cq, internal::RpcMethod(method.c_str(), + internal::RpcMethod::BIDI_STREAMING), context, start, tag)); } @@ -52,8 +53,9 @@ std::unique_ptr GenericStub::PrepareUnaryCall( ClientContext* context, const grpc::string& method, const ByteBuffer& request, CompletionQueue* cq) { return std::unique_ptr( - GenericClientAsyncResponseReader::Create( - channel_.get(), cq, RpcMethod(method.c_str(), RpcMethod::NORMAL_RPC), + GenericClientAsyncResponseReader::internal::Create( + channel_.get(), cq, + internal::RpcMethod(method.c_str(), internal::RpcMethod::NORMAL_RPC), context, request, false)); } diff --git a/src/cpp/common/completion_queue_cc.cc b/src/cpp/common/completion_queue_cc.cc index 4a2e2be6880..eb6dc8cc5fb 100644 --- a/src/cpp/common/completion_queue_cc.cc +++ b/src/cpp/common/completion_queue_cc.cc @@ -60,7 +60,7 @@ CompletionQueue::NextStatus CompletionQueue::AsyncNextInternal( case GRPC_QUEUE_SHUTDOWN: return SHUTDOWN; case GRPC_OP_COMPLETE: - auto cq_tag = static_cast(ev.tag); + auto cq_tag = static_cast(ev.tag); *ok = ev.success != 0; *tag = cq_tag; if (cq_tag->FinalizeResult(tag, ok)) { @@ -87,7 +87,7 @@ bool CompletionQueue::CompletionQueueTLSCache::Flush(void** tag, bool* ok) { flushed_ = true; if (grpc_completion_queue_thread_local_cache_flush(cq_->cq_, &res_tag, &res)) { - auto cq_tag = static_cast(res_tag); + auto cq_tag = static_cast(res_tag); *ok = res == 1; if (cq_tag->FinalizeResult(tag, ok)) { return true; diff --git a/src/cpp/server/health/default_health_check_service.cc b/src/cpp/server/health/default_health_check_service.cc index d2cba6d6627..10dbd3c39af 100644 --- a/src/cpp/server/health/default_health_check_service.cc +++ b/src/cpp/server/health/default_health_check_service.cc @@ -37,11 +37,12 @@ const char kHealthCheckMethodName[] = "/grpc.health.v1.Health/Check"; DefaultHealthCheckService::HealthCheckServiceImpl::HealthCheckServiceImpl( DefaultHealthCheckService* service) : service_(service), method_(nullptr) { - MethodHandler* handler = - new RpcMethodHandler( + internal::MethodHandler* handler = + new internal::RpcMethodHandler( std::mem_fn(&HealthCheckServiceImpl::Check), this); - method_ = new RpcServiceMethod(kHealthCheckMethodName, RpcMethod::NORMAL_RPC, - handler); + method_ = new internal::RpcServiceMethod( + kHealthCheckMethodName, internal::RpcMethod::NORMAL_RPC, handler); AddMethod(method_); } diff --git a/src/cpp/server/health/default_health_check_service.h b/src/cpp/server/health/default_health_check_service.h index 09d5cebe98b..99d6680c501 100644 --- a/src/cpp/server/health/default_health_check_service.h +++ b/src/cpp/server/health/default_health_check_service.h @@ -41,7 +41,7 @@ class DefaultHealthCheckService final : public HealthCheckServiceInterface { private: const DefaultHealthCheckService* const service_; - RpcServiceMethod* method_; + internal::RpcServiceMethod* method_; }; DefaultHealthCheckService(); diff --git a/src/cpp/server/server_cc.cc b/src/cpp/server/server_cc.cc index d982a3d2b76..6480482774e 100644 --- a/src/cpp/server/server_cc.cc +++ b/src/cpp/server/server_cc.cc @@ -90,7 +90,8 @@ class Server::UnimplementedAsyncRequest final ServerCompletionQueue* const cq_; }; -typedef SneakyCallOpSet +typedef internal::SneakyCallOpSet UnimplementedAsyncResponseOp; class Server::UnimplementedAsyncResponse final : public UnimplementedAsyncResponseOp { @@ -108,12 +109,12 @@ class Server::UnimplementedAsyncResponse final UnimplementedAsyncRequest* const request_; }; -class ShutdownTag : public CompletionQueueTag { +class ShutdownTag : public internal::CompletionQueueTag { public: bool FinalizeResult(void** tag, bool* status) { return false; } }; -class DummyTag : public CompletionQueueTag { +class DummyTag : public internal::CompletionQueueTag { public: bool FinalizeResult(void** tag, bool* status) { *status = true; @@ -121,15 +122,15 @@ class DummyTag : public CompletionQueueTag { } }; -class Server::SyncRequest final : public CompletionQueueTag { +class Server::SyncRequest final : public internal::CompletionQueueTag { public: - SyncRequest(RpcServiceMethod* method, void* tag) + SyncRequest(internal::RpcServiceMethod* method, void* tag) : method_(method), tag_(tag), in_flight_(false), - has_request_payload_(method->method_type() == RpcMethod::NORMAL_RPC || - method->method_type() == - RpcMethod::SERVER_STREAMING), + has_request_payload_( + method->method_type() == internal::RpcMethod::NORMAL_RPC || + method->method_type() == internal::RpcMethod::SERVER_STREAMING), call_details_(nullptr), cq_(nullptr) { grpc_metadata_array_init(&request_metadata_); @@ -212,14 +213,14 @@ class Server::SyncRequest final : public CompletionQueueTag { void Run(std::shared_ptr global_callbacks) { ctx_.BeginCompletionOp(&call_); global_callbacks->PreSynchronousRequest(&ctx_); - method_->handler()->RunHandler( - MethodHandler::HandlerParameter(&call_, &ctx_, request_payload_)); + method_->handler()->RunHandler(internal::MethodHandler::HandlerParameter( + &call_, &ctx_, request_payload_)); global_callbacks->PostSynchronousRequest(&ctx_); request_payload_ = nullptr; cq_.Shutdown(); - CompletionQueueTag* op_tag = ctx_.GetCompletionOpTag(); + internal::CompletionQueueTag* op_tag = ctx_.GetCompletionOpTag(); cq_.TryPluck(op_tag, gpr_inf_future(GPR_CLOCK_REALTIME)); /* Ensure the cq_ is shutdown */ @@ -229,15 +230,15 @@ class Server::SyncRequest final : public CompletionQueueTag { private: CompletionQueue cq_; - Call call_; + internal::Call call_; ServerContext ctx_; const bool has_request_payload_; grpc_byte_buffer* request_payload_; - RpcServiceMethod* const method_; + internal::RpcServiceMethod* const method_; }; private: - RpcServiceMethod* const method_; + internal::RpcServiceMethod* const method_; void* const tag_; bool in_flight_; const bool has_request_payload_; @@ -311,14 +312,15 @@ class Server::SyncRequestThreadManager : public ThreadManager { // object } - void AddSyncMethod(RpcServiceMethod* method, void* tag) { + void AddSyncMethod(internal::RpcServiceMethod* method, void* tag) { sync_requests_.emplace_back(new SyncRequest(method, tag)); } void AddUnknownSyncMethod() { if (!sync_requests_.empty()) { - unknown_method_.reset(new RpcServiceMethod( - "unknown", RpcMethod::BIDI_STREAMING, new UnknownMethodHandler)); + unknown_method_.reset(new internal::RpcServiceMethod( + "unknown", internal::RpcMethod::BIDI_STREAMING, + new internal::UnknownMethodHandler)); sync_requests_.emplace_back( new SyncRequest(unknown_method_.get(), nullptr)); } @@ -355,8 +357,8 @@ class Server::SyncRequestThreadManager : public ThreadManager { CompletionQueue* server_cq_; int cq_timeout_msec_; std::vector> sync_requests_; - std::unique_ptr unknown_method_; - std::unique_ptr health_check_; + std::unique_ptr unknown_method_; + std::unique_ptr health_check_; std::shared_ptr global_callbacks_; }; @@ -439,13 +441,13 @@ std::shared_ptr Server::InProcessChannel( } static grpc_server_register_method_payload_handling PayloadHandlingForMethod( - RpcServiceMethod* method) { + internal::RpcServiceMethod* method) { switch (method->method_type()) { - case RpcMethod::NORMAL_RPC: - case RpcMethod::SERVER_STREAMING: + case internal::RpcMethod::NORMAL_RPC: + case internal::RpcMethod::SERVER_STREAMING: return GRPC_SRM_PAYLOAD_READ_INITIAL_BYTE_BUFFER; - case RpcMethod::CLIENT_STREAMING: - case RpcMethod::BIDI_STREAMING: + case internal::RpcMethod::CLIENT_STREAMING: + case internal::RpcMethod::BIDI_STREAMING: return GRPC_SRM_PAYLOAD_NONE; } GPR_UNREACHABLE_CODE(return GRPC_SRM_PAYLOAD_NONE;); @@ -466,7 +468,7 @@ bool Server::RegisterService(const grpc::string* host, Service* service) { continue; } - RpcServiceMethod* method = it->get(); + internal::RpcServiceMethod* method = it->get(); void* tag = grpc_server_register_method( server_, method->name(), host ? host->c_str() : nullptr, PayloadHandlingForMethod(method), 0); @@ -606,7 +608,8 @@ void Server::Wait() { } } -void Server::PerformOpsOnCall(CallOpSetInterface* ops, Call* call) { +void Server::PerformOpsOnCall(internal::CallOpSetInterface* ops, + internal::Call* call) { static const size_t MAX_OPS = 8; size_t nops = 0; grpc_op cops[MAX_OPS]; @@ -622,8 +625,8 @@ void Server::PerformOpsOnCall(CallOpSetInterface* ops, Call* call) { ServerInterface::BaseAsyncRequest::BaseAsyncRequest( ServerInterface* server, ServerContext* context, - ServerAsyncStreamingInterface* stream, CompletionQueue* call_cq, void* tag, - bool delete_on_finalize) + internal::ServerAsyncStreamingInterface* stream, CompletionQueue* call_cq, + void* tag, bool delete_on_finalize) : server_(server), context_(context), stream_(stream), @@ -645,7 +648,8 @@ bool ServerInterface::BaseAsyncRequest::FinalizeResult(void** tag, } context_->set_call(call_); context_->cq_ = call_cq_; - Call call(call_, server_, call_cq_, server_->max_receive_message_size()); + internal::Call call(call_, server_, call_cq_, + server_->max_receive_message_size()); if (*status && call_) { context_->BeginCompletionOp(&call); } @@ -660,7 +664,8 @@ bool ServerInterface::BaseAsyncRequest::FinalizeResult(void** tag, ServerInterface::RegisteredAsyncRequest::RegisteredAsyncRequest( ServerInterface* server, ServerContext* context, - ServerAsyncStreamingInterface* stream, CompletionQueue* call_cq, void* tag) + internal::ServerAsyncStreamingInterface* stream, CompletionQueue* call_cq, + void* tag) : BaseAsyncRequest(server, context, stream, call_cq, tag, true) {} void ServerInterface::RegisteredAsyncRequest::IssueRequest( @@ -675,7 +680,7 @@ void ServerInterface::RegisteredAsyncRequest::IssueRequest( ServerInterface::GenericAsyncRequest::GenericAsyncRequest( ServerInterface* server, GenericServerContext* context, - ServerAsyncStreamingInterface* stream, CompletionQueue* call_cq, + internal::ServerAsyncStreamingInterface* stream, CompletionQueue* call_cq, ServerCompletionQueue* notification_cq, void* tag, bool delete_on_finalize) : BaseAsyncRequest(server, context, stream, call_cq, tag, delete_on_finalize) { @@ -718,7 +723,7 @@ Server::UnimplementedAsyncResponse::UnimplementedAsyncResponse( UnimplementedAsyncRequest* request) : request_(request) { Status status(StatusCode::UNIMPLEMENTED, ""); - UnknownMethodHandler::FillOps(request_->context(), this); + internal::UnknownMethodHandler::FillOps(request_->context(), this); request_->stream()->call_.PerformOps(this); } diff --git a/src/cpp/server/server_context.cc b/src/cpp/server/server_context.cc index d7876a000b4..f2cb6363f5c 100644 --- a/src/cpp/server/server_context.cc +++ b/src/cpp/server/server_context.cc @@ -37,7 +37,7 @@ namespace grpc { // CompletionOp -class ServerContext::CompletionOp final : public CallOpSetInterface { +class ServerContext::CompletionOp final : public internal::CallOpSetInterface { public: // initial refs: one in the server context, one in the cq CompletionOp() @@ -146,7 +146,7 @@ ServerContext::~ServerContext() { } } -void ServerContext::BeginCompletionOp(Call* call) { +void ServerContext::BeginCompletionOp(internal::Call* call) { GPR_ASSERT(!completion_op_); completion_op_ = new CompletionOp(); if (has_notify_when_done_tag_) { @@ -155,8 +155,8 @@ void ServerContext::BeginCompletionOp(Call* call) { call->PerformOps(completion_op_); } -CompletionQueueTag* ServerContext::GetCompletionOpTag() { - return static_cast(completion_op_); +internal::CompletionQueueTag* ServerContext::GetCompletionOpTag() { + return static_cast(completion_op_); } void ServerContext::AddInitialMetadata(const grpc::string& key, diff --git a/test/cpp/codegen/compiler_test_golden b/test/cpp/codegen/compiler_test_golden index 3d664e88254..026a94112a6 100644 --- a/test/cpp/codegen/compiler_test_golden +++ b/test/cpp/codegen/compiler_test_golden @@ -39,7 +39,6 @@ namespace grpc { class CompletionQueue; class Channel; -class RpcService; class ServerCompletionQueue; class ServerContext; } // namespace grpc @@ -169,10 +168,10 @@ class ServiceA final { ::grpc::ClientReaderWriter< ::grpc::testing::Request, ::grpc::testing::Response>* MethodA4Raw(::grpc::ClientContext* context) override; ::grpc::ClientAsyncReaderWriter< ::grpc::testing::Request, ::grpc::testing::Response>* AsyncMethodA4Raw(::grpc::ClientContext* context, ::grpc::CompletionQueue* cq, void* tag) override; ::grpc::ClientAsyncReaderWriter< ::grpc::testing::Request, ::grpc::testing::Response>* PrepareAsyncMethodA4Raw(::grpc::ClientContext* context, ::grpc::CompletionQueue* cq) override; - const ::grpc::RpcMethod rpcmethod_MethodA1_; - const ::grpc::RpcMethod rpcmethod_MethodA2_; - const ::grpc::RpcMethod rpcmethod_MethodA3_; - const ::grpc::RpcMethod rpcmethod_MethodA4_; + const ::grpc::internal::RpcMethod rpcmethod_MethodA1_; + const ::grpc::internal::RpcMethod rpcmethod_MethodA2_; + const ::grpc::internal::RpcMethod rpcmethod_MethodA3_; + const ::grpc::internal::RpcMethod rpcmethod_MethodA4_; }; static std::unique_ptr NewStub(const std::shared_ptr< ::grpc::ChannelInterface>& channel, const ::grpc::StubOptions& options = ::grpc::StubOptions()); @@ -352,7 +351,7 @@ class ServiceA final { public: WithStreamedUnaryMethod_MethodA1() { ::grpc::Service::MarkMethodStreamed(0, - new ::grpc::StreamedUnaryHandler< ::grpc::testing::Request, ::grpc::testing::Response>(std::bind(&WithStreamedUnaryMethod_MethodA1::StreamedMethodA1, this, std::placeholders::_1, std::placeholders::_2))); + new ::grpc::internal::StreamedUnaryHandler< ::grpc::testing::Request, ::grpc::testing::Response>(std::bind(&WithStreamedUnaryMethod_MethodA1::StreamedMethodA1, this, std::placeholders::_1, std::placeholders::_2))); } ~WithStreamedUnaryMethod_MethodA1() override { BaseClassMustBeDerivedFromService(this); @@ -373,7 +372,7 @@ class ServiceA final { public: WithSplitStreamingMethod_MethodA3() { ::grpc::Service::MarkMethodStreamed(2, - new ::grpc::SplitServerStreamingHandler< ::grpc::testing::Request, ::grpc::testing::Response>(std::bind(&WithSplitStreamingMethod_MethodA3::StreamedMethodA3, this, std::placeholders::_1, std::placeholders::_2))); + new ::grpc::internal::SplitServerStreamingHandler< ::grpc::testing::Request, ::grpc::testing::Response>(std::bind(&WithSplitStreamingMethod_MethodA3::StreamedMethodA3, this, std::placeholders::_1, std::placeholders::_2))); } ~WithSplitStreamingMethod_MethodA3() override { BaseClassMustBeDerivedFromService(this); @@ -427,7 +426,7 @@ class ServiceB final { std::shared_ptr< ::grpc::ChannelInterface> channel_; ::grpc::ClientAsyncResponseReader< ::grpc::testing::Response>* AsyncMethodB1Raw(::grpc::ClientContext* context, const ::grpc::testing::Request& request, ::grpc::CompletionQueue* cq) override; ::grpc::ClientAsyncResponseReader< ::grpc::testing::Response>* PrepareAsyncMethodB1Raw(::grpc::ClientContext* context, const ::grpc::testing::Request& request, ::grpc::CompletionQueue* cq) override; - const ::grpc::RpcMethod rpcmethod_MethodB1_; + const ::grpc::internal::RpcMethod rpcmethod_MethodB1_; }; static std::unique_ptr NewStub(const std::shared_ptr< ::grpc::ChannelInterface>& channel, const ::grpc::StubOptions& options = ::grpc::StubOptions()); @@ -484,7 +483,7 @@ class ServiceB final { public: WithStreamedUnaryMethod_MethodB1() { ::grpc::Service::MarkMethodStreamed(0, - new ::grpc::StreamedUnaryHandler< ::grpc::testing::Request, ::grpc::testing::Response>(std::bind(&WithStreamedUnaryMethod_MethodB1::StreamedMethodB1, this, std::placeholders::_1, std::placeholders::_2))); + new ::grpc::internal::StreamedUnaryHandler< ::grpc::testing::Request, ::grpc::testing::Response>(std::bind(&WithStreamedUnaryMethod_MethodB1::StreamedMethodB1, this, std::placeholders::_1, std::placeholders::_2))); } ~WithStreamedUnaryMethod_MethodB1() override { BaseClassMustBeDerivedFromService(this); diff --git a/test/cpp/microbenchmarks/bm_cq.cc b/test/cpp/microbenchmarks/bm_cq.cc index a0c0414f2f5..020ec0461c4 100644 --- a/test/cpp/microbenchmarks/bm_cq.cc +++ b/test/cpp/microbenchmarks/bm_cq.cc @@ -70,7 +70,7 @@ BENCHMARK(BM_CreateDestroyCore); static void DoneWithCompletionOnStack(grpc_exec_ctx* exec_ctx, void* arg, grpc_cq_completion* completion) {} -class DummyTag final : public CompletionQueueTag { +class DummyTag final : public internal::CompletionQueueTag { public: bool FinalizeResult(void** tag, bool* status) override { return true; } }; From 37f1bd13ab703d7b1c0eb641f2d0515ea91ce8af Mon Sep 17 00:00:00 2001 From: yang-g Date: Thu, 26 Oct 2017 14:42:51 -0700 Subject: [PATCH 22/47] clear the request --- test/cpp/qps/server_async.cc | 34 +++++++++++++++++----------------- 1 file changed, 17 insertions(+), 17 deletions(-) diff --git a/test/cpp/qps/server_async.cc b/test/cpp/qps/server_async.cc index 4576be5bb35..4cf80e9e3d6 100644 --- a/test/cpp/qps/server_async.cc +++ b/test/cpp/qps/server_async.cc @@ -70,7 +70,7 @@ class AsyncQpsServerTest final : public grpc::testing::Server { ServerAsyncReaderWriter *, CompletionQueue *, ServerCompletionQueue *, void *)> request_streaming_both_ways_function, - std::function process_rpc) : Server(config) { @@ -255,7 +255,7 @@ class AsyncQpsServerTest final : public grpc::testing::Server { grpc::ServerAsyncResponseWriter *, void *)> request_method, - std::function + std::function invoke_method) : srv_ctx_(new ServerContextType), next_state_(&ServerRpcContextUnaryImpl::invoker), @@ -301,8 +301,7 @@ class AsyncQpsServerTest final : public grpc::testing::Server { std::function *, void *)> request_method_; - std::function - invoke_method_; + std::function invoke_method_; grpc::ServerAsyncResponseWriter response_writer_; }; @@ -313,7 +312,7 @@ class AsyncQpsServerTest final : public grpc::testing::Server { ServerContextType *, grpc::ServerAsyncReaderWriter *, void *)> request_method, - std::function + std::function invoke_method) : srv_ctx_(new ServerContextType), next_state_(&ServerRpcContextStreamingImpl::request_done), @@ -381,8 +380,7 @@ class AsyncQpsServerTest final : public grpc::testing::Server { ServerContextType *, grpc::ServerAsyncReaderWriter *, void *)> request_method_; - std::function - invoke_method_; + std::function invoke_method_; grpc::ServerAsyncReaderWriter stream_; }; @@ -394,7 +392,7 @@ class AsyncQpsServerTest final : public grpc::testing::Server { grpc::ServerAsyncReader *, void *)> request_method, - std::function + std::function invoke_method) : srv_ctx_(new ServerContextType), next_state_(&ServerRpcContextStreamingFromClientImpl::request_done), @@ -452,8 +450,7 @@ class AsyncQpsServerTest final : public grpc::testing::Server { grpc::ServerAsyncReader *, void *)> request_method_; - std::function - invoke_method_; + std::function invoke_method_; grpc::ServerAsyncReader stream_; }; @@ -464,7 +461,7 @@ class AsyncQpsServerTest final : public grpc::testing::Server { std::function *, void *)> request_method, - std::function + std::function invoke_method) : srv_ctx_(new ServerContextType), next_state_(&ServerRpcContextStreamingFromServerImpl::request_done), @@ -521,8 +518,7 @@ class AsyncQpsServerTest final : public grpc::testing::Server { std::function *, void *)> request_method_; - std::function - invoke_method_; + std::function invoke_method_; grpc::ServerAsyncWriter stream_; }; @@ -551,8 +547,7 @@ static void RegisterGenericService(ServerBuilder *builder, builder->RegisterAsyncGenericService(service); } -static Status ProcessSimpleRPC(const PayloadConfig &, - const SimpleRequest *request, +static Status ProcessSimpleRPC(const PayloadConfig &, SimpleRequest *request, SimpleResponse *response) { if (request->response_size() > 0) { if (!Server::SetPayload(request->response_type(), request->response_size(), @@ -560,12 +555,17 @@ static Status ProcessSimpleRPC(const PayloadConfig &, return Status(grpc::StatusCode::INTERNAL, "Error creating payload."); } } + // We are done using the request. Clear it to reduce working memory. + // This proves to reduce cache misses in large message size cases. + request->Clear(); return Status::OK; } static Status ProcessGenericRPC(const PayloadConfig &payload_config, - const ByteBuffer *request, - ByteBuffer *response) { + ByteBuffer *request, ByteBuffer *response) { + // We are done using the request. Clear it to reduce working memory. + // This proves to reduce cache misses in large message size cases. + request->Clear(); int resp_size = payload_config.bytebuf_params().resp_size(); std::unique_ptr buf(new char[resp_size]); Slice slice(buf.get(), resp_size); From 918ce7a686fee457d43820db980832e94b46d4a9 Mon Sep 17 00:00:00 2001 From: Ken Payson Date: Fri, 27 Oct 2017 02:48:15 -0700 Subject: [PATCH 23/47] Fix QPS Async Client Next loop --- test/cpp/qps/client_async.cc | 28 ++++++++++++++-------------- test/cpp/qps/server_async.cc | 3 +-- 2 files changed, 15 insertions(+), 16 deletions(-) diff --git a/test/cpp/qps/client_async.cc b/test/cpp/qps/client_async.cc index b5c7208664c..a541f94fa55 100644 --- a/test/cpp/qps/client_async.cc +++ b/test/cpp/qps/client_async.cc @@ -245,9 +245,20 @@ class AsyncClient : public ClientImpl { if (!cli_cqs_[cq_[thread_idx]]->Next(&got_tag, &ok)) { return; } - ClientRpcContext* ctx; + ClientRpcContext* ctx = ClientRpcContext::detag(got_tag); std::mutex* shutdown_mu = &shutdown_state_[thread_idx]->mutex; - do { + shutdown_mu->lock(); + while (cli_cqs_[cq_[thread_idx]]->DoThenAsyncNext( + [&, ctx, ok, entry_ptr, shutdown_mu]() { + if (!ctx->RunNextState(ok, entry_ptr)) { + // The RPC and callback are done, so clone the ctx + // and kickstart the new one + ctx->StartNewClone(cli_cqs_[cq_[thread_idx]].get()); + delete ctx; + } + shutdown_mu->unlock(); + }, + &got_tag, &ok, gpr_inf_future(GPR_CLOCK_REALTIME))) { t->UpdateHistogram(entry_ptr); // Got a regular event, so process it ctx = ClientRpcContext::detag(got_tag); @@ -265,18 +276,7 @@ class AsyncClient : public ClientImpl { shutdown_mu->unlock(); return; } - } while (cli_cqs_[cq_[thread_idx]]->DoThenAsyncNext( - [&, ctx, ok, entry_ptr, shutdown_mu]() { - bool next_ok = ok; - if (!ctx->RunNextState(next_ok, entry_ptr)) { - // The RPC and callback are done, so clone the ctx - // and kickstart the new one - ctx->StartNewClone(cli_cqs_[cq_[thread_idx]].get()); - delete ctx; - } - shutdown_mu->unlock(); - }, - &got_tag, &ok, gpr_inf_future(GPR_CLOCK_REALTIME))); + } } std::vector> cli_cqs_; diff --git a/test/cpp/qps/server_async.cc b/test/cpp/qps/server_async.cc index 4cf80e9e3d6..1c1a5636a94 100644 --- a/test/cpp/qps/server_async.cc +++ b/test/cpp/qps/server_async.cc @@ -206,13 +206,12 @@ class AsyncQpsServerTest final : public grpc::testing::Server { return; } ServerRpcContext *ctx; - std::mutex *mu_ptr; + std::mutex *mu_ptr = &shutdown_state_[thread_idx]->mutex; do { ctx = detag(got_tag); // The tag is a pointer to an RPC context to invoke // Proceed while holding a lock to make sure that // this thread isn't supposed to shut down - mu_ptr = &shutdown_state_[thread_idx]->mutex; mu_ptr->lock(); if (shutdown_state_[thread_idx]->shutdown) { mu_ptr->unlock(); From 6e5ce7288da316a6ceee84bd071b6bbddec21495 Mon Sep 17 00:00:00 2001 From: "Mark D. Roth" Date: Fri, 27 Oct 2017 09:37:41 -0700 Subject: [PATCH 24/47] Assume that subchannels start in state IDLE. --- .../grpc/impl/codegen/connectivity_state.h | 2 - .../client_channel/lb_policy/grpclb/grpclb.cc | 2 - .../lb_policy/pick_first/pick_first.cc | 6 ++- .../lb_policy/round_robin/round_robin.cc | 2 +- .../lb_policy/subchannel_list.cc | 41 ++++--------------- .../lb_policy/subchannel_list.h | 2 +- .../ext/filters/client_channel/subchannel.h | 4 +- src/core/lib/transport/connectivity_state.cc | 3 -- test/cpp/end2end/client_lb_end2end_test.cc | 4 +- 9 files changed, 18 insertions(+), 48 deletions(-) diff --git a/include/grpc/impl/codegen/connectivity_state.h b/include/grpc/impl/codegen/connectivity_state.h index 545b4fdbcc7..b70dbef3564 100644 --- a/include/grpc/impl/codegen/connectivity_state.h +++ b/include/grpc/impl/codegen/connectivity_state.h @@ -25,8 +25,6 @@ extern "C" { /** Connectivity state of a channel. */ typedef enum { - /** channel has just been initialized */ - GRPC_CHANNEL_INIT = -1, /** channel is idle */ GRPC_CHANNEL_IDLE, /** channel is connecting */ diff --git a/src/core/ext/filters/client_channel/lb_policy/grpclb/grpclb.cc b/src/core/ext/filters/client_channel/lb_policy/grpclb/grpclb.cc index d6bdc13ba9d..85e76e68b5a 100644 --- a/src/core/ext/filters/client_channel/lb_policy/grpclb/grpclb.cc +++ b/src/core/ext/filters/client_channel/lb_policy/grpclb/grpclb.cc @@ -611,7 +611,6 @@ static void update_lb_connectivity_status_locked( case GRPC_CHANNEL_SHUTDOWN: GPR_ASSERT(rr_state_error != GRPC_ERROR_NONE); break; - case GRPC_CHANNEL_INIT: case GRPC_CHANNEL_IDLE: case GRPC_CHANNEL_CONNECTING: case GRPC_CHANNEL_READY: @@ -1790,7 +1789,6 @@ static void glb_lb_channel_on_connectivity_changed_cb(grpc_exec_ctx *exec_ctx, // embedded RR policy. Note that the current RR policy, if any, will stay in // effect until an update from the new lb_call is received. switch (glb_policy->lb_channel_connectivity) { - case GRPC_CHANNEL_INIT: case GRPC_CHANNEL_CONNECTING: case GRPC_CHANNEL_TRANSIENT_FAILURE: { /* resub. */ diff --git a/src/core/ext/filters/client_channel/lb_policy/pick_first/pick_first.cc b/src/core/ext/filters/client_channel/lb_policy/pick_first/pick_first.cc index 9b5b9217afe..f0c66c68e1f 100644 --- a/src/core/ext/filters/client_channel/lb_policy/pick_first/pick_first.cc +++ b/src/core/ext/filters/client_channel/lb_policy/pick_first/pick_first.cc @@ -312,6 +312,10 @@ static void pf_update_locked(grpc_exec_ctx *exec_ctx, grpc_lb_policy *policy, exec_ctx, p->subchannel_list, "pf_update_includes_selected"); } p->subchannel_list = subchannel_list; + if (p->selected->connected_subchannel != NULL) { + sd->connected_subchannel = GRPC_CONNECTED_SUBCHANNEL_REF( + p->selected->connected_subchannel, "pf_update_includes_selected"); + } p->selected = sd; destroy_unselected_subchannels_locked(exec_ctx, p); // If there was a previously pending update (which may or may @@ -442,8 +446,6 @@ static void pf_connectivity_changed_locked(grpc_exec_ctx *exec_ctx, void *arg, } while (true) { switch (sd->curr_connectivity_state) { - case GRPC_CHANNEL_INIT: - GPR_UNREACHABLE_CODE(return ); case GRPC_CHANNEL_READY: { // Case 2. Promote p->latest_pending_subchannel_list to // p->subchannel_list. diff --git a/src/core/ext/filters/client_channel/lb_policy/round_robin/round_robin.cc b/src/core/ext/filters/client_channel/lb_policy/round_robin/round_robin.cc index 488fd3c0ac9..8f29c80130c 100644 --- a/src/core/ext/filters/client_channel/lb_policy/round_robin/round_robin.cc +++ b/src/core/ext/filters/client_channel/lb_policy/round_robin/round_robin.cc @@ -334,6 +334,7 @@ static void update_state_counters_locked(grpc_lb_subchannel_data *sd) { GPR_ASSERT(subchannel_list->num_idle > 0); --subchannel_list->num_idle; } + sd->prev_connectivity_state = sd->curr_connectivity_state; if (sd->curr_connectivity_state == GRPC_CHANNEL_READY) { ++subchannel_list->num_ready; } else if (sd->curr_connectivity_state == GRPC_CHANNEL_TRANSIENT_FAILURE) { @@ -451,7 +452,6 @@ static void rr_connectivity_changed_locked(grpc_exec_ctx *exec_ctx, void *arg, sd->curr_connectivity_state = sd->pending_connectivity_state_unsafe; // Update state counters and determine new overall state. update_state_counters_locked(sd); - sd->prev_connectivity_state = sd->curr_connectivity_state; const grpc_connectivity_state new_policy_connectivity_state = update_lb_connectivity_status_locked(exec_ctx, sd, GRPC_ERROR_REF(error)); // If the sd's new state is SHUTDOWN, unref the subchannel, and if the new diff --git a/src/core/ext/filters/client_channel/lb_policy/subchannel_list.cc b/src/core/ext/filters/client_channel/lb_policy/subchannel_list.cc index 831d8ac2556..08ea4f480b5 100644 --- a/src/core/ext/filters/client_channel/lb_policy/subchannel_list.cc +++ b/src/core/ext/filters/client_channel/lb_policy/subchannel_list.cc @@ -137,34 +137,13 @@ grpc_lb_subchannel_list *grpc_lb_subchannel_list_create( } continue; } - grpc_error *error; - // Get the connectivity state of the subchannel. Already existing ones may - // be in a state other than INIT. - const grpc_connectivity_state subchannel_connectivity_state = - grpc_subchannel_check_connectivity(subchannel, &error); - if (error != GRPC_ERROR_NONE) { - // The subchannel is in error (e.g. shutting down). Ignore it. - if (GRPC_TRACER_ON(*tracer)) { - char *address_uri = - grpc_sockaddr_to_uri(&addresses->addresses[i].address); - gpr_log(GPR_DEBUG, - "[%s %p] subchannel for address uri %s shutting down, ignoring", - tracer->name, subchannel_list->policy, address_uri); - gpr_free(address_uri); - } - GRPC_SUBCHANNEL_UNREF(exec_ctx, subchannel, "new_sc_connectivity_error"); - GRPC_ERROR_UNREF(error); - continue; - } if (GRPC_TRACER_ON(*tracer)) { char *address_uri = grpc_sockaddr_to_uri(&addresses->addresses[i].address); gpr_log(GPR_DEBUG, "[%s %p] subchannel list %p index %" PRIuPTR - ": Created subchannel %p for address uri %s; " - "initial connectivity state: %s", + ": Created subchannel %p for address uri %s", tracer->name, p, subchannel_list, subchannel_index, subchannel, - address_uri, - grpc_connectivity_state_name(subchannel_connectivity_state)); + address_uri); gpr_free(address_uri); } grpc_lb_subchannel_data *sd = @@ -174,16 +153,11 @@ grpc_lb_subchannel_list *grpc_lb_subchannel_list_create( GRPC_CLOSURE_INIT(&sd->connectivity_changed_closure, connectivity_changed_cb, sd, grpc_combiner_scheduler(args->combiner)); - // Use some sentinel value outside of the range of - // grpc_connectivity_state to signal an undefined previous state. - sd->prev_connectivity_state = GRPC_CHANNEL_INIT; - sd->curr_connectivity_state = subchannel_connectivity_state; - sd->pending_connectivity_state_unsafe = subchannel_connectivity_state; - if (sd->curr_connectivity_state == GRPC_CHANNEL_READY) { - sd->connected_subchannel = GRPC_CONNECTED_SUBCHANNEL_REF( - grpc_subchannel_get_connected_subchannel(sd->subchannel), - "ready_at_sl_creation"); - } + // We assume that the current state is IDLE. If not, we'll get a + // callback telling us that. + sd->prev_connectivity_state = GRPC_CHANNEL_IDLE; + sd->curr_connectivity_state = GRPC_CHANNEL_IDLE; + sd->pending_connectivity_state_unsafe = GRPC_CHANNEL_IDLE; sd->user_data_vtable = addresses->user_data_vtable; if (sd->user_data_vtable != NULL) { sd->user_data = @@ -191,6 +165,7 @@ grpc_lb_subchannel_list *grpc_lb_subchannel_list_create( } } subchannel_list->num_subchannels = subchannel_index; + subchannel_list->num_idle = subchannel_index; return subchannel_list; } diff --git a/src/core/ext/filters/client_channel/lb_policy/subchannel_list.h b/src/core/ext/filters/client_channel/lb_policy/subchannel_list.h index 7ad22302ce2..9d5984260f8 100644 --- a/src/core/ext/filters/client_channel/lb_policy/subchannel_list.h +++ b/src/core/ext/filters/client_channel/lb_policy/subchannel_list.h @@ -97,7 +97,7 @@ struct grpc_lb_subchannel_list { /** Index into subchannels of the one we're currently checking. * Used when connecting to subchannels serially instead of in parallel. */ // TODO(roth): When we have time, we can probably make this go away - // and the index dynamically by subtracting + // and compute the index dynamically by subtracting // subchannel_list->subchannels from the subchannel_data pointer. size_t checking_subchannel; diff --git a/src/core/ext/filters/client_channel/subchannel.h b/src/core/ext/filters/client_channel/subchannel.h index 46b29f1fe02..1cd73f3ff45 100644 --- a/src/core/ext/filters/client_channel/subchannel.h +++ b/src/core/ext/filters/client_channel/subchannel.h @@ -127,8 +127,8 @@ void grpc_connected_subchannel_process_transport_op( grpc_connectivity_state grpc_subchannel_check_connectivity( grpc_subchannel *channel, grpc_error **error); -/** call notify when the connectivity state of a channel changes from *state. - Updates *state with the new state of the channel */ +/** Calls notify when the connectivity state of a channel becomes different + from *state. Updates *state with the new state of the channel. */ void grpc_subchannel_notify_on_state_change( grpc_exec_ctx *exec_ctx, grpc_subchannel *channel, grpc_pollset_set *interested_parties, grpc_connectivity_state *state, diff --git a/src/core/lib/transport/connectivity_state.cc b/src/core/lib/transport/connectivity_state.cc index f328a6cdbb7..652c26cf0a5 100644 --- a/src/core/lib/transport/connectivity_state.cc +++ b/src/core/lib/transport/connectivity_state.cc @@ -29,8 +29,6 @@ grpc_tracer_flag grpc_connectivity_state_trace = const char *grpc_connectivity_state_name(grpc_connectivity_state state) { switch (state) { - case GRPC_CHANNEL_INIT: - return "INIT"; case GRPC_CHANNEL_IDLE: return "IDLE"; case GRPC_CHANNEL_CONNECTING: @@ -174,7 +172,6 @@ void grpc_connectivity_state_set(grpc_exec_ctx *exec_ctx, grpc_connectivity_state_name(state), reason, error, error_string); } switch (state) { - case GRPC_CHANNEL_INIT: case GRPC_CHANNEL_CONNECTING: case GRPC_CHANNEL_IDLE: case GRPC_CHANNEL_READY: diff --git a/test/cpp/end2end/client_lb_end2end_test.cc b/test/cpp/end2end/client_lb_end2end_test.cc index c236f76e89c..805e5b1045a 100644 --- a/test/cpp/end2end/client_lb_end2end_test.cc +++ b/test/cpp/end2end/client_lb_end2end_test.cc @@ -305,7 +305,7 @@ TEST_F(ClientLbEnd2endTest, PickFirstUpdates) { ports.clear(); SetNextResolution(ports); gpr_log(GPR_INFO, "****** SET none *******"); - grpc_connectivity_state channel_state = GRPC_CHANNEL_INIT; + grpc_connectivity_state channel_state; do { channel_state = channel_->GetState(true /* try to connect */); } while (channel_state == GRPC_CHANNEL_READY); @@ -481,7 +481,7 @@ TEST_F(ClientLbEnd2endTest, RoundRobinUpdates) { // An empty update will result in the channel going into TRANSIENT_FAILURE. ports.clear(); SetNextResolution(ports); - grpc_connectivity_state channel_state = GRPC_CHANNEL_INIT; + grpc_connectivity_state channel_state; do { channel_state = channel_->GetState(true /* try to connect */); } while (channel_state == GRPC_CHANNEL_READY); From 0e06c41c9cefe80ec2bae8a92bc0a0e2500af800 Mon Sep 17 00:00:00 2001 From: "Mark D. Roth" Date: Fri, 27 Oct 2017 10:17:54 -0700 Subject: [PATCH 25/47] Fix build failure. --- test/core/client_channel/lb_policies_test.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/test/core/client_channel/lb_policies_test.c b/test/core/client_channel/lb_policies_test.c index ba37cd673f6..0e47d8f3249 100644 --- a/test/core/client_channel/lb_policies_test.c +++ b/test/core/client_channel/lb_policies_test.c @@ -53,8 +53,8 @@ typedef struct request_sequences { size_t n; /* number of iterations */ int *connections; /* indexed by the interation number, value is the index of the server it connected to or -1 if none */ - int *connectivity_states; /* indexed by the interation number, value is the - client connectivity state */ + /* indexed by the interation number, value is the client connectivity state */ + grpc_connectivity_state *connectivity_states; } request_sequences; typedef void (*verifier_fn)(const servers_fixture *, grpc_channel *, From 7a648854e9e53f5228ad1218b559e358f72a9a38 Mon Sep 17 00:00:00 2001 From: Vijay Pai Date: Fri, 27 Oct 2017 10:22:51 -0700 Subject: [PATCH 26/47] Adopt the static factory pattern (#10) * Switch sync streams from "struct internal" to static factory in namespace internal * Reduce diff size * fix friends * Use static factory pattern for async unary calls * Use static factories for async streams * clang-format --- include/grpc++/impl/codegen/async_stream.h | 147 ++++++++++-------- .../grpc++/impl/codegen/async_unary_call.h | 43 ++--- .../grpc++/impl/codegen/channel_interface.h | 24 +-- include/grpc++/impl/codegen/sync_stream.h | 70 +++++---- src/compiler/cpp_generator.cc | 24 +-- src/cpp/client/generic_stub.cc | 4 +- 6 files changed, 174 insertions(+), 138 deletions(-) diff --git a/include/grpc++/impl/codegen/async_stream.h b/include/grpc++/impl/codegen/async_stream.h index 2012b3170b3..4476033463b 100644 --- a/include/grpc++/impl/codegen/async_stream.h +++ b/include/grpc++/impl/codegen/async_stream.h @@ -159,33 +159,37 @@ class ClientAsyncReaderInterface : public internal::ClientAsyncStreamingInterface, public internal::AsyncReaderInterface {}; +namespace internal { +template +class ClientAsyncReaderFactory { + public: + /// Create a stream object. + /// Write the first request out if \a start is set. + /// \a tag will be notified on \a cq when the call has been started and + /// \a request has been written out. If \a start is not set, \a tag must be + /// nullptr and the actual call must be initiated by StartCall + /// Note that \a context will be used to fill in custom initial metadata + /// used to send to the server when starting the call. + template + static ClientAsyncReader* Create(ChannelInterface* channel, + CompletionQueue* cq, + const ::grpc::internal::RpcMethod& method, + ClientContext* context, const W& request, + bool start, void* tag) { + ::grpc::internal::Call call = channel->CreateCall(method, context, cq); + return new (g_core_codegen_interface->grpc_call_arena_alloc( + call.call(), sizeof(ClientAsyncReader))) + ClientAsyncReader(call, context, request, start, tag); + } +}; +} // namespace internal + /// Async client-side API for doing server-streaming RPCs, /// where the incoming message stream coming from the server has /// messages of type \a R. template class ClientAsyncReader final : public ClientAsyncReaderInterface { public: - struct internal { - /// Create a stream object. - /// Write the first request out if \a start is set. - /// \a tag will be notified on \a cq when the call has been started and - /// \a request has been written out. If \a start is not set, \a tag must be - /// nullptr and the actual call must be initiated by StartCall - /// Note that \a context will be used to fill in custom initial metadata - /// used to send to the server when starting the call. - template - static ClientAsyncReader* Create(ChannelInterface* channel, - CompletionQueue* cq, - const ::grpc::internal::RpcMethod& method, - ClientContext* context, const W& request, - bool start, void* tag) { - ::grpc::internal::Call call = channel->CreateCall(method, context, cq); - return new (g_core_codegen_interface->grpc_call_arena_alloc( - call.call(), sizeof(ClientAsyncReader))) - ClientAsyncReader(call, context, request, start, tag); - } - }; - // always allocated against a call arena, no memory free required static void operator delete(void* ptr, std::size_t size) { assert(size == sizeof(ClientAsyncReader)); @@ -240,6 +244,7 @@ class ClientAsyncReader final : public ClientAsyncReaderInterface { } private: + friend class internal::ClientAsyncReaderFactory; template ClientAsyncReader(::grpc::internal::Call call, ClientContext* context, const W& request, bool start, void* tag) @@ -291,37 +296,41 @@ class ClientAsyncWriterInterface virtual void WritesDone(void* tag) = 0; }; +namespace internal { +template +class ClientAsyncWriterFactory { + public: + /// Create a stream object. + /// Start the RPC if \a start is set + /// \a tag will be notified on \a cq when the call has been started (i.e. + /// intitial metadata sent) and \a request has been written out. + /// If \a start is not set, \a tag must be nullptr and the actual call + /// must be initiated by StartCall + /// Note that \a context will be used to fill in custom initial metadata + /// used to send to the server when starting the call. + /// \a response will be filled in with the single expected response + /// message from the server upon a successful call to the \a Finish + /// method of this instance. + template + static ClientAsyncWriter* Create(ChannelInterface* channel, + CompletionQueue* cq, + const ::grpc::internal::RpcMethod& method, + ClientContext* context, R* response, + bool start, void* tag) { + ::grpc::internal::Call call = channel->CreateCall(method, context, cq); + return new (g_core_codegen_interface->grpc_call_arena_alloc( + call.call(), sizeof(ClientAsyncWriter))) + ClientAsyncWriter(call, context, response, start, tag); + } +}; +} // namespace internal + /// Async API on the client side for doing client-streaming RPCs, /// where the outgoing message stream going to the server contains /// messages of type \a W. template class ClientAsyncWriter final : public ClientAsyncWriterInterface { public: - struct internal { - /// Create a stream object. - /// Start the RPC if \a start is set - /// \a tag will be notified on \a cq when the call has been started (i.e. - /// intitial metadata sent) and \a request has been written out. - /// If \a start is not set, \a tag must be nullptr and the actual call - /// must be initiated by StartCall - /// Note that \a context will be used to fill in custom initial metadata - /// used to send to the server when starting the call. - /// \a response will be filled in with the single expected response - /// message from the server upon a successful call to the \a Finish - /// method of this instance. - template - static ClientAsyncWriter* Create(ChannelInterface* channel, - CompletionQueue* cq, - const ::grpc::internal::RpcMethod& method, - ClientContext* context, R* response, - bool start, void* tag) { - ::grpc::internal::Call call = channel->CreateCall(method, context, cq); - return new (g_core_codegen_interface->grpc_call_arena_alloc( - call.call(), sizeof(ClientAsyncWriter))) - ClientAsyncWriter(call, context, response, start, tag); - } - }; - // always allocated against a call arena, no memory free required static void operator delete(void* ptr, std::size_t size) { assert(size == sizeof(ClientAsyncWriter)); @@ -394,6 +403,7 @@ class ClientAsyncWriter final : public ClientAsyncWriterInterface { } private: + friend class internal::ClientAsyncWriterFactory; template ClientAsyncWriter(::grpc::internal::Call call, ClientContext* context, R* response, bool start, void* tag) @@ -449,6 +459,30 @@ class ClientAsyncReaderWriterInterface virtual void WritesDone(void* tag) = 0; }; +namespace internal { +template +class ClientAsyncReaderWriterFactory { + public: + /// Create a stream object. + /// Start the RPC request if \a start is set. + /// \a tag will be notified on \a cq when the call has been started (i.e. + /// intitial metadata sent). If \a start is not set, \a tag must be + /// nullptr and the actual call must be initiated by StartCall + /// Note that \a context will be used to fill in custom initial metadata + /// used to send to the server when starting the call. + static ClientAsyncReaderWriter* Create( + ChannelInterface* channel, CompletionQueue* cq, + const ::grpc::internal::RpcMethod& method, ClientContext* context, + bool start, void* tag) { + ::grpc::internal::Call call = channel->CreateCall(method, context, cq); + + return new (g_core_codegen_interface->grpc_call_arena_alloc( + call.call(), sizeof(ClientAsyncReaderWriter))) + ClientAsyncReaderWriter(call, context, start, tag); + } +}; +} // namespace internal + /// Async client-side interface for bi-directional streaming, /// where the outgoing message stream going to the server /// has messages of type \a W, and the incoming message stream coming @@ -457,26 +491,6 @@ template class ClientAsyncReaderWriter final : public ClientAsyncReaderWriterInterface { public: - struct internal { - /// Create a stream object. - /// Start the RPC request if \a start is set. - /// \a tag will be notified on \a cq when the call has been started (i.e. - /// intitial metadata sent). If \a start is not set, \a tag must be - /// nullptr and the actual call must be initiated by StartCall - /// Note that \a context will be used to fill in custom initial metadata - /// used to send to the server when starting the call. - static ClientAsyncReaderWriter* Create( - ChannelInterface* channel, CompletionQueue* cq, - const ::grpc::internal::RpcMethod& method, ClientContext* context, - bool start, void* tag) { - ::grpc::internal::Call call = channel->CreateCall(method, context, cq); - - return new (g_core_codegen_interface->grpc_call_arena_alloc( - call.call(), sizeof(ClientAsyncReaderWriter))) - ClientAsyncReaderWriter(call, context, start, tag); - } - }; - // always allocated against a call arena, no memory free required static void operator delete(void* ptr, std::size_t size) { assert(size == sizeof(ClientAsyncReaderWriter)); @@ -556,6 +570,7 @@ class ClientAsyncReaderWriter final } private: + friend class internal::ClientAsyncReaderWriterFactory; ClientAsyncReaderWriter(::grpc::internal::Call call, ClientContext* context, bool start, void* tag) : context_(context), call_(call), started_(start) { diff --git a/include/grpc++/impl/codegen/async_unary_call.h b/include/grpc++/impl/codegen/async_unary_call.h index 8a3dfbc4db0..6d51c78d5cc 100644 --- a/include/grpc++/impl/codegen/async_unary_call.h +++ b/include/grpc++/impl/codegen/async_unary_call.h @@ -69,31 +69,35 @@ class ClientAsyncResponseReaderInterface { virtual void Finish(R* msg, Status* status, void* tag) = 0; }; +namespace internal { +template +class ClientAsyncResponseReaderFactory { + public: + /// Start a call and write the request out if \a start is set. + /// \a tag will be notified on \a cq when the call has been started (i.e. + /// intitial metadata sent) and \a request has been written out. + /// If \a start is not set, the actual call must be initiated by StartCall + /// Note that \a context will be used to fill in custom initial metadata + /// used to send to the server when starting the call. + template + static ClientAsyncResponseReader* Create( + ChannelInterface* channel, CompletionQueue* cq, + const ::grpc::internal::RpcMethod& method, ClientContext* context, + const W& request, bool start) { + ::grpc::internal::Call call = channel->CreateCall(method, context, cq); + return new (g_core_codegen_interface->grpc_call_arena_alloc( + call.call(), sizeof(ClientAsyncResponseReader))) + ClientAsyncResponseReader(call, context, request, start); + } +}; +} // namespace internal + /// Async API for client-side unary RPCs, where the message response /// received from the server is of type \a R. template class ClientAsyncResponseReader final : public ClientAsyncResponseReaderInterface { public: - struct internal { - /// Start a call and write the request out if \a start is set. - /// \a tag will be notified on \a cq when the call has been started (i.e. - /// intitial metadata sent) and \a request has been written out. - /// If \a start is not set, the actual call must be initiated by StartCall - /// Note that \a context will be used to fill in custom initial metadata - /// used to send to the server when starting the call. - template - static ClientAsyncResponseReader* Create( - ChannelInterface* channel, CompletionQueue* cq, - const ::grpc::internal::RpcMethod& method, ClientContext* context, - const W& request, bool start) { - ::grpc::internal::Call call = channel->CreateCall(method, context, cq); - return new (g_core_codegen_interface->grpc_call_arena_alloc( - call.call(), sizeof(ClientAsyncResponseReader))) - ClientAsyncResponseReader(call, context, request, start); - } - }; - // always allocated against a call arena, no memory free required static void operator delete(void* ptr, std::size_t size) { assert(size == sizeof(ClientAsyncResponseReader)); @@ -138,6 +142,7 @@ class ClientAsyncResponseReader final } private: + friend class internal::ClientAsyncResponseReaderFactory; ClientContext* const context_; ::grpc::internal::Call call_; bool started_; diff --git a/include/grpc++/impl/codegen/channel_interface.h b/include/grpc++/impl/codegen/channel_interface.h index 41c213f64a9..769f8539747 100644 --- a/include/grpc++/impl/codegen/channel_interface.h +++ b/include/grpc++/impl/codegen/channel_interface.h @@ -34,14 +34,6 @@ template class ClientWriter; template class ClientReaderWriter; -template -class ClientAsyncReader; -template -class ClientAsyncWriter; -template -class ClientAsyncReaderWriter; -template -class ClientAsyncResponseReader; namespace internal { class Call; @@ -49,6 +41,14 @@ class CallOpSetInterface; class RpcMethod; template class BlockingUnaryCallImpl; +template +class ClientAsyncReaderFactory; +template +class ClientAsyncWriterFactory; +template +class ClientAsyncReaderWriterFactory; +template +class ClientAsyncResponseReaderFactory; } // namespace internal /// Codegen interface for \a grpc::Channel. @@ -94,13 +94,13 @@ class ChannelInterface { template friend class ::grpc::ClientReaderWriter; template - friend class ::grpc::ClientAsyncReader; + friend class ::grpc::internal::ClientAsyncReaderFactory; template - friend class ::grpc::ClientAsyncWriter; + friend class ::grpc::internal::ClientAsyncWriterFactory; template - friend class ::grpc::ClientAsyncReaderWriter; + friend class ::grpc::internal::ClientAsyncReaderWriterFactory; template - friend class ::grpc::ClientAsyncResponseReader; + friend class ::grpc::internal::ClientAsyncResponseReaderFactory; template friend class ::grpc::internal::BlockingUnaryCallImpl; friend class ::grpc::internal::RpcMethod; diff --git a/include/grpc++/impl/codegen/sync_stream.h b/include/grpc++/impl/codegen/sync_stream.h index 49ace0beeb6..a6dd26fb008 100644 --- a/include/grpc++/impl/codegen/sync_stream.h +++ b/include/grpc++/impl/codegen/sync_stream.h @@ -156,21 +156,25 @@ class ClientReaderInterface : public internal::ClientStreamingInterface, virtual void WaitForInitialMetadata() = 0; }; +namespace internal { +template +class ClientReaderFactory { + public: + template + static ClientReader* Create(ChannelInterface* channel, + const ::grpc::internal::RpcMethod& method, + ClientContext* context, const W& request) { + return new ClientReader(channel, method, context, request); + } +}; +} // namespace internal + /// Synchronous (blocking) client-side API for doing server-streaming RPCs, /// where the stream of messages coming from the server has messages /// of type \a R. template class ClientReader final : public ClientReaderInterface { public: - struct internal { - template - static ClientReader* Create(ChannelInterface* channel, - const ::grpc::internal::RpcMethod& method, - ClientContext* context, const W& request) { - return new ClientReader(channel, method, context, request); - } - }; - /// See the \a ClientStreamingInterface.WaitForInitialMetadata method for /// semantics. /// @@ -225,6 +229,7 @@ class ClientReader final : public ClientReaderInterface { } private: + friend class internal::ClientReaderFactory; ClientContext* context_; CompletionQueue cq_; ::grpc::internal::Call call_; @@ -269,21 +274,25 @@ class ClientWriterInterface : public internal::ClientStreamingInterface, virtual bool WritesDone() = 0; }; +namespace internal { +template +class ClientWriterFactory { + public: + template + static ClientWriter* Create(::grpc::ChannelInterface* channel, + const ::grpc::internal::RpcMethod& method, + ClientContext* context, R* response) { + return new ClientWriter(channel, method, context, response); + } +}; +} // namespace internal + /// Synchronous (blocking) client-side API for doing client-streaming RPCs, /// where the outgoing message stream coming from the client has messages of /// type \a W. template class ClientWriter : public ClientWriterInterface { public: - struct internal { - template - static ClientWriter* Create(::grpc::ChannelInterface* channel, - const ::grpc::internal::RpcMethod& method, - ClientContext* context, R* response) { - return new ClientWriter(channel, method, context, response); - } - }; - /// See the \a ClientStreamingInterface.WaitForInitialMetadata method for /// semantics. /// @@ -355,12 +364,13 @@ class ClientWriter : public ClientWriterInterface { } private: + friend class internal::ClientWriterFactory; + /// Block to create a stream (i.e. send request headers and other initial /// metadata to the server). Note that \a context will be used to fill /// in custom initial metadata. \a response will be filled in with the /// single expected response message from the server upon a successful /// call to the \a Finish method of this instance. - template ClientWriter(ChannelInterface* channel, const ::grpc::internal::RpcMethod& method, @@ -415,6 +425,18 @@ class ClientReaderWriterInterface : public internal::ClientStreamingInterface, virtual bool WritesDone() = 0; }; +namespace internal { +template +class ClientReaderWriterFactory { + public: + static ClientReaderWriter* Create( + ::grpc::ChannelInterface* channel, + const ::grpc::internal::RpcMethod& method, ClientContext* context) { + return new ClientReaderWriter(channel, method, context); + } +}; +} // namespace internal + /// Synchronous (blocking) client-side API for bi-directional streaming RPCs, /// where the outgoing message stream coming from the client has messages of /// type \a W, and the incoming messages stream coming from the server has @@ -422,14 +444,6 @@ class ClientReaderWriterInterface : public internal::ClientStreamingInterface, template class ClientReaderWriter final : public ClientReaderWriterInterface { public: - struct internal { - static ClientReaderWriter* Create(::grpc::ChannelInterface* channel, - const ::grpc::internal::RpcMethod& method, - ClientContext* context) { - return new ClientReaderWriter(channel, method, context); - } - }; - /// Block waiting to read initial metadata from the server. /// This call is optional, but if it is used, it cannot be used concurrently /// with or after the \a Finish method. @@ -523,6 +537,8 @@ class ClientReaderWriter final : public ClientReaderWriterInterface { } private: + friend class internal::ClientReaderWriterFactory; + ClientContext* context_; CompletionQueue cq_; ::grpc::internal::Call call_; diff --git a/src/compiler/cpp_generator.cc b/src/compiler/cpp_generator.cc index 9efd6208b0e..253280bd244 100644 --- a/src/compiler/cpp_generator.cc +++ b/src/compiler/cpp_generator.cc @@ -1203,8 +1203,8 @@ void PrintSourceClientMethod(grpc_generator::Printer *printer, printer->Print( *vars, " return " - "::grpc::ClientAsyncResponseReader< $Response$>::internal::Create(" - "channel_.get(), cq, " + "::grpc::internal::ClientAsyncResponseReaderFactory< $Response$>" + "::Create(channel_.get(), cq, " "rpcmethod_$Method$_, " "context, request, $AsyncStart$);\n" "}\n\n"); @@ -1216,7 +1216,7 @@ void PrintSourceClientMethod(grpc_generator::Printer *printer, "::grpc::ClientContext* context, $Response$* response) {\n"); printer->Print( *vars, - " return ::grpc::ClientWriter< $Request$>::internal::Create(" + " return ::grpc::internal::ClientWriterFactory< $Request$>::Create(" "channel_.get(), " "rpcmethod_$Method$_, " "context, response);\n" @@ -1233,8 +1233,8 @@ void PrintSourceClientMethod(grpc_generator::Printer *printer, "::grpc::CompletionQueue* cq$AsyncMethodParams$) {\n"); printer->Print( *vars, - " return ::grpc::ClientAsyncWriter< $Request$>::internal::Create(" - "channel_.get(), cq, " + " return ::grpc::internal::ClientAsyncWriterFactory< $Request$>" + "::Create(channel_.get(), cq, " "rpcmethod_$Method$_, " "context, response, $AsyncStart$$AsyncCreateArgs$);\n" "}\n\n"); @@ -1247,7 +1247,7 @@ void PrintSourceClientMethod(grpc_generator::Printer *printer, "::grpc::ClientContext* context, const $Request$& request) {\n"); printer->Print( *vars, - " return ::grpc::ClientReader< $Response$>::internal::Create(" + " return ::grpc::internal::ClientReaderFactory< $Response$>::Create(" "channel_.get(), " "rpcmethod_$Method$_, " "context, request);\n" @@ -1265,8 +1265,8 @@ void PrintSourceClientMethod(grpc_generator::Printer *printer, "::grpc::CompletionQueue* cq$AsyncMethodParams$) {\n"); printer->Print( *vars, - " return ::grpc::ClientAsyncReader< $Response$>::internal::Create(" - "channel_.get(), cq, " + " return ::grpc::internal::ClientAsyncReaderFactory< $Response$>" + "::Create(channel_.get(), cq, " "rpcmethod_$Method$_, " "context, request, $AsyncStart$$AsyncCreateArgs$);\n" "}\n\n"); @@ -1277,8 +1277,8 @@ void PrintSourceClientMethod(grpc_generator::Printer *printer, "::grpc::ClientReaderWriter< $Request$, $Response$>* " "$ns$$Service$::Stub::$Method$Raw(::grpc::ClientContext* context) {\n"); printer->Print(*vars, - " return ::grpc::ClientReaderWriter< " - "$Request$, $Response$>::internal::Create(" + " return ::grpc::internal::ClientReaderWriterFactory< " + "$Request$, $Response$>::Create(" "channel_.get(), " "rpcmethod_$Method$_, " "context);\n" @@ -1295,8 +1295,8 @@ void PrintSourceClientMethod(grpc_generator::Printer *printer, "::grpc::CompletionQueue* cq$AsyncMethodParams$) {\n"); printer->Print(*vars, " return " - "::grpc::ClientAsyncReaderWriter< $Request$, " - "$Response$>::internal::Create(" + "::grpc::internal::ClientAsyncReaderWriterFactory< " + "$Request$, $Response$>::Create(" "channel_.get(), cq, " "rpcmethod_$Method$_, " "context, $AsyncStart$$AsyncCreateArgs$);\n" diff --git a/src/cpp/client/generic_stub.cc b/src/cpp/client/generic_stub.cc index 452a8a7501c..fc18ce90935 100644 --- a/src/cpp/client/generic_stub.cc +++ b/src/cpp/client/generic_stub.cc @@ -27,7 +27,7 @@ std::unique_ptr CallInternal( ChannelInterface* channel, ClientContext* context, const grpc::string& method, CompletionQueue* cq, bool start, void* tag) { return std::unique_ptr( - GenericClientAsyncReaderWriter::internal::Create( + internal::ClientAsyncReaderWriterFactory::Create( channel, cq, internal::RpcMethod(method.c_str(), internal::RpcMethod::BIDI_STREAMING), context, start, tag)); @@ -53,7 +53,7 @@ std::unique_ptr GenericStub::PrepareUnaryCall( ClientContext* context, const grpc::string& method, const ByteBuffer& request, CompletionQueue* cq) { return std::unique_ptr( - GenericClientAsyncResponseReader::internal::Create( + internal::ClientAsyncResponseReaderFactory::Create( channel_.get(), cq, internal::RpcMethod(method.c_str(), internal::RpcMethod::NORMAL_RPC), context, request, false)); From fc062439b624119ca6b4c3e6791d67e7891ea3eb Mon Sep 17 00:00:00 2001 From: ncteisen Date: Fri, 27 Oct 2017 10:46:08 -0700 Subject: [PATCH 27/47] Address github comment, sleep for minimal time --- test/core/transport/status_conversion_test.c | 7 +++++-- 1 file changed, 5 insertions(+), 2 deletions(-) diff --git a/test/core/transport/status_conversion_test.c b/test/core/transport/status_conversion_test.c index 1a437046e8e..e3f7602f64c 100644 --- a/test/core/transport/status_conversion_test.c +++ b/test/core/transport/status_conversion_test.c @@ -18,8 +18,8 @@ #include -#include "src/core/lib/transport/status_conversion.h" #include +#include "src/core/lib/transport/status_conversion.h" #include "test/core/util/test_config.h" #define GRPC_STATUS_TO_HTTP2_ERROR(a, b) \ @@ -132,7 +132,10 @@ int main(int argc, char **argv) { GRPC_STATUS_INTERNAL); HTTP2_ERROR_TO_GRPC_STATUS(GRPC_HTTP2_REFUSED_STREAM, after_deadline, GRPC_STATUS_UNAVAILABLE); - sleep(1); + // We only have millisecond granularity in our timing code. This sleeps for 2 + // millis to ensure that the status conversion code will pick up the fact + // that the deadline has expired. + usleep(2000); HTTP2_ERROR_TO_GRPC_STATUS(GRPC_HTTP2_CANCEL, after_deadline, GRPC_STATUS_DEADLINE_EXCEEDED); HTTP2_ERROR_TO_GRPC_STATUS(GRPC_HTTP2_COMPRESSION_ERROR, after_deadline, From 7721456d907f81747d1c35d7a297ab3c841bc467 Mon Sep 17 00:00:00 2001 From: ncteisen Date: Fri, 27 Oct 2017 12:39:59 -0700 Subject: [PATCH 28/47] Fix portabiloty --- test/core/transport/status_conversion_test.c | 9 ++++----- 1 file changed, 4 insertions(+), 5 deletions(-) diff --git a/test/core/transport/status_conversion_test.c b/test/core/transport/status_conversion_test.c index e3f7602f64c..02dad86693a 100644 --- a/test/core/transport/status_conversion_test.c +++ b/test/core/transport/status_conversion_test.c @@ -16,10 +16,8 @@ * */ -#include - -#include #include "src/core/lib/transport/status_conversion.h" +#include #include "test/core/util/test_config.h" #define GRPC_STATUS_TO_HTTP2_ERROR(a, b) \ @@ -132,10 +130,11 @@ int main(int argc, char **argv) { GRPC_STATUS_INTERNAL); HTTP2_ERROR_TO_GRPC_STATUS(GRPC_HTTP2_REFUSED_STREAM, after_deadline, GRPC_STATUS_UNAVAILABLE); - // We only have millisecond granularity in our timing code. This sleeps for 2 + // We only have millisecond granularity in our timing code. This sleeps for 5 // millis to ensure that the status conversion code will pick up the fact // that the deadline has expired. - usleep(2000); + gpr_sleep_until(gpr_time_add(gpr_now(GPR_CLOCK_REALTIME), + gpr_time_from_millis(5, GPR_TIMESPAN))); HTTP2_ERROR_TO_GRPC_STATUS(GRPC_HTTP2_CANCEL, after_deadline, GRPC_STATUS_DEADLINE_EXCEEDED); HTTP2_ERROR_TO_GRPC_STATUS(GRPC_HTTP2_COMPRESSION_ERROR, after_deadline, From c1d354d7f2621f467e2f37f36498c20e132c3a72 Mon Sep 17 00:00:00 2001 From: Justin Burke Date: Tue, 19 Sep 2017 15:06:01 -0700 Subject: [PATCH 29/47] Support SSL server certificate reloading. --- grpc.def | 6 + include/grpc/grpc_security.h | 74 +++++- include/grpc/grpc_security_constants.h | 7 + .../credentials/ssl/ssl_credentials.cc | 156 ++++++++++- .../credentials/ssl/ssl_credentials.h | 12 + .../security/transport/security_connector.cc | 251 +++++++++++++----- .../security/transport/security_connector.h | 4 +- src/ruby/ext/grpc/rb_grpc_imports.generated.c | 12 + src/ruby/ext/grpc/rb_grpc_imports.generated.h | 18 ++ 9 files changed, 456 insertions(+), 84 deletions(-) diff --git a/grpc.def b/grpc.def index e4281f3ab67..eea12bdda50 100644 --- a/grpc.def +++ b/grpc.def @@ -132,8 +132,14 @@ EXPORTS grpc_metadata_credentials_create_from_plugin grpc_secure_channel_create grpc_server_credentials_release + grpc_ssl_server_certificate_config_create + grpc_ssl_server_certificate_config_destroy grpc_ssl_server_credentials_create grpc_ssl_server_credentials_create_ex + grpc_ssl_server_credentials_create_options_using_config + grpc_ssl_server_credentials_create_options_using_config_fetcher + grpc_ssl_server_credentials_options_destroy + grpc_ssl_server_credentials_create_with_options grpc_server_add_secure_http2_port grpc_call_set_credentials grpc_server_credentials_set_auth_metadata_processor diff --git a/include/grpc/grpc_security.h b/include/grpc/grpc_security.h index 95b14479354..758aaf5b6cc 100644 --- a/include/grpc/grpc_security.h +++ b/include/grpc/grpc_security.h @@ -316,6 +316,43 @@ typedef struct grpc_server_credentials grpc_server_credentials; */ GRPCAPI void grpc_server_credentials_release(grpc_server_credentials *creds); +/** Server certificate config object holds the server's public certificates and + associated private keys, as well as any CA certificates needed for client + certificate validation (if applicable). Create using + grpc_ssl_server_certificate_config_create(). */ +typedef struct grpc_ssl_server_certificate_config + grpc_ssl_server_certificate_config; + +/** Creates a grpc_ssl_server_certificate_config object. + - pem_roots_cert is the NULL-terminated string containing the PEM encoding of + the client root certificates. This parameter may be NULL if the server does + not want the client to be authenticated with SSL. + - pem_key_cert_pairs is an array private key / certificate chains of the + server. This parameter cannot be NULL. + - num_key_cert_pairs indicates the number of items in the private_key_files + and cert_chain_files parameters. It must be at least 1. + - It is the caller's responsibility to free this object via + grpc_ssl_server_certificate_config_destroy(). */ +GRPCAPI grpc_ssl_server_certificate_config * +grpc_ssl_server_certificate_config_create( + const char *pem_root_certs, + const grpc_ssl_pem_key_cert_pair *pem_key_cert_pairs, + size_t num_key_cert_pairs); + +/** Destroys a grpc_ssl_server_certificate_config object. */ +GRPCAPI void grpc_ssl_server_certificate_config_destroy( + grpc_ssl_server_certificate_config *config); + +/** Callback to retrieve updated SSL server certificates, private keys, and + trusted CAs (for client authentication). + - user_data parameter, if not NULL, contains opaque data to be used by the + callback. + - Use grpc_ssl_server_certificate_config_create to create the config. + - The caller assumes ownership of the config. */ +typedef grpc_ssl_certificate_config_reload_status ( + *grpc_ssl_server_certificate_config_callback)( + void *user_data, grpc_ssl_server_certificate_config **config); + /** Deprecated in favor of grpc_ssl_server_credentials_create_ex. Creates an SSL server_credentials object. - pem_roots_cert is the NULL-terminated string containing the PEM encoding of @@ -332,7 +369,8 @@ GRPCAPI grpc_server_credentials *grpc_ssl_server_credentials_create( const char *pem_root_certs, grpc_ssl_pem_key_cert_pair *pem_key_cert_pairs, size_t num_key_cert_pairs, int force_client_auth, void *reserved); -/** Same as grpc_ssl_server_credentials_create method except uses +/** Deprecated in favor of grpc_ssl_server_credentials_create_with_options. + Same as grpc_ssl_server_credentials_create method except uses grpc_ssl_client_certificate_request_type enum to support more ways to authenticate client cerificates.*/ GRPCAPI grpc_server_credentials *grpc_ssl_server_credentials_create_ex( @@ -341,6 +379,40 @@ GRPCAPI grpc_server_credentials *grpc_ssl_server_credentials_create_ex( grpc_ssl_client_certificate_request_type client_certificate_request, void *reserved); +typedef struct grpc_ssl_server_credentials_options + grpc_ssl_server_credentials_options; + +/** Creates an options object using a certificate config. Use this method when + the certificates and keys of the SSL server will not change during the + server's lifetime. + - Takes ownership of the certificate_config parameter. */ +GRPCAPI grpc_ssl_server_credentials_options * +grpc_ssl_server_credentials_create_options_using_config( + grpc_ssl_client_certificate_request_type client_certificate_request, + grpc_ssl_server_certificate_config *certificate_config); + +/** Creates an options object using a certificate config fetcher. Use this + method to reload the certificates and keys of the SSL server without + interrupting the operation of the server. Initial certificate config will be + fetched during server initialization. + - user_data parameter, if not NULL, contains opaque data which will be passed + to the fetcher (see definition of + grpc_ssl_server_certificate_config_callback). */ +GRPCAPI grpc_ssl_server_credentials_options * +grpc_ssl_server_credentials_create_options_using_config_fetcher( + grpc_ssl_client_certificate_request_type client_certificate_request, + grpc_ssl_server_certificate_config_callback cb, void *user_data); + +/** Destroys a grpc_ssl_server_credentials_options object. */ +GRPCAPI void grpc_ssl_server_credentials_options_destroy( + grpc_ssl_server_credentials_options *options); + +/** Creates an SSL server_credentials object using the provided options struct. + - Takes ownership of the options parameter. */ +GRPCAPI grpc_server_credentials * +grpc_ssl_server_credentials_create_with_options( + grpc_ssl_server_credentials_options *options); + /** --- Server-side secure ports. --- */ /** Add a HTTP2 over an encrypted link over tcp listener. diff --git a/include/grpc/grpc_security_constants.h b/include/grpc/grpc_security_constants.h index fde300dfb14..60e167eb885 100644 --- a/include/grpc/grpc_security_constants.h +++ b/include/grpc/grpc_security_constants.h @@ -48,6 +48,13 @@ typedef enum { GRPC_SSL_ROOTS_OVERRIDE_FAIL } grpc_ssl_roots_override_result; +/** Callback results for dynamically loading a SSL certificate config. */ +typedef enum { + GRPC_SSL_CERTIFICATE_CONFIG_RELOAD_UNCHANGED, + GRPC_SSL_CERTIFICATE_CONFIG_RELOAD_NEW, + GRPC_SSL_CERTIFICATE_CONFIG_RELOAD_FAIL +} grpc_ssl_certificate_config_reload_status; + typedef enum { /** Server does not request client certificate. A client can present a self signed or signed certificates if it wishes to do so and they would be diff --git a/src/core/lib/security/credentials/ssl/ssl_credentials.cc b/src/core/lib/security/credentials/ssl/ssl_credentials.cc index 8e47aebedb3..2085e2b8e7b 100644 --- a/src/core/lib/security/credentials/ssl/ssl_credentials.cc +++ b/src/core/lib/security/credentials/ssl/ssl_credentials.cc @@ -119,6 +119,12 @@ grpc_channel_credentials *grpc_ssl_credentials_create( // SSL Server Credentials. // +struct grpc_ssl_server_credentials_options { + grpc_ssl_client_certificate_request_type client_certificate_request; + grpc_ssl_server_certificate_config *certificate_config; + grpc_ssl_server_certificate_config_fetcher *certificate_config_fetcher; +}; + static void ssl_server_destruct(grpc_exec_ctx *exec_ctx, grpc_server_credentials *creds) { grpc_ssl_server_credentials *c = (grpc_ssl_server_credentials *)creds; @@ -130,9 +136,7 @@ static void ssl_server_destruct(grpc_exec_ctx *exec_ctx, static grpc_security_status ssl_server_create_security_connector( grpc_exec_ctx *exec_ctx, grpc_server_credentials *creds, grpc_server_security_connector **sc) { - grpc_ssl_server_credentials *c = (grpc_ssl_server_credentials *)creds; - return grpc_ssl_server_security_connector_create(exec_ctx, creds, &c->config, - sc); + return grpc_ssl_server_security_connector_create(exec_ctx, creds, sc); } static grpc_server_credentials_vtable ssl_server_vtable = { @@ -170,6 +174,86 @@ static void ssl_build_server_config( config->num_key_cert_pairs = num_key_cert_pairs; } +grpc_ssl_server_certificate_config *grpc_ssl_server_certificate_config_create( + const char *pem_root_certs, + const grpc_ssl_pem_key_cert_pair *pem_key_cert_pairs, + size_t num_key_cert_pairs) { + grpc_ssl_server_certificate_config *config = + (grpc_ssl_server_certificate_config *)gpr_zalloc( + sizeof(grpc_ssl_server_certificate_config)); + if (pem_root_certs != NULL) { + config->pem_root_certs = gpr_strdup(pem_root_certs); + } + if (num_key_cert_pairs > 0) { + GPR_ASSERT(pem_key_cert_pairs != NULL); + config->pem_key_cert_pairs = (grpc_ssl_pem_key_cert_pair *)gpr_zalloc( + num_key_cert_pairs * sizeof(grpc_ssl_pem_key_cert_pair)); + } + config->num_key_cert_pairs = num_key_cert_pairs; + for (size_t i = 0; i < num_key_cert_pairs; i++) { + GPR_ASSERT(pem_key_cert_pairs[i].private_key != NULL); + GPR_ASSERT(pem_key_cert_pairs[i].cert_chain != NULL); + config->pem_key_cert_pairs[i].cert_chain = + gpr_strdup(pem_key_cert_pairs[i].cert_chain); + config->pem_key_cert_pairs[i].private_key = + gpr_strdup(pem_key_cert_pairs[i].private_key); + } + return config; +} + +void grpc_ssl_server_certificate_config_destroy( + grpc_ssl_server_certificate_config *config) { + if (config == NULL) return; + for (size_t i = 0; i < config->num_key_cert_pairs; i++) { + gpr_free((void *)config->pem_key_cert_pairs[i].private_key); + gpr_free((void *)config->pem_key_cert_pairs[i].cert_chain); + } + gpr_free(config->pem_key_cert_pairs); + gpr_free(config->pem_root_certs); + gpr_free(config); +} + +grpc_ssl_server_credentials_options * +grpc_ssl_server_credentials_create_options_using_config( + grpc_ssl_client_certificate_request_type client_certificate_request, + grpc_ssl_server_certificate_config *config) { + grpc_ssl_server_credentials_options *options = NULL; + if (config == NULL) { + gpr_log(GPR_ERROR, "Certificate config must not be NULL."); + goto done; + } + options = (grpc_ssl_server_credentials_options *)gpr_zalloc( + sizeof(grpc_ssl_server_credentials_options)); + options->client_certificate_request = client_certificate_request; + options->certificate_config = config; +done: + return options; +} + +grpc_ssl_server_credentials_options * +grpc_ssl_server_credentials_create_options_using_config_fetcher( + grpc_ssl_client_certificate_request_type client_certificate_request, + grpc_ssl_server_certificate_config_callback cb, void *user_data) { + if (cb == NULL) { + gpr_log(GPR_ERROR, "Invalid certificate config callback parameter."); + return NULL; + } + + grpc_ssl_server_certificate_config_fetcher *fetcher = + (grpc_ssl_server_certificate_config_fetcher *)gpr_zalloc( + sizeof(grpc_ssl_server_certificate_config_fetcher)); + fetcher->cb = cb; + fetcher->user_data = user_data; + + grpc_ssl_server_credentials_options *options = + (grpc_ssl_server_credentials_options *)gpr_zalloc( + sizeof(grpc_ssl_server_credentials_options)); + options->client_certificate_request = client_certificate_request; + options->certificate_config_fetcher = fetcher; + + return options; +} + grpc_server_credentials *grpc_ssl_server_credentials_create( const char *pem_root_certs, grpc_ssl_pem_key_cert_pair *pem_key_cert_pairs, size_t num_key_cert_pairs, int force_client_auth, void *reserved) { @@ -186,8 +270,6 @@ grpc_server_credentials *grpc_ssl_server_credentials_create_ex( size_t num_key_cert_pairs, grpc_ssl_client_certificate_request_type client_certificate_request, void *reserved) { - grpc_ssl_server_credentials *c = (grpc_ssl_server_credentials *)gpr_zalloc( - sizeof(grpc_ssl_server_credentials)); GRPC_API_TRACE( "grpc_ssl_server_credentials_create_ex(" "pem_root_certs=%s, pem_key_cert_pairs=%p, num_key_cert_pairs=%lu, " @@ -195,11 +277,67 @@ grpc_server_credentials *grpc_ssl_server_credentials_create_ex( 5, (pem_root_certs, pem_key_cert_pairs, (unsigned long)num_key_cert_pairs, client_certificate_request, reserved)); GPR_ASSERT(reserved == NULL); + + grpc_ssl_server_certificate_config *cert_config = + grpc_ssl_server_certificate_config_create( + pem_root_certs, pem_key_cert_pairs, num_key_cert_pairs); + grpc_ssl_server_credentials_options *options = + grpc_ssl_server_credentials_create_options_using_config( + client_certificate_request, cert_config); + + return grpc_ssl_server_credentials_create_with_options(options); +} + +grpc_server_credentials *grpc_ssl_server_credentials_create_with_options( + grpc_ssl_server_credentials_options *options) { + grpc_server_credentials *retval = NULL; + grpc_ssl_server_credentials *c = NULL; + + if (options == NULL) { + gpr_log(GPR_ERROR, + "Invalid options trying to create SSL server credentials."); + goto done; + } + + if (options->certificate_config == NULL && + options->certificate_config_fetcher == NULL) { + gpr_log(GPR_ERROR, + "SSL server credentials options must specify either " + "certificate config or fetcher."); + goto done; + } else if (options->certificate_config_fetcher != NULL && + options->certificate_config_fetcher->cb == NULL) { + gpr_log(GPR_ERROR, "Certificate config fetcher callback must not be NULL."); + goto done; + } + + c = (grpc_ssl_server_credentials *)gpr_zalloc( + sizeof(grpc_ssl_server_credentials)); c->base.type = GRPC_CHANNEL_CREDENTIALS_TYPE_SSL; gpr_ref_init(&c->base.refcount, 1); c->base.vtable = &ssl_server_vtable; - ssl_build_server_config(pem_root_certs, pem_key_cert_pairs, - num_key_cert_pairs, client_certificate_request, - &c->config); - return &c->base; + + if (options->certificate_config_fetcher != NULL) { + c->config.client_certificate_request = options->client_certificate_request; + c->certificate_config_fetcher = *options->certificate_config_fetcher; + } else { + ssl_build_server_config(options->certificate_config->pem_root_certs, + options->certificate_config->pem_key_cert_pairs, + options->certificate_config->num_key_cert_pairs, + options->client_certificate_request, &c->config); + } + + retval = &c->base; + +done: + grpc_ssl_server_credentials_options_destroy(options); + return retval; +} + +void grpc_ssl_server_credentials_options_destroy( + grpc_ssl_server_credentials_options *o) { + if (o == NULL) return; + gpr_free(o->certificate_config_fetcher); + grpc_ssl_server_certificate_config_destroy(o->certificate_config); + gpr_free(o); } diff --git a/src/core/lib/security/credentials/ssl/ssl_credentials.h b/src/core/lib/security/credentials/ssl/ssl_credentials.h index 42e425d9f15..5542484aae6 100644 --- a/src/core/lib/security/credentials/ssl/ssl_credentials.h +++ b/src/core/lib/security/credentials/ssl/ssl_credentials.h @@ -29,9 +29,21 @@ typedef struct { grpc_ssl_config config; } grpc_ssl_credentials; +struct grpc_ssl_server_certificate_config { + grpc_ssl_pem_key_cert_pair *pem_key_cert_pairs; + size_t num_key_cert_pairs; + char *pem_root_certs; +}; + +typedef struct { + grpc_ssl_server_certificate_config_callback cb; + void *user_data; +} grpc_ssl_server_certificate_config_fetcher; + typedef struct { grpc_server_credentials base; grpc_ssl_server_config config; + grpc_ssl_server_certificate_config_fetcher certificate_config_fetcher; } grpc_ssl_server_credentials; tsi_ssl_pem_key_cert_pair *grpc_convert_grpc_to_tsi_cert_pairs( diff --git a/src/core/lib/security/transport/security_connector.cc b/src/core/lib/security/transport/security_connector.cc index b050be2129c..06160d0caaf 100644 --- a/src/core/lib/security/transport/security_connector.cc +++ b/src/core/lib/security/transport/security_connector.cc @@ -34,6 +34,7 @@ #include "src/core/lib/security/context/security_context.h" #include "src/core/lib/security/credentials/credentials.h" #include "src/core/lib/security/credentials/fake/fake_credentials.h" +#include "src/core/lib/security/credentials/ssl/ssl_credentials.h" #include "src/core/lib/security/transport/lb_targets_info.h" #include "src/core/lib/security/transport/secure_endpoint.h" #include "src/core/lib/security/transport/security_handshaker.h" @@ -277,6 +278,30 @@ grpc_security_connector *grpc_security_connector_find_in_args( return NULL; } +static tsi_client_certificate_request_type +get_tsi_client_certificate_request_type( + grpc_ssl_client_certificate_request_type grpc_request_type) { + switch (grpc_request_type) { + case GRPC_SSL_DONT_REQUEST_CLIENT_CERTIFICATE: + return TSI_DONT_REQUEST_CLIENT_CERTIFICATE; + + case GRPC_SSL_REQUEST_CLIENT_CERTIFICATE_BUT_DONT_VERIFY: + return TSI_REQUEST_CLIENT_CERTIFICATE_BUT_DONT_VERIFY; + + case GRPC_SSL_REQUEST_CLIENT_CERTIFICATE_AND_VERIFY: + return TSI_REQUEST_CLIENT_CERTIFICATE_AND_VERIFY; + + case GRPC_SSL_REQUEST_AND_REQUIRE_CLIENT_CERTIFICATE_BUT_DONT_VERIFY: + return TSI_REQUEST_AND_REQUIRE_CLIENT_CERTIFICATE_BUT_DONT_VERIFY; + + case GRPC_SSL_REQUEST_AND_REQUIRE_CLIENT_CERTIFICATE_AND_VERIFY: + return TSI_REQUEST_AND_REQUIRE_CLIENT_CERTIFICATE_AND_VERIFY; + + default: + return TSI_DONT_REQUEST_CLIENT_CERTIFICATE; + } +} + /* -- Fake implementation. -- */ typedef struct { @@ -533,6 +558,15 @@ typedef struct { tsi_ssl_server_handshaker_factory *server_handshaker_factory; } grpc_ssl_server_security_connector; +static bool server_connector_has_cert_config_fetcher( + grpc_ssl_server_security_connector *c) { + GPR_ASSERT(c != NULL); + grpc_ssl_server_credentials *server_creds = + (grpc_ssl_server_credentials *)c->base.server_creds; + GPR_ASSERT(server_creds != NULL); + return server_creds->certificate_config_fetcher.cb != NULL; +} + static void ssl_channel_destroy(grpc_exec_ctx *exec_ctx, grpc_security_connector *sc) { grpc_ssl_channel_security_connector *c = @@ -573,7 +607,6 @@ static void ssl_channel_add_handshakers(grpc_exec_ctx *exec_ctx, tsi_result_to_string(result)); return; } - // Create handshakers. grpc_handshake_manager_add( handshake_mgr, @@ -581,12 +614,102 @@ static void ssl_channel_add_handshakers(grpc_exec_ctx *exec_ctx, exec_ctx, tsi_create_adapter_handshaker(tsi_hs), &sc->base)); } +static const char **fill_alpn_protocol_strings(size_t *num_alpn_protocols) { + GPR_ASSERT(num_alpn_protocols != NULL); + *num_alpn_protocols = grpc_chttp2_num_alpn_versions(); + const char **alpn_protocol_strings = + (const char **)gpr_malloc(sizeof(const char *) * (*num_alpn_protocols)); + for (size_t i = 0; i < *num_alpn_protocols; i++) { + alpn_protocol_strings[i] = grpc_chttp2_get_alpn_version_index(i); + } + return alpn_protocol_strings; +} + +/* Attempts to replace the server_handshaker_factory with a new factory using + * the provided grpc_ssl_server_certificate_config. Should new factory creation + * fail, the existing factory will not be replaced. Returns true on success (new + * factory created). */ +static bool try_replace_server_handshaker_factory( + grpc_ssl_server_security_connector *sc, + const grpc_ssl_server_certificate_config *config) { + if (config == NULL) { + gpr_log(GPR_ERROR, + "Server certificate config callback returned invalid (NULL) " + "config."); + return false; + } + gpr_log(GPR_DEBUG, "Using new server certificate config (%p).", config); + + size_t num_alpn_protocols = 0; + const char **alpn_protocol_strings = + fill_alpn_protocol_strings(&num_alpn_protocols); + tsi_ssl_pem_key_cert_pair *cert_pairs = grpc_convert_grpc_to_tsi_cert_pairs( + config->pem_key_cert_pairs, config->num_key_cert_pairs); + tsi_ssl_server_handshaker_factory *new_handshaker_factory = NULL; + grpc_ssl_server_credentials *server_creds = + (grpc_ssl_server_credentials *)sc->base.server_creds; + tsi_result result = tsi_create_ssl_server_handshaker_factory_ex( + cert_pairs, config->num_key_cert_pairs, config->pem_root_certs, + get_tsi_client_certificate_request_type( + server_creds->config.client_certificate_request), + ssl_cipher_suites(), alpn_protocol_strings, (uint16_t)num_alpn_protocols, + &new_handshaker_factory); + gpr_free(cert_pairs); + gpr_free((void *)alpn_protocol_strings); + + if (result != TSI_OK) { + gpr_log(GPR_ERROR, "Handshaker factory creation failed with %s.", + tsi_result_to_string(result)); + return false; + } + tsi_ssl_server_handshaker_factory_unref(sc->server_handshaker_factory); + sc->server_handshaker_factory = new_handshaker_factory; + return true; +} + +/* Attempts to fetch the server certificate config if a callback is available. + * Current certificate config will continue to be used if the callback returns + * an error. Returns true if new credentials were sucessfully loaded. */ +static bool try_fetch_ssl_server_credentials( + grpc_ssl_server_security_connector *sc) { + grpc_ssl_server_certificate_config *certificate_config = NULL; + bool status; + + GPR_ASSERT(sc != NULL); + if (!server_connector_has_cert_config_fetcher(sc)) return false; + + grpc_ssl_server_credentials *server_creds = + (grpc_ssl_server_credentials *)sc->base.server_creds; + grpc_ssl_certificate_config_reload_status cb_result = + server_creds->certificate_config_fetcher.cb( + server_creds->certificate_config_fetcher.user_data, + &certificate_config); + if (cb_result == GRPC_SSL_CERTIFICATE_CONFIG_RELOAD_UNCHANGED) { + gpr_log(GPR_DEBUG, "No change in SSL server credentials."); + status = false; + } else if (cb_result == GRPC_SSL_CERTIFICATE_CONFIG_RELOAD_NEW) { + status = try_replace_server_handshaker_factory(sc, certificate_config); + } else { + // Log error, continue using previously-loaded credentials. + gpr_log(GPR_ERROR, + "Failed fetching new server credentials, continuing to " + "use previously-loaded credentials."); + status = false; + } + + if (certificate_config != NULL) { + grpc_ssl_server_certificate_config_destroy(certificate_config); + } + return status; +} + static void ssl_server_add_handshakers(grpc_exec_ctx *exec_ctx, grpc_server_security_connector *sc, grpc_handshake_manager *handshake_mgr) { grpc_ssl_server_security_connector *c = (grpc_ssl_server_security_connector *)sc; // Instantiate TSI handshaker. + try_fetch_ssl_server_credentials(c); tsi_handshaker *tsi_hs = NULL; tsi_result result = tsi_ssl_server_handshaker_factory_create_handshaker( c->server_handshaker_factory, &tsi_hs); @@ -595,7 +718,6 @@ static void ssl_server_add_handshakers(grpc_exec_ctx *exec_ctx, tsi_result_to_string(result)); return; } - // Create handshakers. grpc_handshake_manager_add( handshake_mgr, @@ -857,31 +979,6 @@ grpc_slice grpc_get_default_ssl_roots_for_testing(void) { return compute_default_pem_root_certs_once(); } -static tsi_client_certificate_request_type -get_tsi_client_certificate_request_type( - grpc_ssl_client_certificate_request_type grpc_request_type) { - switch (grpc_request_type) { - case GRPC_SSL_DONT_REQUEST_CLIENT_CERTIFICATE: - return TSI_DONT_REQUEST_CLIENT_CERTIFICATE; - - case GRPC_SSL_REQUEST_CLIENT_CERTIFICATE_BUT_DONT_VERIFY: - return TSI_REQUEST_CLIENT_CERTIFICATE_BUT_DONT_VERIFY; - - case GRPC_SSL_REQUEST_CLIENT_CERTIFICATE_AND_VERIFY: - return TSI_REQUEST_CLIENT_CERTIFICATE_AND_VERIFY; - - case GRPC_SSL_REQUEST_AND_REQUIRE_CLIENT_CERTIFICATE_BUT_DONT_VERIFY: - return TSI_REQUEST_AND_REQUIRE_CLIENT_CERTIFICATE_BUT_DONT_VERIFY; - - case GRPC_SSL_REQUEST_AND_REQUIRE_CLIENT_CERTIFICATE_AND_VERIFY: - return TSI_REQUEST_AND_REQUIRE_CLIENT_CERTIFICATE_AND_VERIFY; - - default: - // Is this a sane default - return TSI_DONT_REQUEST_CLIENT_CERTIFICATE; - } -} - const char *grpc_get_default_ssl_roots(void) { /* TODO(jboeuf@google.com): Maybe revisit the approach which consists in loading all the roots once for the lifetime of the process. */ @@ -897,18 +994,14 @@ grpc_security_status grpc_ssl_channel_security_connector_create( grpc_call_credentials *request_metadata_creds, const grpc_ssl_config *config, const char *target_name, const char *overridden_target_name, grpc_channel_security_connector **sc) { - size_t num_alpn_protocols = grpc_chttp2_num_alpn_versions(); + size_t num_alpn_protocols = 0; const char **alpn_protocol_strings = - (const char **)gpr_malloc(sizeof(const char *) * num_alpn_protocols); + fill_alpn_protocol_strings(&num_alpn_protocols); tsi_result result = TSI_OK; grpc_ssl_channel_security_connector *c; - size_t i; const char *pem_root_certs; char *port; bool has_key_cert_pair; - for (i = 0; i < num_alpn_protocols; i++) { - alpn_protocol_strings[i] = grpc_chttp2_get_alpn_version_index(i); - } if (config == NULL || target_name == NULL) { gpr_log(GPR_ERROR, "An ssl channel needs a config and a target name."); @@ -965,50 +1058,64 @@ error: return GRPC_SECURITY_ERROR; } +static grpc_ssl_server_security_connector * +grpc_ssl_server_security_connector_initialize( + grpc_server_credentials *server_creds) { + grpc_ssl_server_security_connector *c = + (grpc_ssl_server_security_connector *)gpr_zalloc( + sizeof(grpc_ssl_server_security_connector)); + gpr_ref_init(&c->base.base.refcount, 1); + c->base.base.url_scheme = GRPC_SSL_URL_SCHEME; + c->base.base.vtable = &ssl_server_vtable; + c->base.add_handshakers = ssl_server_add_handshakers; + c->base.server_creds = grpc_server_credentials_ref(server_creds); + return c; +} + grpc_security_status grpc_ssl_server_security_connector_create( - grpc_exec_ctx *exec_ctx, grpc_server_credentials *server_creds, - const grpc_ssl_server_config *config, grpc_server_security_connector **sc) { - size_t num_alpn_protocols = grpc_chttp2_num_alpn_versions(); - const char **alpn_protocol_strings = - (const char **)gpr_malloc(sizeof(const char *) * num_alpn_protocols); + grpc_exec_ctx *exec_ctx, grpc_server_credentials *gsc, + grpc_server_security_connector **sc) { tsi_result result = TSI_OK; - grpc_ssl_server_security_connector *c; - size_t i; + grpc_ssl_server_credentials *server_credentials = + (grpc_ssl_server_credentials *)gsc; + grpc_security_status retval = GRPC_SECURITY_OK; - for (i = 0; i < num_alpn_protocols; i++) { - alpn_protocol_strings[i] = grpc_chttp2_get_alpn_version_index(i); - } + GPR_ASSERT(server_credentials != NULL); + GPR_ASSERT(sc != NULL); - if (config == NULL || config->num_key_cert_pairs == 0) { - gpr_log(GPR_ERROR, "An SSL server needs a key and a cert."); - goto error; + grpc_ssl_server_security_connector *c = + grpc_ssl_server_security_connector_initialize(gsc); + if (server_connector_has_cert_config_fetcher(c)) { + // Load initial credentials from certificate_config_fetcher: + if (!try_fetch_ssl_server_credentials(c)) { + gpr_log(GPR_ERROR, "Failed loading SSL server credentials from fetcher."); + retval = GRPC_SECURITY_ERROR; + } + } else { + size_t num_alpn_protocols = 0; + const char **alpn_protocol_strings = + fill_alpn_protocol_strings(&num_alpn_protocols); + result = tsi_create_ssl_server_handshaker_factory_ex( + server_credentials->config.pem_key_cert_pairs, + server_credentials->config.num_key_cert_pairs, + server_credentials->config.pem_root_certs, + get_tsi_client_certificate_request_type( + server_credentials->config.client_certificate_request), + ssl_cipher_suites(), alpn_protocol_strings, + (uint16_t)num_alpn_protocols, &c->server_handshaker_factory); + gpr_free((void *)alpn_protocol_strings); + if (result != TSI_OK) { + gpr_log(GPR_ERROR, "Handshaker factory creation failed with %s.", + tsi_result_to_string(result)); + retval = GRPC_SECURITY_ERROR; + } } - c = (grpc_ssl_server_security_connector *)gpr_zalloc( - sizeof(grpc_ssl_server_security_connector)); - gpr_ref_init(&c->base.base.refcount, 1); - c->base.base.url_scheme = GRPC_SSL_URL_SCHEME; - c->base.base.vtable = &ssl_server_vtable; - c->base.server_creds = grpc_server_credentials_ref(server_creds); - result = tsi_create_ssl_server_handshaker_factory_ex( - config->pem_key_cert_pairs, config->num_key_cert_pairs, - config->pem_root_certs, get_tsi_client_certificate_request_type( - config->client_certificate_request), - ssl_cipher_suites(), alpn_protocol_strings, (uint16_t)num_alpn_protocols, - &c->server_handshaker_factory); - if (result != TSI_OK) { - gpr_log(GPR_ERROR, "Handshaker factory creation failed with %s.", - tsi_result_to_string(result)); - ssl_server_destroy(exec_ctx, &c->base.base); - *sc = NULL; - goto error; + if (retval == GRPC_SECURITY_OK) { + *sc = &c->base; + } else { + if (c != NULL) ssl_server_destroy(exec_ctx, &c->base.base); + if (sc != NULL) *sc = NULL; } - c->base.add_handshakers = ssl_server_add_handshakers; - *sc = &c->base; - gpr_free((void *)alpn_protocol_strings); - return GRPC_SECURITY_OK; - -error: - gpr_free((void *)alpn_protocol_strings); - return GRPC_SECURITY_ERROR; + return retval; } diff --git a/src/core/lib/security/transport/security_connector.h b/src/core/lib/security/transport/security_connector.h index 8287151f44a..54a563bb2c9 100644 --- a/src/core/lib/security/transport/security_connector.h +++ b/src/core/lib/security/transport/security_connector.h @@ -248,8 +248,8 @@ typedef struct { specific error code otherwise. */ grpc_security_status grpc_ssl_server_security_connector_create( - grpc_exec_ctx *exec_ctx, grpc_server_credentials *server_creds, - const grpc_ssl_server_config *config, grpc_server_security_connector **sc); + grpc_exec_ctx *exec_ctx, grpc_server_credentials *server_credentials, + grpc_server_security_connector **sc); /* Util. */ const tsi_peer_property *tsi_peer_get_property_by_name(const tsi_peer *peer, diff --git a/src/ruby/ext/grpc/rb_grpc_imports.generated.c b/src/ruby/ext/grpc/rb_grpc_imports.generated.c index cd1bd98abcd..843e05ab667 100644 --- a/src/ruby/ext/grpc/rb_grpc_imports.generated.c +++ b/src/ruby/ext/grpc/rb_grpc_imports.generated.c @@ -155,8 +155,14 @@ grpc_google_iam_credentials_create_type grpc_google_iam_credentials_create_impor grpc_metadata_credentials_create_from_plugin_type grpc_metadata_credentials_create_from_plugin_import; grpc_secure_channel_create_type grpc_secure_channel_create_import; grpc_server_credentials_release_type grpc_server_credentials_release_import; +grpc_ssl_server_certificate_config_create_type grpc_ssl_server_certificate_config_create_import; +grpc_ssl_server_certificate_config_destroy_type grpc_ssl_server_certificate_config_destroy_import; grpc_ssl_server_credentials_create_type grpc_ssl_server_credentials_create_import; grpc_ssl_server_credentials_create_ex_type grpc_ssl_server_credentials_create_ex_import; +grpc_ssl_server_credentials_create_options_using_config_type grpc_ssl_server_credentials_create_options_using_config_import; +grpc_ssl_server_credentials_create_options_using_config_fetcher_type grpc_ssl_server_credentials_create_options_using_config_fetcher_import; +grpc_ssl_server_credentials_options_destroy_type grpc_ssl_server_credentials_options_destroy_import; +grpc_ssl_server_credentials_create_with_options_type grpc_ssl_server_credentials_create_with_options_import; grpc_server_add_secure_http2_port_type grpc_server_add_secure_http2_port_import; grpc_call_set_credentials_type grpc_call_set_credentials_import; grpc_server_credentials_set_auth_metadata_processor_type grpc_server_credentials_set_auth_metadata_processor_import; @@ -465,8 +471,14 @@ void grpc_rb_load_imports(HMODULE library) { grpc_metadata_credentials_create_from_plugin_import = (grpc_metadata_credentials_create_from_plugin_type) GetProcAddress(library, "grpc_metadata_credentials_create_from_plugin"); grpc_secure_channel_create_import = (grpc_secure_channel_create_type) GetProcAddress(library, "grpc_secure_channel_create"); grpc_server_credentials_release_import = (grpc_server_credentials_release_type) GetProcAddress(library, "grpc_server_credentials_release"); + grpc_ssl_server_certificate_config_create_import = (grpc_ssl_server_certificate_config_create_type) GetProcAddress(library, "grpc_ssl_server_certificate_config_create"); + grpc_ssl_server_certificate_config_destroy_import = (grpc_ssl_server_certificate_config_destroy_type) GetProcAddress(library, "grpc_ssl_server_certificate_config_destroy"); grpc_ssl_server_credentials_create_import = (grpc_ssl_server_credentials_create_type) GetProcAddress(library, "grpc_ssl_server_credentials_create"); grpc_ssl_server_credentials_create_ex_import = (grpc_ssl_server_credentials_create_ex_type) GetProcAddress(library, "grpc_ssl_server_credentials_create_ex"); + grpc_ssl_server_credentials_create_options_using_config_import = (grpc_ssl_server_credentials_create_options_using_config_type) GetProcAddress(library, "grpc_ssl_server_credentials_create_options_using_config"); + grpc_ssl_server_credentials_create_options_using_config_fetcher_import = (grpc_ssl_server_credentials_create_options_using_config_fetcher_type) GetProcAddress(library, "grpc_ssl_server_credentials_create_options_using_config_fetcher"); + grpc_ssl_server_credentials_options_destroy_import = (grpc_ssl_server_credentials_options_destroy_type) GetProcAddress(library, "grpc_ssl_server_credentials_options_destroy"); + grpc_ssl_server_credentials_create_with_options_import = (grpc_ssl_server_credentials_create_with_options_type) GetProcAddress(library, "grpc_ssl_server_credentials_create_with_options"); grpc_server_add_secure_http2_port_import = (grpc_server_add_secure_http2_port_type) GetProcAddress(library, "grpc_server_add_secure_http2_port"); grpc_call_set_credentials_import = (grpc_call_set_credentials_type) GetProcAddress(library, "grpc_call_set_credentials"); grpc_server_credentials_set_auth_metadata_processor_import = (grpc_server_credentials_set_auth_metadata_processor_type) GetProcAddress(library, "grpc_server_credentials_set_auth_metadata_processor"); diff --git a/src/ruby/ext/grpc/rb_grpc_imports.generated.h b/src/ruby/ext/grpc/rb_grpc_imports.generated.h index c7e78b70dcb..998eef800e0 100644 --- a/src/ruby/ext/grpc/rb_grpc_imports.generated.h +++ b/src/ruby/ext/grpc/rb_grpc_imports.generated.h @@ -446,12 +446,30 @@ extern grpc_secure_channel_create_type grpc_secure_channel_create_import; typedef void(*grpc_server_credentials_release_type)(grpc_server_credentials *creds); extern grpc_server_credentials_release_type grpc_server_credentials_release_import; #define grpc_server_credentials_release grpc_server_credentials_release_import +typedef grpc_ssl_server_certificate_config *(*grpc_ssl_server_certificate_config_create_type)(const char *pem_root_certs, const grpc_ssl_pem_key_cert_pair *pem_key_cert_pairs, size_t num_key_cert_pairs); +extern grpc_ssl_server_certificate_config_create_type grpc_ssl_server_certificate_config_create_import; +#define grpc_ssl_server_certificate_config_create grpc_ssl_server_certificate_config_create_import +typedef void(*grpc_ssl_server_certificate_config_destroy_type)(grpc_ssl_server_certificate_config *config); +extern grpc_ssl_server_certificate_config_destroy_type grpc_ssl_server_certificate_config_destroy_import; +#define grpc_ssl_server_certificate_config_destroy grpc_ssl_server_certificate_config_destroy_import typedef grpc_server_credentials *(*grpc_ssl_server_credentials_create_type)(const char *pem_root_certs, grpc_ssl_pem_key_cert_pair *pem_key_cert_pairs, size_t num_key_cert_pairs, int force_client_auth, void *reserved); extern grpc_ssl_server_credentials_create_type grpc_ssl_server_credentials_create_import; #define grpc_ssl_server_credentials_create grpc_ssl_server_credentials_create_import typedef grpc_server_credentials *(*grpc_ssl_server_credentials_create_ex_type)(const char *pem_root_certs, grpc_ssl_pem_key_cert_pair *pem_key_cert_pairs, size_t num_key_cert_pairs, grpc_ssl_client_certificate_request_type client_certificate_request, void *reserved); extern grpc_ssl_server_credentials_create_ex_type grpc_ssl_server_credentials_create_ex_import; #define grpc_ssl_server_credentials_create_ex grpc_ssl_server_credentials_create_ex_import +typedef grpc_ssl_server_credentials_options *(*grpc_ssl_server_credentials_create_options_using_config_type)(grpc_ssl_client_certificate_request_type client_certificate_request, grpc_ssl_server_certificate_config *certificate_config); +extern grpc_ssl_server_credentials_create_options_using_config_type grpc_ssl_server_credentials_create_options_using_config_import; +#define grpc_ssl_server_credentials_create_options_using_config grpc_ssl_server_credentials_create_options_using_config_import +typedef grpc_ssl_server_credentials_options *(*grpc_ssl_server_credentials_create_options_using_config_fetcher_type)(grpc_ssl_client_certificate_request_type client_certificate_request, grpc_ssl_server_certificate_config_callback cb, void *user_data); +extern grpc_ssl_server_credentials_create_options_using_config_fetcher_type grpc_ssl_server_credentials_create_options_using_config_fetcher_import; +#define grpc_ssl_server_credentials_create_options_using_config_fetcher grpc_ssl_server_credentials_create_options_using_config_fetcher_import +typedef void(*grpc_ssl_server_credentials_options_destroy_type)(grpc_ssl_server_credentials_options *options); +extern grpc_ssl_server_credentials_options_destroy_type grpc_ssl_server_credentials_options_destroy_import; +#define grpc_ssl_server_credentials_options_destroy grpc_ssl_server_credentials_options_destroy_import +typedef grpc_server_credentials *(*grpc_ssl_server_credentials_create_with_options_type)(grpc_ssl_server_credentials_options *options); +extern grpc_ssl_server_credentials_create_with_options_type grpc_ssl_server_credentials_create_with_options_import; +#define grpc_ssl_server_credentials_create_with_options grpc_ssl_server_credentials_create_with_options_import typedef int(*grpc_server_add_secure_http2_port_type)(grpc_server *server, const char *addr, grpc_server_credentials *creds); extern grpc_server_add_secure_http2_port_type grpc_server_add_secure_http2_port_import; #define grpc_server_add_secure_http2_port grpc_server_add_secure_http2_port_import From 667aa2b9906aa4eb8bdb3f049444ad68adde5aa8 Mon Sep 17 00:00:00 2001 From: Ken Payson Date: Fri, 27 Oct 2017 14:33:17 -0700 Subject: [PATCH 30/47] Add call size bm_diff --- Makefile | 1 + grpc.gyp | 1 + test/cpp/microbenchmarks/helpers.cc | 14 ++++++++++---- third_party/benchmark | 2 +- .../microbenchmarks/bm_diff/bm_constants.py | 2 +- tools/run_tests/generated/sources_and_headers.json | 2 +- tools/run_tests/sanity/check_submodules.sh | 2 +- 7 files changed, 16 insertions(+), 8 deletions(-) diff --git a/Makefile b/Makefile index 325c9123d99..236dc74779e 100644 --- a/Makefile +++ b/Makefile @@ -8298,6 +8298,7 @@ LIBBENCHMARK_SRC = \ third_party/benchmark/src/commandlineflags.cc \ third_party/benchmark/src/complexity.cc \ third_party/benchmark/src/console_reporter.cc \ + third_party/benchmark/src/counter.cc \ third_party/benchmark/src/csv_reporter.cc \ third_party/benchmark/src/json_reporter.cc \ third_party/benchmark/src/reporter.cc \ diff --git a/grpc.gyp b/grpc.gyp index 487d529316e..e61166e7698 100644 --- a/grpc.gyp +++ b/grpc.gyp @@ -2316,6 +2316,7 @@ 'third_party/benchmark/src/commandlineflags.cc', 'third_party/benchmark/src/complexity.cc', 'third_party/benchmark/src/console_reporter.cc', + 'third_party/benchmark/src/counter.cc', 'third_party/benchmark/src/csv_reporter.cc', 'third_party/benchmark/src/json_reporter.cc', 'third_party/benchmark/src/reporter.cc', diff --git a/test/cpp/microbenchmarks/helpers.cc b/test/cpp/microbenchmarks/helpers.cc index 6802a0aa99b..782f12e99a1 100644 --- a/test/cpp/microbenchmarks/helpers.cc +++ b/test/cpp/microbenchmarks/helpers.cc @@ -16,6 +16,8 @@ * */ +#include + #include "test/cpp/microbenchmarks/helpers.h" void TrackCounters::Finish(benchmark::State &state) { @@ -45,10 +47,14 @@ void TrackCounters::AddToLabel(std::ostream &out, benchmark::State &state) { << "/iter:" << ((double)stats.counters[i] / (double)state.iterations()); } for (int i = 0; i < GRPC_STATS_HISTOGRAM_COUNT; i++) { - out << " " << grpc_stats_histogram_name[i] << "-median:" - << grpc_stats_histo_percentile(&stats, (grpc_stats_histograms)i, 50.0) - << " " << grpc_stats_histogram_name[i] << "-99p:" - << grpc_stats_histo_percentile(&stats, (grpc_stats_histograms)i, 99.0); + std::ostringstream median_ss; + median_ss << grpc_stats_histogram_name[i] << "-median"; + state.counters[median_ss.str()] = benchmark::Counter( + grpc_stats_histo_percentile(&stats, (grpc_stats_histograms)i, 50.0)); + std::ostringstream tail_ss; + tail_ss << grpc_stats_histogram_name[i] << "-99p"; + state.counters[tail_ss.str()] = benchmark::Counter( + grpc_stats_histo_percentile(&stats, (grpc_stats_histograms)i, 99.0)); } #ifdef GPR_LOW_LEVEL_COUNTERS grpc_memory_counters counters_at_end = grpc_memory_counters_snapshot(); diff --git a/third_party/benchmark b/third_party/benchmark index 44c25c892a6..5b7683f49e1 160000 --- a/third_party/benchmark +++ b/third_party/benchmark @@ -1 +1 @@ -Subproject commit 44c25c892a6229b20db7cd9dc05584ea865896de +Subproject commit 5b7683f49e1e9223cf9927b24f6fd3d6bd82e3f8 diff --git a/tools/profiling/microbenchmarks/bm_diff/bm_constants.py b/tools/profiling/microbenchmarks/bm_diff/bm_constants.py index f8989b17fc8..0ec17fa17e2 100644 --- a/tools/profiling/microbenchmarks/bm_diff/bm_constants.py +++ b/tools/profiling/microbenchmarks/bm_diff/bm_constants.py @@ -23,7 +23,7 @@ _AVAILABLE_BENCHMARK_TESTS = [ 'bm_metadata', 'bm_fullstack_trickle' ] -_INTERESTING = ('cpu_time', 'real_time', 'locks_per_iteration', +_INTERESTING = ('cpu_time', 'real_time', 'call_initial_size-median', 'locks_per_iteration', 'allocs_per_iteration', 'writes_per_iteration', 'atm_cas_per_iteration', 'atm_add_per_iteration', 'nows_per_iteration', 'cli_transport_stalls_per_iteration', diff --git a/tools/run_tests/generated/sources_and_headers.json b/tools/run_tests/generated/sources_and_headers.json index 46f4cb65329..08ab2a5d931 100644 --- a/tools/run_tests/generated/sources_and_headers.json +++ b/tools/run_tests/generated/sources_and_headers.json @@ -7453,7 +7453,6 @@ "headers": [ "third_party/benchmark/include/benchmark/benchmark.h", "third_party/benchmark/include/benchmark/benchmark_api.h", - "third_party/benchmark/include/benchmark/macros.h", "third_party/benchmark/include/benchmark/reporter.h", "third_party/benchmark/src/arraysize.h", "third_party/benchmark/src/benchmark_api_internal.h", @@ -7461,6 +7460,7 @@ "third_party/benchmark/src/colorprint.h", "third_party/benchmark/src/commandlineflags.h", "third_party/benchmark/src/complexity.h", + "third_party/benchmark/src/counter.h", "third_party/benchmark/src/cycleclock.h", "third_party/benchmark/src/internal_macros.h", "third_party/benchmark/src/log.h", diff --git a/tools/run_tests/sanity/check_submodules.sh b/tools/run_tests/sanity/check_submodules.sh index 2aee0001a3b..1f7b078ff7a 100755 --- a/tools/run_tests/sanity/check_submodules.sh +++ b/tools/run_tests/sanity/check_submodules.sh @@ -26,7 +26,7 @@ want_submodules=`mktemp /tmp/submXXXXXX` git submodule | awk '{ print $1 }' | sort > $submodules cat << EOF | awk '{ print $1 }' | sort > $want_submodules - 44c25c892a6229b20db7cd9dc05584ea865896de third_party/benchmark (v0.1.0-343-g44c25c8) + 5b7683f49e1e9223cf9927b24f6fd3d6bd82e3f8 third_party/benchmark (v1.2.0) be2ee342d3781ddb954f91f8a7e660c6f59e87e5 third_party/boringssl (heads/chromium-stable) 886e7d75368e3f4fab3f4d0d3584e4abfc557755 third_party/boringssl-with-bazel (version_for_cocoapods_7.0-857-g886e7d7) 30dbc81fb5ffdc98ea9b14b1918bfe4e8779b26e third_party/gflags (v2.2.0) From 7269667f9e091445faa62f8ed96885dca4686487 Mon Sep 17 00:00:00 2001 From: Yuchen Zeng Date: Tue, 26 Sep 2017 19:37:49 -0700 Subject: [PATCH 31/47] Add client channel connectivity watcher --- BUILD | 3 + CMakeLists.txt | 6 + Makefile | 6 + binding.gyp | 1 + config.m4 | 1 + config.w32 | 1 + gRPC-Core.podspec | 5 + grpc.gemspec | 3 + grpc.gyp | 4 + package.xml | 3 + .../client_channel/channel_connectivity.cc | 165 +-------------- .../channel_connectivity_internal.cc | 195 ++++++++++++++++++ .../channel_connectivity_internal.h | 33 +++ .../filters/client_channel/client_channel.cc | 3 + .../client_channel/connectivity_watcher.c | 179 ++++++++++++++++ .../client_channel/connectivity_watcher.h | 30 +++ src/python/grpcio/grpc_core_dependencies.py | 1 + tools/doxygen/Doxyfile.core.internal | 3 + .../generated/sources_and_headers.json | 5 + 19 files changed, 491 insertions(+), 156 deletions(-) create mode 100644 src/core/ext/filters/client_channel/channel_connectivity_internal.cc create mode 100644 src/core/ext/filters/client_channel/channel_connectivity_internal.h create mode 100644 src/core/ext/filters/client_channel/connectivity_watcher.c create mode 100644 src/core/ext/filters/client_channel/connectivity_watcher.h diff --git a/BUILD b/BUILD index 99411f955e7..4e1f61ee10d 100644 --- a/BUILD +++ b/BUILD @@ -876,6 +876,7 @@ grpc_cc_library( "src/core/ext/filters/client_channel/client_channel.cc", "src/core/ext/filters/client_channel/client_channel_factory.cc", "src/core/ext/filters/client_channel/client_channel_plugin.cc", + "src/core/ext/filters/client_channel/connectivity_watcher.cc", "src/core/ext/filters/client_channel/connector.cc", "src/core/ext/filters/client_channel/http_connect_handshaker.cc", "src/core/ext/filters/client_channel/http_proxy.cc", @@ -894,8 +895,10 @@ grpc_cc_library( "src/core/ext/filters/client_channel/uri_parser.cc", ], hdrs = [ + "src/core/ext/filters/client_channel/channel_connectivity_internal.h", "src/core/ext/filters/client_channel/client_channel.h", "src/core/ext/filters/client_channel/client_channel_factory.h", + "src/core/ext/filters/client_channel/connectivity_watcher.h", "src/core/ext/filters/client_channel/connector.h", "src/core/ext/filters/client_channel/http_connect_handshaker.h", "src/core/ext/filters/client_channel/http_proxy.h", diff --git a/CMakeLists.txt b/CMakeLists.txt index 3ac6c9b63d9..8122d4b0253 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -1157,6 +1157,7 @@ add_library(grpc src/core/ext/filters/client_channel/client_channel.cc src/core/ext/filters/client_channel/client_channel_factory.cc src/core/ext/filters/client_channel/client_channel_plugin.cc + src/core/ext/filters/client_channel/connectivity_watcher.c src/core/ext/filters/client_channel/connector.cc src/core/ext/filters/client_channel/http_connect_handshaker.cc src/core/ext/filters/client_channel/http_proxy.cc @@ -1481,6 +1482,7 @@ add_library(grpc_cronet src/core/ext/filters/client_channel/client_channel.cc src/core/ext/filters/client_channel/client_channel_factory.cc src/core/ext/filters/client_channel/client_channel_plugin.cc + src/core/ext/filters/client_channel/connectivity_watcher.c src/core/ext/filters/client_channel/connector.cc src/core/ext/filters/client_channel/http_connect_handshaker.cc src/core/ext/filters/client_channel/http_proxy.cc @@ -1771,6 +1773,7 @@ add_library(grpc_test_util src/core/ext/filters/client_channel/client_channel.cc src/core/ext/filters/client_channel/client_channel_factory.cc src/core/ext/filters/client_channel/client_channel_plugin.cc + src/core/ext/filters/client_channel/connectivity_watcher.c src/core/ext/filters/client_channel/connector.cc src/core/ext/filters/client_channel/http_connect_handshaker.cc src/core/ext/filters/client_channel/http_proxy.cc @@ -2036,6 +2039,7 @@ add_library(grpc_test_util_unsecure src/core/ext/filters/client_channel/client_channel.cc src/core/ext/filters/client_channel/client_channel_factory.cc src/core/ext/filters/client_channel/client_channel_plugin.cc + src/core/ext/filters/client_channel/connectivity_watcher.c src/core/ext/filters/client_channel/connector.cc src/core/ext/filters/client_channel/http_connect_handshaker.cc src/core/ext/filters/client_channel/http_proxy.cc @@ -2320,6 +2324,7 @@ add_library(grpc_unsecure src/core/ext/filters/client_channel/client_channel.cc src/core/ext/filters/client_channel/client_channel_factory.cc src/core/ext/filters/client_channel/client_channel_plugin.cc + src/core/ext/filters/client_channel/connectivity_watcher.c src/core/ext/filters/client_channel/connector.cc src/core/ext/filters/client_channel/http_connect_handshaker.cc src/core/ext/filters/client_channel/http_proxy.cc @@ -3055,6 +3060,7 @@ add_library(grpc++_cronet src/core/ext/filters/client_channel/client_channel.cc src/core/ext/filters/client_channel/client_channel_factory.cc src/core/ext/filters/client_channel/client_channel_plugin.cc + src/core/ext/filters/client_channel/connectivity_watcher.c src/core/ext/filters/client_channel/connector.cc src/core/ext/filters/client_channel/http_connect_handshaker.cc src/core/ext/filters/client_channel/http_proxy.cc diff --git a/Makefile b/Makefile index 236dc74779e..3ff9b39f456 100644 --- a/Makefile +++ b/Makefile @@ -3157,6 +3157,7 @@ LIBGRPC_SRC = \ src/core/ext/filters/client_channel/client_channel.cc \ src/core/ext/filters/client_channel/client_channel_factory.cc \ src/core/ext/filters/client_channel/client_channel_plugin.cc \ + src/core/ext/filters/client_channel/connectivity_watcher.c \ src/core/ext/filters/client_channel/connector.cc \ src/core/ext/filters/client_channel/http_connect_handshaker.cc \ src/core/ext/filters/client_channel/http_proxy.cc \ @@ -3480,6 +3481,7 @@ LIBGRPC_CRONET_SRC = \ src/core/ext/filters/client_channel/client_channel.cc \ src/core/ext/filters/client_channel/client_channel_factory.cc \ src/core/ext/filters/client_channel/client_channel_plugin.cc \ + src/core/ext/filters/client_channel/connectivity_watcher.c \ src/core/ext/filters/client_channel/connector.cc \ src/core/ext/filters/client_channel/http_connect_handshaker.cc \ src/core/ext/filters/client_channel/http_proxy.cc \ @@ -3768,6 +3770,7 @@ LIBGRPC_TEST_UTIL_SRC = \ src/core/ext/filters/client_channel/client_channel.cc \ src/core/ext/filters/client_channel/client_channel_factory.cc \ src/core/ext/filters/client_channel/client_channel_plugin.cc \ + src/core/ext/filters/client_channel/connectivity_watcher.c \ src/core/ext/filters/client_channel/connector.cc \ src/core/ext/filters/client_channel/http_connect_handshaker.cc \ src/core/ext/filters/client_channel/http_proxy.cc \ @@ -4023,6 +4026,7 @@ LIBGRPC_TEST_UTIL_UNSECURE_SRC = \ src/core/ext/filters/client_channel/client_channel.cc \ src/core/ext/filters/client_channel/client_channel_factory.cc \ src/core/ext/filters/client_channel/client_channel_plugin.cc \ + src/core/ext/filters/client_channel/connectivity_watcher.c \ src/core/ext/filters/client_channel/connector.cc \ src/core/ext/filters/client_channel/http_connect_handshaker.cc \ src/core/ext/filters/client_channel/http_proxy.cc \ @@ -4284,6 +4288,7 @@ LIBGRPC_UNSECURE_SRC = \ src/core/ext/filters/client_channel/client_channel.cc \ src/core/ext/filters/client_channel/client_channel_factory.cc \ src/core/ext/filters/client_channel/client_channel_plugin.cc \ + src/core/ext/filters/client_channel/connectivity_watcher.c \ src/core/ext/filters/client_channel/connector.cc \ src/core/ext/filters/client_channel/http_connect_handshaker.cc \ src/core/ext/filters/client_channel/http_proxy.cc \ @@ -4997,6 +5002,7 @@ LIBGRPC++_CRONET_SRC = \ src/core/ext/filters/client_channel/client_channel.cc \ src/core/ext/filters/client_channel/client_channel_factory.cc \ src/core/ext/filters/client_channel/client_channel_plugin.cc \ + src/core/ext/filters/client_channel/connectivity_watcher.c \ src/core/ext/filters/client_channel/connector.cc \ src/core/ext/filters/client_channel/http_connect_handshaker.cc \ src/core/ext/filters/client_channel/http_proxy.cc \ diff --git a/binding.gyp b/binding.gyp index e004b0fa328..707afb476a4 100644 --- a/binding.gyp +++ b/binding.gyp @@ -857,6 +857,7 @@ 'src/core/ext/filters/client_channel/client_channel.cc', 'src/core/ext/filters/client_channel/client_channel_factory.cc', 'src/core/ext/filters/client_channel/client_channel_plugin.cc', + 'src/core/ext/filters/client_channel/connectivity_watcher.c', 'src/core/ext/filters/client_channel/connector.cc', 'src/core/ext/filters/client_channel/http_connect_handshaker.cc', 'src/core/ext/filters/client_channel/http_proxy.cc', diff --git a/config.m4 b/config.m4 index 5d92a2ae348..eaa3af978b0 100644 --- a/config.m4 +++ b/config.m4 @@ -282,6 +282,7 @@ if test "$PHP_GRPC" != "no"; then src/core/ext/filters/client_channel/client_channel.cc \ src/core/ext/filters/client_channel/client_channel_factory.cc \ src/core/ext/filters/client_channel/client_channel_plugin.cc \ + src/core/ext/filters/client_channel/connectivity_watcher.c \ src/core/ext/filters/client_channel/connector.cc \ src/core/ext/filters/client_channel/http_connect_handshaker.cc \ src/core/ext/filters/client_channel/http_proxy.cc \ diff --git a/config.w32 b/config.w32 index 67b5e2f5543..75a83e24140 100644 --- a/config.w32 +++ b/config.w32 @@ -259,6 +259,7 @@ if (PHP_GRPC != "no") { "src\\core\\ext\\filters\\client_channel\\client_channel.cc " + "src\\core\\ext\\filters\\client_channel\\client_channel_factory.cc " + "src\\core\\ext\\filters\\client_channel\\client_channel_plugin.cc " + + "src\\core\\ext\\filters\\client_channel\\connectivity_watcher.c " + "src\\core\\ext\\filters\\client_channel\\connector.cc " + "src\\core\\ext\\filters\\client_channel\\http_connect_handshaker.cc " + "src\\core\\ext\\filters\\client_channel\\http_proxy.cc " + diff --git a/gRPC-Core.podspec b/gRPC-Core.podspec index 0e3b50c4aad..9b4f4ec6752 100644 --- a/gRPC-Core.podspec +++ b/gRPC-Core.podspec @@ -299,8 +299,10 @@ Pod::Spec.new do |s| 'src/core/tsi/transport_security_adapter.h', 'src/core/tsi/transport_security_interface.h', 'src/core/ext/transport/chttp2/server/chttp2_server.h', + 'src/core/ext/filters/client_channel/channel_connectivity_internal.h', 'src/core/ext/filters/client_channel/client_channel.h', 'src/core/ext/filters/client_channel/client_channel_factory.h', + 'src/core/ext/filters/client_channel/connectivity_watcher.h', 'src/core/ext/filters/client_channel/connector.h', 'src/core/ext/filters/client_channel/http_connect_handshaker.h', 'src/core/ext/filters/client_channel/http_proxy.h', @@ -672,6 +674,7 @@ Pod::Spec.new do |s| 'src/core/ext/filters/client_channel/client_channel.cc', 'src/core/ext/filters/client_channel/client_channel_factory.cc', 'src/core/ext/filters/client_channel/client_channel_plugin.cc', + 'src/core/ext/filters/client_channel/connectivity_watcher.c', 'src/core/ext/filters/client_channel/connector.cc', 'src/core/ext/filters/client_channel/http_connect_handshaker.cc', 'src/core/ext/filters/client_channel/http_proxy.cc', @@ -802,8 +805,10 @@ Pod::Spec.new do |s| 'src/core/tsi/transport_security_adapter.h', 'src/core/tsi/transport_security_interface.h', 'src/core/ext/transport/chttp2/server/chttp2_server.h', + 'src/core/ext/filters/client_channel/channel_connectivity_internal.h', 'src/core/ext/filters/client_channel/client_channel.h', 'src/core/ext/filters/client_channel/client_channel_factory.h', + 'src/core/ext/filters/client_channel/connectivity_watcher.h', 'src/core/ext/filters/client_channel/connector.h', 'src/core/ext/filters/client_channel/http_connect_handshaker.h', 'src/core/ext/filters/client_channel/http_proxy.h', diff --git a/grpc.gemspec b/grpc.gemspec index 45670583441..9f5f45bb1bf 100644 --- a/grpc.gemspec +++ b/grpc.gemspec @@ -230,8 +230,10 @@ Gem::Specification.new do |s| s.files += %w( src/core/tsi/transport_security_adapter.h ) s.files += %w( src/core/tsi/transport_security_interface.h ) s.files += %w( src/core/ext/transport/chttp2/server/chttp2_server.h ) + s.files += %w( src/core/ext/filters/client_channel/channel_connectivity_internal.h ) s.files += %w( src/core/ext/filters/client_channel/client_channel.h ) s.files += %w( src/core/ext/filters/client_channel/client_channel_factory.h ) + s.files += %w( src/core/ext/filters/client_channel/connectivity_watcher.h ) s.files += %w( src/core/ext/filters/client_channel/connector.h ) s.files += %w( src/core/ext/filters/client_channel/http_connect_handshaker.h ) s.files += %w( src/core/ext/filters/client_channel/http_proxy.h ) @@ -607,6 +609,7 @@ Gem::Specification.new do |s| s.files += %w( src/core/ext/filters/client_channel/client_channel.cc ) s.files += %w( src/core/ext/filters/client_channel/client_channel_factory.cc ) s.files += %w( src/core/ext/filters/client_channel/client_channel_plugin.cc ) + s.files += %w( src/core/ext/filters/client_channel/connectivity_watcher.c ) s.files += %w( src/core/ext/filters/client_channel/connector.cc ) s.files += %w( src/core/ext/filters/client_channel/http_connect_handshaker.cc ) s.files += %w( src/core/ext/filters/client_channel/http_proxy.cc ) diff --git a/grpc.gyp b/grpc.gyp index e61166e7698..420621fb4c5 100644 --- a/grpc.gyp +++ b/grpc.gyp @@ -423,6 +423,7 @@ 'src/core/ext/filters/client_channel/client_channel.cc', 'src/core/ext/filters/client_channel/client_channel_factory.cc', 'src/core/ext/filters/client_channel/client_channel_plugin.cc', + 'src/core/ext/filters/client_channel/connectivity_watcher.c', 'src/core/ext/filters/client_channel/connector.cc', 'src/core/ext/filters/client_channel/http_connect_handshaker.cc', 'src/core/ext/filters/client_channel/http_proxy.cc', @@ -665,6 +666,7 @@ 'src/core/ext/filters/client_channel/client_channel.cc', 'src/core/ext/filters/client_channel/client_channel_factory.cc', 'src/core/ext/filters/client_channel/client_channel_plugin.cc', + 'src/core/ext/filters/client_channel/connectivity_watcher.c', 'src/core/ext/filters/client_channel/connector.cc', 'src/core/ext/filters/client_channel/http_connect_handshaker.cc', 'src/core/ext/filters/client_channel/http_proxy.cc', @@ -872,6 +874,7 @@ 'src/core/ext/filters/client_channel/client_channel.cc', 'src/core/ext/filters/client_channel/client_channel_factory.cc', 'src/core/ext/filters/client_channel/client_channel_plugin.cc', + 'src/core/ext/filters/client_channel/connectivity_watcher.c', 'src/core/ext/filters/client_channel/connector.cc', 'src/core/ext/filters/client_channel/http_connect_handshaker.cc', 'src/core/ext/filters/client_channel/http_proxy.cc', @@ -1097,6 +1100,7 @@ 'src/core/ext/filters/client_channel/client_channel.cc', 'src/core/ext/filters/client_channel/client_channel_factory.cc', 'src/core/ext/filters/client_channel/client_channel_plugin.cc', + 'src/core/ext/filters/client_channel/connectivity_watcher.c', 'src/core/ext/filters/client_channel/connector.cc', 'src/core/ext/filters/client_channel/http_connect_handshaker.cc', 'src/core/ext/filters/client_channel/http_proxy.cc', diff --git a/package.xml b/package.xml index d08b803355e..65cb53ad1cc 100644 --- a/package.xml +++ b/package.xml @@ -242,8 +242,10 @@ + + @@ -619,6 +621,7 @@ + diff --git a/src/core/ext/filters/client_channel/channel_connectivity.cc b/src/core/ext/filters/client_channel/channel_connectivity.cc index 31a8fc39ce6..33e9deaaf6b 100644 --- a/src/core/ext/filters/client_channel/channel_connectivity.cc +++ b/src/core/ext/filters/client_channel/channel_connectivity.cc @@ -23,8 +23,8 @@ #include #include +#include "src/core/ext/filters/client_channel/channel_connectivity_internal.h" #include "src/core/ext/filters/client_channel/client_channel.h" -#include "src/core/lib/iomgr/timer.h" #include "src/core/lib/surface/api_trace.h" #include "src/core/lib/surface/completion_queue.h" @@ -52,125 +52,6 @@ grpc_connectivity_state grpc_channel_check_connectivity_state( return GRPC_CHANNEL_SHUTDOWN; } -typedef enum { - WAITING, - READY_TO_CALL_BACK, - CALLING_BACK_AND_FINISHED, -} callback_phase; - -typedef struct { - gpr_mu mu; - callback_phase phase; - grpc_closure on_complete; - grpc_closure on_timeout; - grpc_closure watcher_timer_init; - grpc_timer alarm; - grpc_connectivity_state state; - grpc_completion_queue *cq; - grpc_cq_completion completion_storage; - grpc_channel *channel; - grpc_error *error; - void *tag; -} state_watcher; - -static void delete_state_watcher(grpc_exec_ctx *exec_ctx, state_watcher *w) { - grpc_channel_element *client_channel_elem = grpc_channel_stack_last_element( - grpc_channel_get_channel_stack(w->channel)); - if (client_channel_elem->filter == &grpc_client_channel_filter) { - GRPC_CHANNEL_INTERNAL_UNREF(exec_ctx, w->channel, - "watch_channel_connectivity"); - } else { - abort(); - } - gpr_mu_destroy(&w->mu); - gpr_free(w); -} - -static void finished_completion(grpc_exec_ctx *exec_ctx, void *pw, - grpc_cq_completion *ignored) { - bool should_delete = false; - state_watcher *w = (state_watcher *)pw; - gpr_mu_lock(&w->mu); - switch (w->phase) { - case WAITING: - case READY_TO_CALL_BACK: - GPR_UNREACHABLE_CODE(return ); - case CALLING_BACK_AND_FINISHED: - should_delete = true; - break; - } - gpr_mu_unlock(&w->mu); - - if (should_delete) { - delete_state_watcher(exec_ctx, w); - } -} - -static void partly_done(grpc_exec_ctx *exec_ctx, state_watcher *w, - bool due_to_completion, grpc_error *error) { - if (due_to_completion) { - grpc_timer_cancel(exec_ctx, &w->alarm); - } else { - grpc_channel_element *client_channel_elem = grpc_channel_stack_last_element( - grpc_channel_get_channel_stack(w->channel)); - grpc_client_channel_watch_connectivity_state( - exec_ctx, client_channel_elem, - grpc_polling_entity_create_from_pollset(grpc_cq_pollset(w->cq)), NULL, - &w->on_complete, NULL); - } - - gpr_mu_lock(&w->mu); - - if (due_to_completion) { - if (GRPC_TRACER_ON(grpc_trace_operation_failures)) { - GRPC_LOG_IF_ERROR("watch_completion_error", GRPC_ERROR_REF(error)); - } - GRPC_ERROR_UNREF(error); - error = GRPC_ERROR_NONE; - } else { - if (error == GRPC_ERROR_NONE) { - error = GRPC_ERROR_CREATE_FROM_STATIC_STRING( - "Timed out waiting for connection state change"); - } else if (error == GRPC_ERROR_CANCELLED) { - error = GRPC_ERROR_NONE; - } - } - switch (w->phase) { - case WAITING: - GRPC_ERROR_REF(error); - w->error = error; - w->phase = READY_TO_CALL_BACK; - break; - case READY_TO_CALL_BACK: - if (error != GRPC_ERROR_NONE) { - GPR_ASSERT(!due_to_completion); - GRPC_ERROR_UNREF(w->error); - GRPC_ERROR_REF(error); - w->error = error; - } - w->phase = CALLING_BACK_AND_FINISHED; - grpc_cq_end_op(exec_ctx, w->cq, w->tag, w->error, finished_completion, w, - &w->completion_storage); - break; - case CALLING_BACK_AND_FINISHED: - GPR_UNREACHABLE_CODE(return ); - break; - } - gpr_mu_unlock(&w->mu); - - GRPC_ERROR_UNREF(error); -} - -static void watch_complete(grpc_exec_ctx *exec_ctx, void *pw, - grpc_error *error) { - partly_done(exec_ctx, (state_watcher *)pw, true, GRPC_ERROR_REF(error)); -} - -static void timeout_complete(grpc_exec_ctx *exec_ctx, void *pw, - grpc_error *error) { - partly_done(exec_ctx, (state_watcher *)pw, false, GRPC_ERROR_REF(error)); -} - int grpc_channel_num_external_connectivity_watchers(grpc_channel *channel) { grpc_channel_element *client_channel_elem = grpc_channel_stack_last_element(grpc_channel_get_channel_stack(channel)); @@ -202,10 +83,10 @@ int grpc_channel_support_connectivity_watcher(grpc_channel *channel) { void grpc_channel_watch_connectivity_state( grpc_channel *channel, grpc_connectivity_state last_observed_state, gpr_timespec deadline, grpc_completion_queue *cq, void *tag) { + grpc_channel_stack *channel_stack = grpc_channel_get_channel_stack(channel); grpc_channel_element *client_channel_elem = - grpc_channel_stack_last_element(grpc_channel_get_channel_stack(channel)); + grpc_channel_stack_last_element(channel_stack); grpc_exec_ctx exec_ctx = GRPC_EXEC_CTX_INIT; - state_watcher *w = (state_watcher *)gpr_malloc(sizeof(*w)); GRPC_API_TRACE( "grpc_channel_watch_connectivity_state(" @@ -213,39 +94,11 @@ void grpc_channel_watch_connectivity_state( "deadline=gpr_timespec { tv_sec: %" PRId64 ", tv_nsec: %d, clock_type: %d }, " "cq=%p, tag=%p)", - 7, (channel, (int)last_observed_state, deadline.tv_sec, deadline.tv_nsec, - (int)deadline.clock_type, cq, tag)); - - GPR_ASSERT(grpc_cq_begin_op(cq, tag)); - - gpr_mu_init(&w->mu); - GRPC_CLOSURE_INIT(&w->on_complete, watch_complete, w, - grpc_schedule_on_exec_ctx); - GRPC_CLOSURE_INIT(&w->on_timeout, timeout_complete, w, - grpc_schedule_on_exec_ctx); - w->phase = WAITING; - w->state = last_observed_state; - w->cq = cq; - w->tag = tag; - w->channel = channel; - w->error = NULL; - - watcher_timer_init_arg *wa = - (watcher_timer_init_arg *)gpr_malloc(sizeof(watcher_timer_init_arg)); - wa->w = w; - wa->deadline = deadline; - GRPC_CLOSURE_INIT(&w->watcher_timer_init, watcher_timer_init, wa, - grpc_schedule_on_exec_ctx); - - if (client_channel_elem->filter == &grpc_client_channel_filter) { - GRPC_CHANNEL_INTERNAL_REF(channel, "watch_channel_connectivity"); - grpc_client_channel_watch_connectivity_state( - &exec_ctx, client_channel_elem, - grpc_polling_entity_create_from_pollset(grpc_cq_pollset(cq)), &w->state, - &w->on_complete, &w->watcher_timer_init); - } else { - abort(); - } - + 7, + (channel, (int)last_observed_state, deadline.tv_sec, deadline.tv_nsec, + (int)deadline.clock_type, cq, tag)); + grpc_channel_watch_connectivity_state_internal( + &exec_ctx, client_channel_elem, channel_stack, last_observed_state, + deadline, cq, tag); grpc_exec_ctx_finish(&exec_ctx); } diff --git a/src/core/ext/filters/client_channel/channel_connectivity_internal.cc b/src/core/ext/filters/client_channel/channel_connectivity_internal.cc new file mode 100644 index 00000000000..06bcfe2ffbf --- /dev/null +++ b/src/core/ext/filters/client_channel/channel_connectivity_internal.cc @@ -0,0 +1,195 @@ +/* + * + * 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 "src/core/ext/filters/client_channel/channel_connectivity_internal.h" + +#include +#include + +#include "src/core/ext/filters/client_channel/client_channel.h" +#include "src/core/lib/iomgr/timer.h" +#include "src/core/lib/surface/api_trace.h" +#include "src/core/lib/surface/completion_queue.h" + +typedef enum { + WAITING, + READY_TO_CALL_BACK, + CALLING_BACK_AND_FINISHED, +} callback_phase; + +typedef struct { + gpr_mu mu; + callback_phase phase; + grpc_closure on_complete; + grpc_closure on_timeout; + grpc_closure watcher_timer_init; + grpc_timer alarm; + grpc_connectivity_state state; + grpc_completion_queue *cq; + grpc_cq_completion completion_storage; + grpc_channel_element *client_channel_elem; + grpc_channel_stack *channel_stack; + grpc_error *error; + void *tag; +} state_watcher; + +static void delete_state_watcher(grpc_exec_ctx *exec_ctx, state_watcher *w) { + GRPC_CHANNEL_STACK_UNREF(exec_ctx, w->channel_stack, + "watch_channel_connectivity"); + gpr_mu_destroy(&w->mu); + gpr_free(w); +} + +static void finished_completion(grpc_exec_ctx *exec_ctx, void *pw, + grpc_cq_completion *ignored) { + bool should_delete = false; + state_watcher *w = (state_watcher *)pw; + gpr_mu_lock(&w->mu); + switch (w->phase) { + case WAITING: + case READY_TO_CALL_BACK: + GPR_UNREACHABLE_CODE(return ); + case CALLING_BACK_AND_FINISHED: + should_delete = true; + break; + } + gpr_mu_unlock(&w->mu); + + if (should_delete) { + delete_state_watcher(exec_ctx, w); + } +} + +static void partly_done(grpc_exec_ctx *exec_ctx, state_watcher *w, + bool due_to_completion, grpc_error *error) { + if (due_to_completion) { + grpc_timer_cancel(exec_ctx, &w->alarm); + } else { + grpc_channel_element *client_channel_elem = w->client_channel_elem; + grpc_client_channel_watch_connectivity_state( + exec_ctx, client_channel_elem, + grpc_polling_entity_create_from_pollset(grpc_cq_pollset(w->cq)), NULL, + &w->on_complete, NULL); + } + + gpr_mu_lock(&w->mu); + + if (due_to_completion) { + if (GRPC_TRACER_ON(grpc_trace_operation_failures)) { + GRPC_LOG_IF_ERROR("watch_completion_error", GRPC_ERROR_REF(error)); + } + GRPC_ERROR_UNREF(error); + error = GRPC_ERROR_NONE; + } else { + if (error == GRPC_ERROR_NONE) { + error = GRPC_ERROR_CREATE_FROM_STATIC_STRING( + "Timed out waiting for connection state change"); + } else if (error == GRPC_ERROR_CANCELLED) { + error = GRPC_ERROR_NONE; + } + } + switch (w->phase) { + case WAITING: + GRPC_ERROR_REF(error); + w->error = error; + w->phase = READY_TO_CALL_BACK; + break; + case READY_TO_CALL_BACK: + if (error != GRPC_ERROR_NONE) { + GPR_ASSERT(!due_to_completion); + GRPC_ERROR_UNREF(w->error); + GRPC_ERROR_REF(error); + w->error = error; + } + w->phase = CALLING_BACK_AND_FINISHED; + grpc_cq_end_op(exec_ctx, w->cq, w->tag, w->error, finished_completion, w, + &w->completion_storage); + break; + case CALLING_BACK_AND_FINISHED: + GPR_UNREACHABLE_CODE(return ); + break; + } + gpr_mu_unlock(&w->mu); + + GRPC_ERROR_UNREF(error); +} + +static void watch_complete(grpc_exec_ctx *exec_ctx, void *pw, + grpc_error *error) { + partly_done(exec_ctx, (state_watcher *)pw, true, GRPC_ERROR_REF(error)); +} + +static void timeout_complete(grpc_exec_ctx *exec_ctx, void *pw, + grpc_error *error) { + partly_done(exec_ctx, (state_watcher *)pw, false, GRPC_ERROR_REF(error)); +} + +typedef struct watcher_timer_init_arg { + state_watcher *w; + gpr_timespec deadline; +} watcher_timer_init_arg; + +static void watcher_timer_init(grpc_exec_ctx *exec_ctx, void *arg, + grpc_error *error_ignored) { + watcher_timer_init_arg *wa = (watcher_timer_init_arg *)arg; + + grpc_timer_init(exec_ctx, &wa->w->alarm, + gpr_convert_clock_type(wa->deadline, GPR_CLOCK_MONOTONIC), + &wa->w->on_timeout, gpr_now(GPR_CLOCK_MONOTONIC)); + gpr_free(wa); +} + +void grpc_channel_watch_connectivity_state_internal( + grpc_exec_ctx *exec_ctx, grpc_channel_element *client_channel_elem, + grpc_channel_stack *channel_stack, + grpc_connectivity_state last_observed_state, gpr_timespec deadline, + grpc_completion_queue *cq, void *tag) { + state_watcher *w = (state_watcher *)gpr_malloc(sizeof(*w)); + + GPR_ASSERT(grpc_cq_begin_op(cq, tag)); + + gpr_mu_init(&w->mu); + GRPC_CLOSURE_INIT(&w->on_complete, watch_complete, w, + grpc_schedule_on_exec_ctx); + GRPC_CLOSURE_INIT(&w->on_timeout, timeout_complete, w, + grpc_schedule_on_exec_ctx); + w->phase = WAITING; + w->state = last_observed_state; + w->cq = cq; + w->tag = tag; + w->client_channel_elem = client_channel_elem; + w->channel_stack = channel_stack; + w->error = NULL; + + watcher_timer_init_arg *wa = + (watcher_timer_init_arg *)gpr_malloc(sizeof(watcher_timer_init_arg)); + wa->w = w; + wa->deadline = deadline; + GRPC_CLOSURE_INIT(&w->watcher_timer_init, watcher_timer_init, wa, + grpc_schedule_on_exec_ctx); + + if (client_channel_elem->filter == &grpc_client_channel_filter) { + GRPC_CHANNEL_STACK_REF(channel_stack, "watch_channel_connectivity"); + grpc_client_channel_watch_connectivity_state( + exec_ctx, client_channel_elem, + grpc_polling_entity_create_from_pollset(grpc_cq_pollset(cq)), &w->state, + &w->on_complete, &w->watcher_timer_init); + } else { + abort(); + } +} diff --git a/src/core/ext/filters/client_channel/channel_connectivity_internal.h b/src/core/ext/filters/client_channel/channel_connectivity_internal.h new file mode 100644 index 00000000000..d260a20c07b --- /dev/null +++ b/src/core/ext/filters/client_channel/channel_connectivity_internal.h @@ -0,0 +1,33 @@ +/* + * + * 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_CHANNEL_CONNECTIVITY_INTERNAL_H +#define GRPC_CORE_EXT_FILTERS_CLIENT_CHANNEL_CHANNEL_CONNECTIVITY_INTERNAL_H + +#include +#include "src/core/lib/channel/channel_stack.h" +#include "src/core/lib/iomgr/exec_ctx.h" + +void grpc_channel_watch_connectivity_state_internal( + grpc_exec_ctx *exec_ctx, grpc_channel_element *client_channel_elem, + grpc_channel_stack *channel_stack, + grpc_connectivity_state last_observed_state, gpr_timespec deadline, + grpc_completion_queue *cq, void *tag); + +#endif /* GRPC_CORE_EXT_FILTERS_CLIENT_CHANNEL_CHANNEL_CONNECTIVITY_INTERNAL_H \ + */ diff --git a/src/core/ext/filters/client_channel/client_channel.cc b/src/core/ext/filters/client_channel/client_channel.cc index ea5e076c3be..be8ea81a020 100644 --- a/src/core/ext/filters/client_channel/client_channel.cc +++ b/src/core/ext/filters/client_channel/client_channel.cc @@ -31,6 +31,7 @@ #include #include +#include "src/core/ext/filters/client_channel/connectivity_watcher.h" #include "src/core/ext/filters/client_channel/http_connect_handshaker.h" #include "src/core/ext/filters/client_channel/lb_policy_registry.h" #include "src/core/ext/filters/client_channel/proxy_mapper_registry.h" @@ -753,6 +754,8 @@ static grpc_error *cc_init_channel_elem(grpc_exec_ctx *exec_ctx, } chand->deadline_checking_enabled = grpc_deadline_checking_enabled(args->channel_args); + grpc_client_channel_start_watching_connectivity(exec_ctx, elem, + chand->owning_stack); return GRPC_ERROR_NONE; } diff --git a/src/core/ext/filters/client_channel/connectivity_watcher.c b/src/core/ext/filters/client_channel/connectivity_watcher.c new file mode 100644 index 00000000000..da45929f269 --- /dev/null +++ b/src/core/ext/filters/client_channel/connectivity_watcher.c @@ -0,0 +1,179 @@ +/* + * + * 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 "src/core/ext/filters/client_channel/connectivity_watcher.h" + +#include +#include +#include +#include +#include "src/core/ext/filters/client_channel/channel_connectivity_internal.h" +#include "src/core/ext/filters/client_channel/client_channel.h" +#include "src/core/lib/iomgr/timer.h" +#include "src/core/lib/support/env.h" +#include "src/core/lib/support/string.h" +#include "src/core/lib/surface/channel.h" +#include "src/core/lib/surface/completion_queue.h" + +#define DEFAULT_CONNECTIVITY_CHECK_INTERVAL_MS 500 + +typedef struct connectivity_watcher { + grpc_timer watcher_timer; + grpc_closure check_connectivity_closure; + grpc_completion_queue* cq; + gpr_refcount refs; + size_t channel_count; + bool shutting_down; +} connectivity_watcher; + +typedef struct channel_state { + grpc_channel_element* client_channel_elem; + grpc_channel_stack* channel_stack; + grpc_connectivity_state state; +} channel_state; + +static gpr_once g_once = GPR_ONCE_INIT; +static gpr_mu g_watcher_mu; +static connectivity_watcher* g_watcher = NULL; + +static void init_g_watcher_mu() { gpr_mu_init(&g_watcher_mu); } + +static void start_watching_locked(grpc_exec_ctx* exec_ctx, + grpc_channel_element* client_channel_elem, + grpc_channel_stack* channel_stack) { + gpr_ref(&g_watcher->refs); + ++g_watcher->channel_count; + channel_state* s = (channel_state*)gpr_zalloc(sizeof(channel_state)); + s->client_channel_elem = client_channel_elem; + s->channel_stack = channel_stack; + s->state = GRPC_CHANNEL_IDLE; + grpc_channel_watch_connectivity_state_internal( + exec_ctx, client_channel_elem, channel_stack, s->state, + gpr_inf_future(GPR_CLOCK_MONOTONIC), g_watcher->cq, (void*)s); +} + +static bool is_disabled() { + char* env = gpr_getenv("GRPC_DISABLE_CHANNEL_CONNECTIVITY_WATCHER"); + bool disabled = gpr_is_true(env); + gpr_free(env); + return disabled; +} + +static bool connectivity_watcher_unref(grpc_exec_ctx* exec_ctx) { + if (gpr_unref(&g_watcher->refs)) { + gpr_mu_lock(&g_watcher_mu); + grpc_completion_queue_destroy(g_watcher->cq); + gpr_free(g_watcher); + g_watcher = NULL; + gpr_mu_unlock(&g_watcher_mu); + return true; + } + return false; +} + +static void check_connectivity_state(grpc_exec_ctx* exec_ctx, void* ignored, + grpc_error* error) { + grpc_event ev; + while (true) { + gpr_mu_lock(&g_watcher_mu); + if (g_watcher->shutting_down) { + // Drain cq if the watcher is shutting down + ev = grpc_completion_queue_next( + g_watcher->cq, gpr_inf_future(GPR_CLOCK_MONOTONIC), NULL); + } else { + ev = grpc_completion_queue_next(g_watcher->cq, + gpr_inf_past(GPR_CLOCK_MONOTONIC), NULL); + // Make sure we've seen 2 TIMEOUTs before going to sleep + if (ev.type == GRPC_QUEUE_TIMEOUT) { + ev = grpc_completion_queue_next( + g_watcher->cq, gpr_inf_past(GPR_CLOCK_MONOTONIC), NULL); + if (ev.type == GRPC_QUEUE_TIMEOUT) { + gpr_timespec now = gpr_now(GPR_CLOCK_MONOTONIC); + grpc_timer_init( + exec_ctx, &g_watcher->watcher_timer, + gpr_time_add(now, gpr_time_from_millis( + DEFAULT_CONNECTIVITY_CHECK_INTERVAL_MS, + GPR_TIMESPAN)), + &g_watcher->check_connectivity_closure, now); + gpr_mu_unlock(&g_watcher_mu); + break; + } + } + } + gpr_mu_unlock(&g_watcher_mu); + if (ev.type != GRPC_OP_COMPLETE) { + break; + } + channel_state* s = (channel_state*)(ev.tag); + s->state = grpc_client_channel_check_connectivity_state( + exec_ctx, s->client_channel_elem, false /* try_to_connect */); + if (s->state == GRPC_CHANNEL_SHUTDOWN) { + GRPC_CHANNEL_STACK_UNREF(exec_ctx, s->channel_stack, + "connectivity_watcher_stop_watching"); + gpr_free(s); + if (connectivity_watcher_unref(exec_ctx)) { + break; + } + } else { + grpc_channel_watch_connectivity_state_internal( + exec_ctx, s->client_channel_elem, s->channel_stack, s->state, + gpr_inf_future(GPR_CLOCK_MONOTONIC), g_watcher->cq, s); + } + } +} + +void grpc_client_channel_start_watching_connectivity( + grpc_exec_ctx* exec_ctx, grpc_channel_element* client_channel_elem, + grpc_channel_stack* channel_stack) { + if (is_disabled()) return; + GRPC_CHANNEL_STACK_REF(channel_stack, "connectivity_watcher_start_watching"); + gpr_once_init(&g_once, init_g_watcher_mu); + gpr_mu_lock(&g_watcher_mu); + if (g_watcher == NULL) { + g_watcher = (connectivity_watcher*)gpr_zalloc(sizeof(connectivity_watcher)); + g_watcher->cq = grpc_completion_queue_create_internal( + GRPC_CQ_NEXT, GRPC_CQ_DEFAULT_POLLING); + gpr_ref_init(&g_watcher->refs, 0); + GRPC_CLOSURE_INIT(&g_watcher->check_connectivity_closure, + check_connectivity_state, NULL, + grpc_schedule_on_exec_ctx); + gpr_timespec now = gpr_now(GPR_CLOCK_MONOTONIC); + grpc_timer_init( + exec_ctx, &g_watcher->watcher_timer, + gpr_time_add( + now, gpr_time_from_millis(DEFAULT_CONNECTIVITY_CHECK_INTERVAL_MS, + GPR_TIMESPAN)), + &g_watcher->check_connectivity_closure, now); + } + start_watching_locked(exec_ctx, client_channel_elem, channel_stack); + gpr_mu_init(&g_watcher_mu); +} + +void grpc_client_channel_stop_watching_connectivity( + grpc_exec_ctx* exec_ctx, grpc_channel_element* client_channel_elem, + grpc_channel_stack* channel_stack) { + if (is_disabled()) return; + gpr_once_init(&g_once, init_g_watcher_mu); + gpr_mu_lock(&g_watcher_mu); + if (--g_watcher->channel_count == 0) { + g_watcher->shutting_down = true; + grpc_timer_cancel(exec_ctx, &g_watcher->watcher_timer); + connectivity_watcher_unref(exec_ctx); + } + gpr_mu_unlock(&g_watcher_mu); +} diff --git a/src/core/ext/filters/client_channel/connectivity_watcher.h b/src/core/ext/filters/client_channel/connectivity_watcher.h new file mode 100644 index 00000000000..89586dc7368 --- /dev/null +++ b/src/core/ext/filters/client_channel/connectivity_watcher.h @@ -0,0 +1,30 @@ +/* + * + * 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_CONNECTIVITY_WATCHER_H +#define GRPC_CORE_EXT_FILTERS_CLIENT_CHANNEL_CONNECTIVITY_WATCHER_H + +#include +#include "src/core/lib/channel/channel_stack.h" +#include "src/core/lib/iomgr/exec_ctx.h" + +void grpc_client_channel_start_watching_connectivity( + grpc_exec_ctx* exec_ctx, grpc_channel_element* client_channel_elem, + grpc_channel_stack* channel_stack); + +#endif /* GRPC_CORE_EXT_FILTERS_CLIENT_CHANNEL_CONNECTIVITY_WATCHER_H */ diff --git a/src/python/grpcio/grpc_core_dependencies.py b/src/python/grpcio/grpc_core_dependencies.py index 140f4ceee12..467b13f22b4 100644 --- a/src/python/grpcio/grpc_core_dependencies.py +++ b/src/python/grpcio/grpc_core_dependencies.py @@ -258,6 +258,7 @@ CORE_SOURCE_FILES = [ 'src/core/ext/filters/client_channel/client_channel.cc', 'src/core/ext/filters/client_channel/client_channel_factory.cc', 'src/core/ext/filters/client_channel/client_channel_plugin.cc', + 'src/core/ext/filters/client_channel/connectivity_watcher.c', 'src/core/ext/filters/client_channel/connector.cc', 'src/core/ext/filters/client_channel/http_connect_handshaker.cc', 'src/core/ext/filters/client_channel/http_proxy.cc', diff --git a/tools/doxygen/Doxyfile.core.internal b/tools/doxygen/Doxyfile.core.internal index e0536423fae..bed3845db29 100644 --- a/tools/doxygen/Doxyfile.core.internal +++ b/tools/doxygen/Doxyfile.core.internal @@ -908,11 +908,14 @@ src/core/ext/census/tracing.cc \ src/core/ext/census/tracing.h \ src/core/ext/filters/client_channel/README.md \ src/core/ext/filters/client_channel/channel_connectivity.cc \ +src/core/ext/filters/client_channel/channel_connectivity_internal.h \ src/core/ext/filters/client_channel/client_channel.cc \ src/core/ext/filters/client_channel/client_channel.h \ src/core/ext/filters/client_channel/client_channel_factory.cc \ src/core/ext/filters/client_channel/client_channel_factory.h \ src/core/ext/filters/client_channel/client_channel_plugin.cc \ +src/core/ext/filters/client_channel/connectivity_watcher.c \ +src/core/ext/filters/client_channel/connectivity_watcher.h \ src/core/ext/filters/client_channel/connector.cc \ src/core/ext/filters/client_channel/connector.h \ src/core/ext/filters/client_channel/http_connect_handshaker.cc \ diff --git a/tools/run_tests/generated/sources_and_headers.json b/tools/run_tests/generated/sources_and_headers.json index 08ab2a5d931..af7b7ee9a0c 100644 --- a/tools/run_tests/generated/sources_and_headers.json +++ b/tools/run_tests/generated/sources_and_headers.json @@ -8467,8 +8467,10 @@ "grpc_deadline_filter" ], "headers": [ + "src/core/ext/filters/client_channel/channel_connectivity_internal.h", "src/core/ext/filters/client_channel/client_channel.h", "src/core/ext/filters/client_channel/client_channel_factory.h", + "src/core/ext/filters/client_channel/connectivity_watcher.h", "src/core/ext/filters/client_channel/connector.h", "src/core/ext/filters/client_channel/http_connect_handshaker.h", "src/core/ext/filters/client_channel/http_proxy.h", @@ -8491,11 +8493,14 @@ "name": "grpc_client_channel", "src": [ "src/core/ext/filters/client_channel/channel_connectivity.cc", + "src/core/ext/filters/client_channel/channel_connectivity_internal.h", "src/core/ext/filters/client_channel/client_channel.cc", "src/core/ext/filters/client_channel/client_channel.h", "src/core/ext/filters/client_channel/client_channel_factory.cc", "src/core/ext/filters/client_channel/client_channel_factory.h", "src/core/ext/filters/client_channel/client_channel_plugin.cc", + "src/core/ext/filters/client_channel/connectivity_watcher.c", + "src/core/ext/filters/client_channel/connectivity_watcher.h", "src/core/ext/filters/client_channel/connector.cc", "src/core/ext/filters/client_channel/connector.h", "src/core/ext/filters/client_channel/http_connect_handshaker.cc", From 6a48dc544e4db970b19cf132019bcccb8eb92df1 Mon Sep 17 00:00:00 2001 From: Yuchen Zeng Date: Tue, 26 Sep 2017 19:49:23 -0700 Subject: [PATCH 32/47] Remove c++ channel connectivity watcher --- .../client_channel/connectivity_watcher.h | 2 + src/cpp/client/channel_cc.cc | 194 ++---------------- 2 files changed, 21 insertions(+), 175 deletions(-) diff --git a/src/core/ext/filters/client_channel/connectivity_watcher.h b/src/core/ext/filters/client_channel/connectivity_watcher.h index 89586dc7368..e12d6c284a1 100644 --- a/src/core/ext/filters/client_channel/connectivity_watcher.h +++ b/src/core/ext/filters/client_channel/connectivity_watcher.h @@ -23,6 +23,8 @@ #include "src/core/lib/channel/channel_stack.h" #include "src/core/lib/iomgr/exec_ctx.h" +/* Constantly watches client channel connectivity status to reconnect a + * transiently disconnected channel */ void grpc_client_channel_start_watching_connectivity( grpc_exec_ctx* exec_ctx, grpc_channel_element* client_channel_elem, grpc_channel_stack* channel_stack); diff --git a/src/cpp/client/channel_cc.cc b/src/cpp/client/channel_cc.cc index 4049fc846b9..1509a92d268 100644 --- a/src/cpp/client/channel_cc.cc +++ b/src/cpp/client/channel_cc.cc @@ -48,187 +48,13 @@ namespace grpc { -namespace { -int kConnectivityCheckIntervalMsec = 500; -void WatchStateChange(void* arg); - -class TagSaver final : public internal::CompletionQueueTag { - public: - explicit TagSaver(void* tag) : tag_(tag) {} - ~TagSaver() override {} - bool FinalizeResult(void** tag, bool* status) override { - *tag = tag_; - delete this; - return true; - } - - private: - void* tag_; -}; - -// Constantly watches channel connectivity status to reconnect a transiently -// disconnected channel. This is a temporary work-around before we have retry -// support. -class ChannelConnectivityWatcher : private GrpcLibraryCodegen { - public: - static void StartWatching(grpc_channel* channel) { - if (!IsDisabled()) { - std::unique_lock lock(g_watcher_mu_); - if (g_watcher_ == nullptr) { - g_watcher_ = new ChannelConnectivityWatcher(); - } - g_watcher_->StartWatchingLocked(channel); - } - } - - static void StopWatching() { - if (!IsDisabled()) { - std::unique_lock lock(g_watcher_mu_); - if (g_watcher_->StopWatchingLocked()) { - delete g_watcher_; - g_watcher_ = nullptr; - } - } - } - - private: - ChannelConnectivityWatcher() : channel_count_(0), shutdown_(false) { - gpr_ref_init(&ref_, 0); - gpr_thd_options options = gpr_thd_options_default(); - gpr_thd_options_set_joinable(&options); - gpr_thd_new(&thd_id_, &WatchStateChange, this, &options); - } - - static bool IsDisabled() { - char* env = gpr_getenv("GRPC_DISABLE_CHANNEL_CONNECTIVITY_WATCHER"); - bool disabled = gpr_is_true(env); - gpr_free(env); - return disabled; - } - - void WatchStateChangeImpl() { - bool ok = false; - void* tag = NULL; - CompletionQueue::NextStatus status = CompletionQueue::GOT_EVENT; - while (true) { - { - std::unique_lock lock(shutdown_mu_); - if (shutdown_) { - // Drain cq_ if the watcher is shutting down - status = cq_.AsyncNext(&tag, &ok, gpr_inf_future(GPR_CLOCK_REALTIME)); - } else { - status = cq_.AsyncNext(&tag, &ok, gpr_inf_past(GPR_CLOCK_REALTIME)); - // Make sure we've seen 2 TIMEOUTs before going to sleep - if (status == CompletionQueue::TIMEOUT) { - status = cq_.AsyncNext(&tag, &ok, gpr_inf_past(GPR_CLOCK_REALTIME)); - if (status == CompletionQueue::TIMEOUT) { - shutdown_cv_.wait_for(lock, std::chrono::milliseconds( - kConnectivityCheckIntervalMsec)); - continue; - } - } - } - } - ChannelState* channel_state = static_cast(tag); - channel_state->state = - grpc_channel_check_connectivity_state(channel_state->channel, false); - if (channel_state->state == GRPC_CHANNEL_SHUTDOWN) { - void* shutdown_tag = NULL; - channel_state->shutdown_cq.Next(&shutdown_tag, &ok); - delete channel_state; - if (gpr_unref(&ref_)) { - break; - } - } else { - TagSaver* tag_saver = new TagSaver(channel_state); - grpc_channel_watch_connectivity_state( - channel_state->channel, channel_state->state, - gpr_inf_future(GPR_CLOCK_REALTIME), cq_.cq(), tag_saver); - } - } - } - - void StartWatchingLocked(grpc_channel* channel) { - if (thd_id_ != 0) { - gpr_ref(&ref_); - ++channel_count_; - ChannelState* channel_state = new ChannelState(channel); - // The first grpc_channel_watch_connectivity_state() is not used to - // monitor the channel state change, but to hold a reference of the - // c channel. So that WatchStateChangeImpl() can observe state == - // GRPC_CHANNEL_SHUTDOWN before the channel gets destroyed. - grpc_channel_watch_connectivity_state( - channel_state->channel, channel_state->state, - gpr_inf_future(GPR_CLOCK_REALTIME), channel_state->shutdown_cq.cq(), - new TagSaver(nullptr)); - grpc_channel_watch_connectivity_state( - channel_state->channel, channel_state->state, - gpr_inf_future(GPR_CLOCK_REALTIME), cq_.cq(), - new TagSaver(channel_state)); - } - } - - bool StopWatchingLocked() { - if (--channel_count_ == 0) { - { - std::unique_lock lock(shutdown_mu_); - shutdown_ = true; - shutdown_cv_.notify_one(); - } - gpr_thd_join(thd_id_); - return true; - } - return false; - } - - friend void WatchStateChange(void* arg); - struct ChannelState { - explicit ChannelState(grpc_channel* channel) - : channel(channel), state(GRPC_CHANNEL_IDLE){}; - grpc_channel* channel; - grpc_connectivity_state state; - CompletionQueue shutdown_cq; - }; - gpr_thd_id thd_id_; - CompletionQueue cq_; - gpr_refcount ref_; - int channel_count_; - - std::mutex shutdown_mu_; - std::condition_variable shutdown_cv_; // protected by shutdown_mu_ - bool shutdown_; // protected by shutdown_mu_ - - static std::mutex g_watcher_mu_; - static ChannelConnectivityWatcher* g_watcher_; // protected by g_watcher_mu_ -}; - -std::mutex ChannelConnectivityWatcher::g_watcher_mu_; -ChannelConnectivityWatcher* ChannelConnectivityWatcher::g_watcher_ = nullptr; - -void WatchStateChange(void* arg) { - ChannelConnectivityWatcher* watcher = - static_cast(arg); - watcher->WatchStateChangeImpl(); -} -} // namespace - static internal::GrpcLibraryInitializer g_gli_initializer; Channel::Channel(const grpc::string& host, grpc_channel* channel) : host_(host), c_channel_(channel) { g_gli_initializer.summon(); - if (grpc_channel_support_connectivity_watcher(channel)) { - ChannelConnectivityWatcher::StartWatching(channel); - } } -Channel::~Channel() { - const bool stop_watching = - grpc_channel_support_connectivity_watcher(c_channel_); - grpc_channel_destroy(c_channel_); - if (stop_watching) { - ChannelConnectivityWatcher::StopWatching(); - } -} +Channel::~Channel() { grpc_channel_destroy(c_channel_); } namespace { @@ -315,6 +141,24 @@ grpc_connectivity_state Channel::GetState(bool try_to_connect) { return grpc_channel_check_connectivity_state(c_channel_, try_to_connect); } +namespace { + +class TagSaver final : public CompletionQueueTag { + public: + explicit TagSaver(void* tag) : tag_(tag) {} + ~TagSaver() override {} + bool FinalizeResult(void** tag, bool* status) override { + *tag = tag_; + delete this; + return true; + } + + private: + void* tag_; +}; + +} // namespace + void Channel::NotifyOnStateChangeImpl(grpc_connectivity_state last_observed, gpr_timespec deadline, CompletionQueue* cq, void* tag) { From f8ed4fa7f4b516d98daeefb0459ce1b175baa7e3 Mon Sep 17 00:00:00 2001 From: Yuchen Zeng Date: Thu, 5 Oct 2017 13:15:49 -0700 Subject: [PATCH 33/47] convert connectivity_watcher to cpp file --- BUILD | 1 + CMakeLists.txt | 18 ++++++++++++------ Makefile | 18 ++++++++++++------ binding.gyp | 3 ++- build.yaml | 4 ++++ config.m4 | 3 ++- config.w32 | 3 ++- gRPC-Core.podspec | 3 ++- grpc.gemspec | 3 ++- grpc.gyp | 12 ++++++++---- package.xml | 3 ++- ...ivity_watcher.c => connectivity_watcher.cc} | 0 src/python/grpcio/grpc_core_dependencies.py | 3 ++- tools/doxygen/Doxyfile.core.internal | 3 ++- .../generated/sources_and_headers.json | 3 ++- 15 files changed, 55 insertions(+), 25 deletions(-) rename src/core/ext/filters/client_channel/{connectivity_watcher.c => connectivity_watcher.cc} (100%) diff --git a/BUILD b/BUILD index 4e1f61ee10d..0e59e78db45 100644 --- a/BUILD +++ b/BUILD @@ -872,6 +872,7 @@ grpc_cc_library( grpc_cc_library( name = "grpc_client_channel", srcs = [ + "src/core/ext/filters/client_channel/channel_connectivity_internal.cc", "src/core/ext/filters/client_channel/channel_connectivity.cc", "src/core/ext/filters/client_channel/client_channel.cc", "src/core/ext/filters/client_channel/client_channel_factory.cc", diff --git a/CMakeLists.txt b/CMakeLists.txt index 8122d4b0253..c00a9e04a03 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -1154,10 +1154,11 @@ add_library(grpc src/core/ext/transport/chttp2/server/chttp2_server.cc src/core/ext/transport/chttp2/client/secure/secure_channel_create.cc src/core/ext/filters/client_channel/channel_connectivity.cc + src/core/ext/filters/client_channel/channel_connectivity_internal.cc src/core/ext/filters/client_channel/client_channel.cc src/core/ext/filters/client_channel/client_channel_factory.cc src/core/ext/filters/client_channel/client_channel_plugin.cc - src/core/ext/filters/client_channel/connectivity_watcher.c + src/core/ext/filters/client_channel/connectivity_watcher.cc src/core/ext/filters/client_channel/connector.cc src/core/ext/filters/client_channel/http_connect_handshaker.cc src/core/ext/filters/client_channel/http_proxy.cc @@ -1479,10 +1480,11 @@ add_library(grpc_cronet src/core/ext/filters/http/message_compress/message_compress_filter.cc src/core/ext/filters/http/server/http_server_filter.cc src/core/ext/filters/client_channel/channel_connectivity.cc + src/core/ext/filters/client_channel/channel_connectivity_internal.cc src/core/ext/filters/client_channel/client_channel.cc src/core/ext/filters/client_channel/client_channel_factory.cc src/core/ext/filters/client_channel/client_channel_plugin.cc - src/core/ext/filters/client_channel/connectivity_watcher.c + src/core/ext/filters/client_channel/connectivity_watcher.cc src/core/ext/filters/client_channel/connector.cc src/core/ext/filters/client_channel/http_connect_handshaker.cc src/core/ext/filters/client_channel/http_proxy.cc @@ -1770,10 +1772,11 @@ add_library(grpc_test_util src/core/lib/transport/transport_op_string.cc src/core/lib/debug/trace.cc src/core/ext/filters/client_channel/channel_connectivity.cc + src/core/ext/filters/client_channel/channel_connectivity_internal.cc src/core/ext/filters/client_channel/client_channel.cc src/core/ext/filters/client_channel/client_channel_factory.cc src/core/ext/filters/client_channel/client_channel_plugin.cc - src/core/ext/filters/client_channel/connectivity_watcher.c + src/core/ext/filters/client_channel/connectivity_watcher.cc src/core/ext/filters/client_channel/connector.cc src/core/ext/filters/client_channel/http_connect_handshaker.cc src/core/ext/filters/client_channel/http_proxy.cc @@ -2036,10 +2039,11 @@ add_library(grpc_test_util_unsecure src/core/lib/transport/transport_op_string.cc src/core/lib/debug/trace.cc src/core/ext/filters/client_channel/channel_connectivity.cc + src/core/ext/filters/client_channel/channel_connectivity_internal.cc src/core/ext/filters/client_channel/client_channel.cc src/core/ext/filters/client_channel/client_channel_factory.cc src/core/ext/filters/client_channel/client_channel_plugin.cc - src/core/ext/filters/client_channel/connectivity_watcher.c + src/core/ext/filters/client_channel/connectivity_watcher.cc src/core/ext/filters/client_channel/connector.cc src/core/ext/filters/client_channel/http_connect_handshaker.cc src/core/ext/filters/client_channel/http_proxy.cc @@ -2321,10 +2325,11 @@ add_library(grpc_unsecure src/core/ext/transport/chttp2/client/insecure/channel_create_posix.cc src/core/ext/transport/chttp2/client/chttp2_connector.cc src/core/ext/filters/client_channel/channel_connectivity.cc + src/core/ext/filters/client_channel/channel_connectivity_internal.cc src/core/ext/filters/client_channel/client_channel.cc src/core/ext/filters/client_channel/client_channel_factory.cc src/core/ext/filters/client_channel/client_channel_plugin.cc - src/core/ext/filters/client_channel/connectivity_watcher.c + src/core/ext/filters/client_channel/connectivity_watcher.cc src/core/ext/filters/client_channel/connector.cc src/core/ext/filters/client_channel/http_connect_handshaker.cc src/core/ext/filters/client_channel/http_proxy.cc @@ -3057,10 +3062,11 @@ add_library(grpc++_cronet src/core/ext/filters/http/message_compress/message_compress_filter.cc src/core/ext/filters/http/server/http_server_filter.cc src/core/ext/filters/client_channel/channel_connectivity.cc + src/core/ext/filters/client_channel/channel_connectivity_internal.cc src/core/ext/filters/client_channel/client_channel.cc src/core/ext/filters/client_channel/client_channel_factory.cc src/core/ext/filters/client_channel/client_channel_plugin.cc - src/core/ext/filters/client_channel/connectivity_watcher.c + src/core/ext/filters/client_channel/connectivity_watcher.cc src/core/ext/filters/client_channel/connector.cc src/core/ext/filters/client_channel/http_connect_handshaker.cc src/core/ext/filters/client_channel/http_proxy.cc diff --git a/Makefile b/Makefile index 3ff9b39f456..bda3c3fce4c 100644 --- a/Makefile +++ b/Makefile @@ -3154,10 +3154,11 @@ LIBGRPC_SRC = \ src/core/ext/transport/chttp2/server/chttp2_server.cc \ src/core/ext/transport/chttp2/client/secure/secure_channel_create.cc \ src/core/ext/filters/client_channel/channel_connectivity.cc \ + src/core/ext/filters/client_channel/channel_connectivity_internal.cc \ src/core/ext/filters/client_channel/client_channel.cc \ src/core/ext/filters/client_channel/client_channel_factory.cc \ src/core/ext/filters/client_channel/client_channel_plugin.cc \ - src/core/ext/filters/client_channel/connectivity_watcher.c \ + src/core/ext/filters/client_channel/connectivity_watcher.cc \ src/core/ext/filters/client_channel/connector.cc \ src/core/ext/filters/client_channel/http_connect_handshaker.cc \ src/core/ext/filters/client_channel/http_proxy.cc \ @@ -3478,10 +3479,11 @@ LIBGRPC_CRONET_SRC = \ src/core/ext/filters/http/message_compress/message_compress_filter.cc \ src/core/ext/filters/http/server/http_server_filter.cc \ src/core/ext/filters/client_channel/channel_connectivity.cc \ + src/core/ext/filters/client_channel/channel_connectivity_internal.cc \ src/core/ext/filters/client_channel/client_channel.cc \ src/core/ext/filters/client_channel/client_channel_factory.cc \ src/core/ext/filters/client_channel/client_channel_plugin.cc \ - src/core/ext/filters/client_channel/connectivity_watcher.c \ + src/core/ext/filters/client_channel/connectivity_watcher.cc \ src/core/ext/filters/client_channel/connector.cc \ src/core/ext/filters/client_channel/http_connect_handshaker.cc \ src/core/ext/filters/client_channel/http_proxy.cc \ @@ -3767,10 +3769,11 @@ LIBGRPC_TEST_UTIL_SRC = \ src/core/lib/transport/transport_op_string.cc \ src/core/lib/debug/trace.cc \ src/core/ext/filters/client_channel/channel_connectivity.cc \ + src/core/ext/filters/client_channel/channel_connectivity_internal.cc \ src/core/ext/filters/client_channel/client_channel.cc \ src/core/ext/filters/client_channel/client_channel_factory.cc \ src/core/ext/filters/client_channel/client_channel_plugin.cc \ - src/core/ext/filters/client_channel/connectivity_watcher.c \ + src/core/ext/filters/client_channel/connectivity_watcher.cc \ src/core/ext/filters/client_channel/connector.cc \ src/core/ext/filters/client_channel/http_connect_handshaker.cc \ src/core/ext/filters/client_channel/http_proxy.cc \ @@ -4023,10 +4026,11 @@ LIBGRPC_TEST_UTIL_UNSECURE_SRC = \ src/core/lib/transport/transport_op_string.cc \ src/core/lib/debug/trace.cc \ src/core/ext/filters/client_channel/channel_connectivity.cc \ + src/core/ext/filters/client_channel/channel_connectivity_internal.cc \ src/core/ext/filters/client_channel/client_channel.cc \ src/core/ext/filters/client_channel/client_channel_factory.cc \ src/core/ext/filters/client_channel/client_channel_plugin.cc \ - src/core/ext/filters/client_channel/connectivity_watcher.c \ + src/core/ext/filters/client_channel/connectivity_watcher.cc \ src/core/ext/filters/client_channel/connector.cc \ src/core/ext/filters/client_channel/http_connect_handshaker.cc \ src/core/ext/filters/client_channel/http_proxy.cc \ @@ -4285,10 +4289,11 @@ LIBGRPC_UNSECURE_SRC = \ src/core/ext/transport/chttp2/client/insecure/channel_create_posix.cc \ src/core/ext/transport/chttp2/client/chttp2_connector.cc \ src/core/ext/filters/client_channel/channel_connectivity.cc \ + src/core/ext/filters/client_channel/channel_connectivity_internal.cc \ src/core/ext/filters/client_channel/client_channel.cc \ src/core/ext/filters/client_channel/client_channel_factory.cc \ src/core/ext/filters/client_channel/client_channel_plugin.cc \ - src/core/ext/filters/client_channel/connectivity_watcher.c \ + src/core/ext/filters/client_channel/connectivity_watcher.cc \ src/core/ext/filters/client_channel/connector.cc \ src/core/ext/filters/client_channel/http_connect_handshaker.cc \ src/core/ext/filters/client_channel/http_proxy.cc \ @@ -4999,10 +5004,11 @@ LIBGRPC++_CRONET_SRC = \ src/core/ext/filters/http/message_compress/message_compress_filter.cc \ src/core/ext/filters/http/server/http_server_filter.cc \ src/core/ext/filters/client_channel/channel_connectivity.cc \ + src/core/ext/filters/client_channel/channel_connectivity_internal.cc \ src/core/ext/filters/client_channel/client_channel.cc \ src/core/ext/filters/client_channel/client_channel_factory.cc \ src/core/ext/filters/client_channel/client_channel_plugin.cc \ - src/core/ext/filters/client_channel/connectivity_watcher.c \ + src/core/ext/filters/client_channel/connectivity_watcher.cc \ src/core/ext/filters/client_channel/connector.cc \ src/core/ext/filters/client_channel/http_connect_handshaker.cc \ src/core/ext/filters/client_channel/http_proxy.cc \ diff --git a/binding.gyp b/binding.gyp index 707afb476a4..ff7bf8fcdab 100644 --- a/binding.gyp +++ b/binding.gyp @@ -854,10 +854,11 @@ 'src/core/ext/transport/chttp2/server/chttp2_server.cc', 'src/core/ext/transport/chttp2/client/secure/secure_channel_create.cc', 'src/core/ext/filters/client_channel/channel_connectivity.cc', + 'src/core/ext/filters/client_channel/channel_connectivity_internal.cc', 'src/core/ext/filters/client_channel/client_channel.cc', 'src/core/ext/filters/client_channel/client_channel_factory.cc', 'src/core/ext/filters/client_channel/client_channel_plugin.cc', - 'src/core/ext/filters/client_channel/connectivity_watcher.c', + 'src/core/ext/filters/client_channel/connectivity_watcher.cc', 'src/core/ext/filters/client_channel/connector.cc', 'src/core/ext/filters/client_channel/http_connect_handshaker.cc', 'src/core/ext/filters/client_channel/http_proxy.cc', diff --git a/build.yaml b/build.yaml index 592cbb9f8c8..6308b080400 100644 --- a/build.yaml +++ b/build.yaml @@ -463,8 +463,10 @@ filegroups: - grpc_trace_headers - name: grpc_client_channel headers: + - src/core/ext/filters/client_channel/channel_connectivity_internal.h - src/core/ext/filters/client_channel/client_channel.h - src/core/ext/filters/client_channel/client_channel_factory.h + - src/core/ext/filters/client_channel/connectivity_watcher.h - src/core/ext/filters/client_channel/connector.h - src/core/ext/filters/client_channel/http_connect_handshaker.h - src/core/ext/filters/client_channel/http_proxy.h @@ -483,9 +485,11 @@ filegroups: - src/core/ext/filters/client_channel/uri_parser.h src: - src/core/ext/filters/client_channel/channel_connectivity.cc + - src/core/ext/filters/client_channel/channel_connectivity_internal.cc - src/core/ext/filters/client_channel/client_channel.cc - src/core/ext/filters/client_channel/client_channel_factory.cc - src/core/ext/filters/client_channel/client_channel_plugin.cc + - src/core/ext/filters/client_channel/connectivity_watcher.cc - src/core/ext/filters/client_channel/connector.cc - src/core/ext/filters/client_channel/http_connect_handshaker.cc - src/core/ext/filters/client_channel/http_proxy.cc diff --git a/config.m4 b/config.m4 index eaa3af978b0..ca374cec0d0 100644 --- a/config.m4 +++ b/config.m4 @@ -279,10 +279,11 @@ if test "$PHP_GRPC" != "no"; then src/core/ext/transport/chttp2/server/chttp2_server.cc \ src/core/ext/transport/chttp2/client/secure/secure_channel_create.cc \ src/core/ext/filters/client_channel/channel_connectivity.cc \ + src/core/ext/filters/client_channel/channel_connectivity_internal.cc \ src/core/ext/filters/client_channel/client_channel.cc \ src/core/ext/filters/client_channel/client_channel_factory.cc \ src/core/ext/filters/client_channel/client_channel_plugin.cc \ - src/core/ext/filters/client_channel/connectivity_watcher.c \ + src/core/ext/filters/client_channel/connectivity_watcher.cc \ src/core/ext/filters/client_channel/connector.cc \ src/core/ext/filters/client_channel/http_connect_handshaker.cc \ src/core/ext/filters/client_channel/http_proxy.cc \ diff --git a/config.w32 b/config.w32 index 75a83e24140..0db7620b30b 100644 --- a/config.w32 +++ b/config.w32 @@ -256,10 +256,11 @@ if (PHP_GRPC != "no") { "src\\core\\ext\\transport\\chttp2\\server\\chttp2_server.cc " + "src\\core\\ext\\transport\\chttp2\\client\\secure\\secure_channel_create.cc " + "src\\core\\ext\\filters\\client_channel\\channel_connectivity.cc " + + "src\\core\\ext\\filters\\client_channel\\channel_connectivity_internal.cc " + "src\\core\\ext\\filters\\client_channel\\client_channel.cc " + "src\\core\\ext\\filters\\client_channel\\client_channel_factory.cc " + "src\\core\\ext\\filters\\client_channel\\client_channel_plugin.cc " + - "src\\core\\ext\\filters\\client_channel\\connectivity_watcher.c " + + "src\\core\\ext\\filters\\client_channel\\connectivity_watcher.cc " + "src\\core\\ext\\filters\\client_channel\\connector.cc " + "src\\core\\ext\\filters\\client_channel\\http_connect_handshaker.cc " + "src\\core\\ext\\filters\\client_channel\\http_proxy.cc " + diff --git a/gRPC-Core.podspec b/gRPC-Core.podspec index 9b4f4ec6752..b0ac155e543 100644 --- a/gRPC-Core.podspec +++ b/gRPC-Core.podspec @@ -671,10 +671,11 @@ Pod::Spec.new do |s| 'src/core/ext/transport/chttp2/server/chttp2_server.cc', 'src/core/ext/transport/chttp2/client/secure/secure_channel_create.cc', 'src/core/ext/filters/client_channel/channel_connectivity.cc', + 'src/core/ext/filters/client_channel/channel_connectivity_internal.cc', 'src/core/ext/filters/client_channel/client_channel.cc', 'src/core/ext/filters/client_channel/client_channel_factory.cc', 'src/core/ext/filters/client_channel/client_channel_plugin.cc', - 'src/core/ext/filters/client_channel/connectivity_watcher.c', + 'src/core/ext/filters/client_channel/connectivity_watcher.cc', 'src/core/ext/filters/client_channel/connector.cc', 'src/core/ext/filters/client_channel/http_connect_handshaker.cc', 'src/core/ext/filters/client_channel/http_proxy.cc', diff --git a/grpc.gemspec b/grpc.gemspec index 9f5f45bb1bf..c791adf74b2 100644 --- a/grpc.gemspec +++ b/grpc.gemspec @@ -606,10 +606,11 @@ Gem::Specification.new do |s| s.files += %w( src/core/ext/transport/chttp2/server/chttp2_server.cc ) s.files += %w( src/core/ext/transport/chttp2/client/secure/secure_channel_create.cc ) s.files += %w( src/core/ext/filters/client_channel/channel_connectivity.cc ) + s.files += %w( src/core/ext/filters/client_channel/channel_connectivity_internal.cc ) s.files += %w( src/core/ext/filters/client_channel/client_channel.cc ) s.files += %w( src/core/ext/filters/client_channel/client_channel_factory.cc ) s.files += %w( src/core/ext/filters/client_channel/client_channel_plugin.cc ) - s.files += %w( src/core/ext/filters/client_channel/connectivity_watcher.c ) + s.files += %w( src/core/ext/filters/client_channel/connectivity_watcher.cc ) s.files += %w( src/core/ext/filters/client_channel/connector.cc ) s.files += %w( src/core/ext/filters/client_channel/http_connect_handshaker.cc ) s.files += %w( src/core/ext/filters/client_channel/http_proxy.cc ) diff --git a/grpc.gyp b/grpc.gyp index 420621fb4c5..96224ab8890 100644 --- a/grpc.gyp +++ b/grpc.gyp @@ -420,10 +420,11 @@ 'src/core/ext/transport/chttp2/server/chttp2_server.cc', 'src/core/ext/transport/chttp2/client/secure/secure_channel_create.cc', 'src/core/ext/filters/client_channel/channel_connectivity.cc', + 'src/core/ext/filters/client_channel/channel_connectivity_internal.cc', 'src/core/ext/filters/client_channel/client_channel.cc', 'src/core/ext/filters/client_channel/client_channel_factory.cc', 'src/core/ext/filters/client_channel/client_channel_plugin.cc', - 'src/core/ext/filters/client_channel/connectivity_watcher.c', + 'src/core/ext/filters/client_channel/connectivity_watcher.cc', 'src/core/ext/filters/client_channel/connector.cc', 'src/core/ext/filters/client_channel/http_connect_handshaker.cc', 'src/core/ext/filters/client_channel/http_proxy.cc', @@ -663,10 +664,11 @@ 'src/core/lib/transport/transport_op_string.cc', 'src/core/lib/debug/trace.cc', 'src/core/ext/filters/client_channel/channel_connectivity.cc', + 'src/core/ext/filters/client_channel/channel_connectivity_internal.cc', 'src/core/ext/filters/client_channel/client_channel.cc', 'src/core/ext/filters/client_channel/client_channel_factory.cc', 'src/core/ext/filters/client_channel/client_channel_plugin.cc', - 'src/core/ext/filters/client_channel/connectivity_watcher.c', + 'src/core/ext/filters/client_channel/connectivity_watcher.cc', 'src/core/ext/filters/client_channel/connector.cc', 'src/core/ext/filters/client_channel/http_connect_handshaker.cc', 'src/core/ext/filters/client_channel/http_proxy.cc', @@ -871,10 +873,11 @@ 'src/core/lib/transport/transport_op_string.cc', 'src/core/lib/debug/trace.cc', 'src/core/ext/filters/client_channel/channel_connectivity.cc', + 'src/core/ext/filters/client_channel/channel_connectivity_internal.cc', 'src/core/ext/filters/client_channel/client_channel.cc', 'src/core/ext/filters/client_channel/client_channel_factory.cc', 'src/core/ext/filters/client_channel/client_channel_plugin.cc', - 'src/core/ext/filters/client_channel/connectivity_watcher.c', + 'src/core/ext/filters/client_channel/connectivity_watcher.cc', 'src/core/ext/filters/client_channel/connector.cc', 'src/core/ext/filters/client_channel/http_connect_handshaker.cc', 'src/core/ext/filters/client_channel/http_proxy.cc', @@ -1097,10 +1100,11 @@ 'src/core/ext/transport/chttp2/client/insecure/channel_create_posix.cc', 'src/core/ext/transport/chttp2/client/chttp2_connector.cc', 'src/core/ext/filters/client_channel/channel_connectivity.cc', + 'src/core/ext/filters/client_channel/channel_connectivity_internal.cc', 'src/core/ext/filters/client_channel/client_channel.cc', 'src/core/ext/filters/client_channel/client_channel_factory.cc', 'src/core/ext/filters/client_channel/client_channel_plugin.cc', - 'src/core/ext/filters/client_channel/connectivity_watcher.c', + 'src/core/ext/filters/client_channel/connectivity_watcher.cc', 'src/core/ext/filters/client_channel/connector.cc', 'src/core/ext/filters/client_channel/http_connect_handshaker.cc', 'src/core/ext/filters/client_channel/http_proxy.cc', diff --git a/package.xml b/package.xml index 65cb53ad1cc..b78b210069e 100644 --- a/package.xml +++ b/package.xml @@ -618,10 +618,11 @@ + - + diff --git a/src/core/ext/filters/client_channel/connectivity_watcher.c b/src/core/ext/filters/client_channel/connectivity_watcher.cc similarity index 100% rename from src/core/ext/filters/client_channel/connectivity_watcher.c rename to src/core/ext/filters/client_channel/connectivity_watcher.cc diff --git a/src/python/grpcio/grpc_core_dependencies.py b/src/python/grpcio/grpc_core_dependencies.py index 467b13f22b4..44a4f0401a0 100644 --- a/src/python/grpcio/grpc_core_dependencies.py +++ b/src/python/grpcio/grpc_core_dependencies.py @@ -255,10 +255,11 @@ CORE_SOURCE_FILES = [ 'src/core/ext/transport/chttp2/server/chttp2_server.cc', 'src/core/ext/transport/chttp2/client/secure/secure_channel_create.cc', 'src/core/ext/filters/client_channel/channel_connectivity.cc', + 'src/core/ext/filters/client_channel/channel_connectivity_internal.cc', 'src/core/ext/filters/client_channel/client_channel.cc', 'src/core/ext/filters/client_channel/client_channel_factory.cc', 'src/core/ext/filters/client_channel/client_channel_plugin.cc', - 'src/core/ext/filters/client_channel/connectivity_watcher.c', + 'src/core/ext/filters/client_channel/connectivity_watcher.cc', 'src/core/ext/filters/client_channel/connector.cc', 'src/core/ext/filters/client_channel/http_connect_handshaker.cc', 'src/core/ext/filters/client_channel/http_proxy.cc', diff --git a/tools/doxygen/Doxyfile.core.internal b/tools/doxygen/Doxyfile.core.internal index bed3845db29..15ec466ded9 100644 --- a/tools/doxygen/Doxyfile.core.internal +++ b/tools/doxygen/Doxyfile.core.internal @@ -908,13 +908,14 @@ src/core/ext/census/tracing.cc \ src/core/ext/census/tracing.h \ src/core/ext/filters/client_channel/README.md \ src/core/ext/filters/client_channel/channel_connectivity.cc \ +src/core/ext/filters/client_channel/channel_connectivity_internal.cc \ src/core/ext/filters/client_channel/channel_connectivity_internal.h \ src/core/ext/filters/client_channel/client_channel.cc \ src/core/ext/filters/client_channel/client_channel.h \ src/core/ext/filters/client_channel/client_channel_factory.cc \ src/core/ext/filters/client_channel/client_channel_factory.h \ src/core/ext/filters/client_channel/client_channel_plugin.cc \ -src/core/ext/filters/client_channel/connectivity_watcher.c \ +src/core/ext/filters/client_channel/connectivity_watcher.cc \ src/core/ext/filters/client_channel/connectivity_watcher.h \ src/core/ext/filters/client_channel/connector.cc \ src/core/ext/filters/client_channel/connector.h \ diff --git a/tools/run_tests/generated/sources_and_headers.json b/tools/run_tests/generated/sources_and_headers.json index af7b7ee9a0c..e6ee1cf7332 100644 --- a/tools/run_tests/generated/sources_and_headers.json +++ b/tools/run_tests/generated/sources_and_headers.json @@ -8493,13 +8493,14 @@ "name": "grpc_client_channel", "src": [ "src/core/ext/filters/client_channel/channel_connectivity.cc", + "src/core/ext/filters/client_channel/channel_connectivity_internal.cc", "src/core/ext/filters/client_channel/channel_connectivity_internal.h", "src/core/ext/filters/client_channel/client_channel.cc", "src/core/ext/filters/client_channel/client_channel.h", "src/core/ext/filters/client_channel/client_channel_factory.cc", "src/core/ext/filters/client_channel/client_channel_factory.h", "src/core/ext/filters/client_channel/client_channel_plugin.cc", - "src/core/ext/filters/client_channel/connectivity_watcher.c", + "src/core/ext/filters/client_channel/connectivity_watcher.cc", "src/core/ext/filters/client_channel/connectivity_watcher.h", "src/core/ext/filters/client_channel/connector.cc", "src/core/ext/filters/client_channel/connector.h", From d9ce7d9233f90918b39771d5cba605101ccf2b16 Mon Sep 17 00:00:00 2001 From: Yuchen Zeng Date: Thu, 5 Oct 2017 13:58:01 -0700 Subject: [PATCH 34/47] clang-format --- src/core/ext/filters/client_channel/channel_connectivity.cc | 5 ++--- 1 file changed, 2 insertions(+), 3 deletions(-) diff --git a/src/core/ext/filters/client_channel/channel_connectivity.cc b/src/core/ext/filters/client_channel/channel_connectivity.cc index 33e9deaaf6b..4c36b0f97ab 100644 --- a/src/core/ext/filters/client_channel/channel_connectivity.cc +++ b/src/core/ext/filters/client_channel/channel_connectivity.cc @@ -94,9 +94,8 @@ void grpc_channel_watch_connectivity_state( "deadline=gpr_timespec { tv_sec: %" PRId64 ", tv_nsec: %d, clock_type: %d }, " "cq=%p, tag=%p)", - 7, - (channel, (int)last_observed_state, deadline.tv_sec, deadline.tv_nsec, - (int)deadline.clock_type, cq, tag)); + 7, (channel, (int)last_observed_state, deadline.tv_sec, deadline.tv_nsec, + (int)deadline.clock_type, cq, tag)); grpc_channel_watch_connectivity_state_internal( &exec_ctx, client_channel_elem, channel_stack, last_observed_state, deadline, cq, tag); From 0bad30a244e060c602904bef3f3447558d9445fb Mon Sep 17 00:00:00 2001 From: Yuchen Zeng Date: Thu, 5 Oct 2017 21:47:39 -0700 Subject: [PATCH 35/47] Use backup pollser instead of connectivity watcher --- BUILD | 6 +- CMakeLists.txt | 18 +- Makefile | 18 +- binding.gyp | 3 +- build.yaml | 6 +- config.m4 | 3 +- config.w32 | 3 +- gRPC-Core.podspec | 9 +- grpc.gemspec | 6 +- grpc.gyp | 12 +- package.xml | 6 +- .../filters/client_channel/backup_poller.cc | 143 +++++++++++++ ...connectivity_watcher.h => backup_poller.h} | 14 +- .../client_channel/channel_connectivity.cc | 160 +++++++++++++- .../channel_connectivity_internal.cc | 195 ------------------ .../channel_connectivity_internal.h | 33 --- .../filters/client_channel/client_channel.cc | 6 +- .../client_channel/connectivity_watcher.cc | 179 ---------------- src/python/grpcio/grpc_core_dependencies.py | 3 +- test/cpp/end2end/async_end2end_test.cc | 5 +- test/cpp/end2end/end2end_test.cc | 5 +- tools/doxygen/Doxyfile.core.internal | 6 +- .../generated/sources_and_headers.json | 9 +- 23 files changed, 350 insertions(+), 498 deletions(-) create mode 100644 src/core/ext/filters/client_channel/backup_poller.cc rename src/core/ext/filters/client_channel/{connectivity_watcher.h => backup_poller.h} (66%) delete mode 100644 src/core/ext/filters/client_channel/channel_connectivity_internal.cc delete mode 100644 src/core/ext/filters/client_channel/channel_connectivity_internal.h delete mode 100644 src/core/ext/filters/client_channel/connectivity_watcher.cc diff --git a/BUILD b/BUILD index 0e59e78db45..4c7376c862f 100644 --- a/BUILD +++ b/BUILD @@ -872,12 +872,11 @@ grpc_cc_library( grpc_cc_library( name = "grpc_client_channel", srcs = [ - "src/core/ext/filters/client_channel/channel_connectivity_internal.cc", + "src/core/ext/filters/client_channel/backup_poller.cc", "src/core/ext/filters/client_channel/channel_connectivity.cc", "src/core/ext/filters/client_channel/client_channel.cc", "src/core/ext/filters/client_channel/client_channel_factory.cc", "src/core/ext/filters/client_channel/client_channel_plugin.cc", - "src/core/ext/filters/client_channel/connectivity_watcher.cc", "src/core/ext/filters/client_channel/connector.cc", "src/core/ext/filters/client_channel/http_connect_handshaker.cc", "src/core/ext/filters/client_channel/http_proxy.cc", @@ -896,10 +895,9 @@ grpc_cc_library( "src/core/ext/filters/client_channel/uri_parser.cc", ], hdrs = [ - "src/core/ext/filters/client_channel/channel_connectivity_internal.h", + "src/core/ext/filters/client_channel/backup_poller.h", "src/core/ext/filters/client_channel/client_channel.h", "src/core/ext/filters/client_channel/client_channel_factory.h", - "src/core/ext/filters/client_channel/connectivity_watcher.h", "src/core/ext/filters/client_channel/connector.h", "src/core/ext/filters/client_channel/http_connect_handshaker.h", "src/core/ext/filters/client_channel/http_proxy.h", diff --git a/CMakeLists.txt b/CMakeLists.txt index c00a9e04a03..67a4c5dcd8c 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -1153,12 +1153,11 @@ add_library(grpc src/core/tsi/transport_security_adapter.cc src/core/ext/transport/chttp2/server/chttp2_server.cc src/core/ext/transport/chttp2/client/secure/secure_channel_create.cc + src/core/ext/filters/client_channel/backup_poller.cc src/core/ext/filters/client_channel/channel_connectivity.cc - src/core/ext/filters/client_channel/channel_connectivity_internal.cc src/core/ext/filters/client_channel/client_channel.cc src/core/ext/filters/client_channel/client_channel_factory.cc src/core/ext/filters/client_channel/client_channel_plugin.cc - src/core/ext/filters/client_channel/connectivity_watcher.cc src/core/ext/filters/client_channel/connector.cc src/core/ext/filters/client_channel/http_connect_handshaker.cc src/core/ext/filters/client_channel/http_proxy.cc @@ -1479,12 +1478,11 @@ add_library(grpc_cronet src/core/ext/filters/http/http_filters_plugin.cc src/core/ext/filters/http/message_compress/message_compress_filter.cc src/core/ext/filters/http/server/http_server_filter.cc + src/core/ext/filters/client_channel/backup_poller.cc src/core/ext/filters/client_channel/channel_connectivity.cc - src/core/ext/filters/client_channel/channel_connectivity_internal.cc src/core/ext/filters/client_channel/client_channel.cc src/core/ext/filters/client_channel/client_channel_factory.cc src/core/ext/filters/client_channel/client_channel_plugin.cc - src/core/ext/filters/client_channel/connectivity_watcher.cc src/core/ext/filters/client_channel/connector.cc src/core/ext/filters/client_channel/http_connect_handshaker.cc src/core/ext/filters/client_channel/http_proxy.cc @@ -1771,12 +1769,11 @@ add_library(grpc_test_util src/core/lib/transport/transport.cc src/core/lib/transport/transport_op_string.cc src/core/lib/debug/trace.cc + src/core/ext/filters/client_channel/backup_poller.cc src/core/ext/filters/client_channel/channel_connectivity.cc - src/core/ext/filters/client_channel/channel_connectivity_internal.cc src/core/ext/filters/client_channel/client_channel.cc src/core/ext/filters/client_channel/client_channel_factory.cc src/core/ext/filters/client_channel/client_channel_plugin.cc - src/core/ext/filters/client_channel/connectivity_watcher.cc src/core/ext/filters/client_channel/connector.cc src/core/ext/filters/client_channel/http_connect_handshaker.cc src/core/ext/filters/client_channel/http_proxy.cc @@ -2038,12 +2035,11 @@ add_library(grpc_test_util_unsecure src/core/lib/transport/transport.cc src/core/lib/transport/transport_op_string.cc src/core/lib/debug/trace.cc + src/core/ext/filters/client_channel/backup_poller.cc src/core/ext/filters/client_channel/channel_connectivity.cc - src/core/ext/filters/client_channel/channel_connectivity_internal.cc src/core/ext/filters/client_channel/client_channel.cc src/core/ext/filters/client_channel/client_channel_factory.cc src/core/ext/filters/client_channel/client_channel_plugin.cc - src/core/ext/filters/client_channel/connectivity_watcher.cc src/core/ext/filters/client_channel/connector.cc src/core/ext/filters/client_channel/http_connect_handshaker.cc src/core/ext/filters/client_channel/http_proxy.cc @@ -2324,12 +2320,11 @@ add_library(grpc_unsecure src/core/ext/transport/chttp2/client/insecure/channel_create.cc src/core/ext/transport/chttp2/client/insecure/channel_create_posix.cc src/core/ext/transport/chttp2/client/chttp2_connector.cc + src/core/ext/filters/client_channel/backup_poller.cc src/core/ext/filters/client_channel/channel_connectivity.cc - src/core/ext/filters/client_channel/channel_connectivity_internal.cc src/core/ext/filters/client_channel/client_channel.cc src/core/ext/filters/client_channel/client_channel_factory.cc src/core/ext/filters/client_channel/client_channel_plugin.cc - src/core/ext/filters/client_channel/connectivity_watcher.cc src/core/ext/filters/client_channel/connector.cc src/core/ext/filters/client_channel/http_connect_handshaker.cc src/core/ext/filters/client_channel/http_proxy.cc @@ -3061,12 +3056,11 @@ add_library(grpc++_cronet src/core/ext/filters/http/http_filters_plugin.cc src/core/ext/filters/http/message_compress/message_compress_filter.cc src/core/ext/filters/http/server/http_server_filter.cc + src/core/ext/filters/client_channel/backup_poller.cc src/core/ext/filters/client_channel/channel_connectivity.cc - src/core/ext/filters/client_channel/channel_connectivity_internal.cc src/core/ext/filters/client_channel/client_channel.cc src/core/ext/filters/client_channel/client_channel_factory.cc src/core/ext/filters/client_channel/client_channel_plugin.cc - src/core/ext/filters/client_channel/connectivity_watcher.cc src/core/ext/filters/client_channel/connector.cc src/core/ext/filters/client_channel/http_connect_handshaker.cc src/core/ext/filters/client_channel/http_proxy.cc diff --git a/Makefile b/Makefile index bda3c3fce4c..0df40b13fc4 100644 --- a/Makefile +++ b/Makefile @@ -3153,12 +3153,11 @@ LIBGRPC_SRC = \ src/core/tsi/transport_security_adapter.cc \ src/core/ext/transport/chttp2/server/chttp2_server.cc \ src/core/ext/transport/chttp2/client/secure/secure_channel_create.cc \ + src/core/ext/filters/client_channel/backup_poller.cc \ src/core/ext/filters/client_channel/channel_connectivity.cc \ - src/core/ext/filters/client_channel/channel_connectivity_internal.cc \ src/core/ext/filters/client_channel/client_channel.cc \ src/core/ext/filters/client_channel/client_channel_factory.cc \ src/core/ext/filters/client_channel/client_channel_plugin.cc \ - src/core/ext/filters/client_channel/connectivity_watcher.cc \ src/core/ext/filters/client_channel/connector.cc \ src/core/ext/filters/client_channel/http_connect_handshaker.cc \ src/core/ext/filters/client_channel/http_proxy.cc \ @@ -3478,12 +3477,11 @@ LIBGRPC_CRONET_SRC = \ src/core/ext/filters/http/http_filters_plugin.cc \ src/core/ext/filters/http/message_compress/message_compress_filter.cc \ src/core/ext/filters/http/server/http_server_filter.cc \ + src/core/ext/filters/client_channel/backup_poller.cc \ src/core/ext/filters/client_channel/channel_connectivity.cc \ - src/core/ext/filters/client_channel/channel_connectivity_internal.cc \ src/core/ext/filters/client_channel/client_channel.cc \ src/core/ext/filters/client_channel/client_channel_factory.cc \ src/core/ext/filters/client_channel/client_channel_plugin.cc \ - src/core/ext/filters/client_channel/connectivity_watcher.cc \ src/core/ext/filters/client_channel/connector.cc \ src/core/ext/filters/client_channel/http_connect_handshaker.cc \ src/core/ext/filters/client_channel/http_proxy.cc \ @@ -3768,12 +3766,11 @@ LIBGRPC_TEST_UTIL_SRC = \ src/core/lib/transport/transport.cc \ src/core/lib/transport/transport_op_string.cc \ src/core/lib/debug/trace.cc \ + src/core/ext/filters/client_channel/backup_poller.cc \ src/core/ext/filters/client_channel/channel_connectivity.cc \ - src/core/ext/filters/client_channel/channel_connectivity_internal.cc \ src/core/ext/filters/client_channel/client_channel.cc \ src/core/ext/filters/client_channel/client_channel_factory.cc \ src/core/ext/filters/client_channel/client_channel_plugin.cc \ - src/core/ext/filters/client_channel/connectivity_watcher.cc \ src/core/ext/filters/client_channel/connector.cc \ src/core/ext/filters/client_channel/http_connect_handshaker.cc \ src/core/ext/filters/client_channel/http_proxy.cc \ @@ -4025,12 +4022,11 @@ LIBGRPC_TEST_UTIL_UNSECURE_SRC = \ src/core/lib/transport/transport.cc \ src/core/lib/transport/transport_op_string.cc \ src/core/lib/debug/trace.cc \ + src/core/ext/filters/client_channel/backup_poller.cc \ src/core/ext/filters/client_channel/channel_connectivity.cc \ - src/core/ext/filters/client_channel/channel_connectivity_internal.cc \ src/core/ext/filters/client_channel/client_channel.cc \ src/core/ext/filters/client_channel/client_channel_factory.cc \ src/core/ext/filters/client_channel/client_channel_plugin.cc \ - src/core/ext/filters/client_channel/connectivity_watcher.cc \ src/core/ext/filters/client_channel/connector.cc \ src/core/ext/filters/client_channel/http_connect_handshaker.cc \ src/core/ext/filters/client_channel/http_proxy.cc \ @@ -4288,12 +4284,11 @@ LIBGRPC_UNSECURE_SRC = \ src/core/ext/transport/chttp2/client/insecure/channel_create.cc \ src/core/ext/transport/chttp2/client/insecure/channel_create_posix.cc \ src/core/ext/transport/chttp2/client/chttp2_connector.cc \ + src/core/ext/filters/client_channel/backup_poller.cc \ src/core/ext/filters/client_channel/channel_connectivity.cc \ - src/core/ext/filters/client_channel/channel_connectivity_internal.cc \ src/core/ext/filters/client_channel/client_channel.cc \ src/core/ext/filters/client_channel/client_channel_factory.cc \ src/core/ext/filters/client_channel/client_channel_plugin.cc \ - src/core/ext/filters/client_channel/connectivity_watcher.cc \ src/core/ext/filters/client_channel/connector.cc \ src/core/ext/filters/client_channel/http_connect_handshaker.cc \ src/core/ext/filters/client_channel/http_proxy.cc \ @@ -5003,12 +4998,11 @@ LIBGRPC++_CRONET_SRC = \ src/core/ext/filters/http/http_filters_plugin.cc \ src/core/ext/filters/http/message_compress/message_compress_filter.cc \ src/core/ext/filters/http/server/http_server_filter.cc \ + src/core/ext/filters/client_channel/backup_poller.cc \ src/core/ext/filters/client_channel/channel_connectivity.cc \ - src/core/ext/filters/client_channel/channel_connectivity_internal.cc \ src/core/ext/filters/client_channel/client_channel.cc \ src/core/ext/filters/client_channel/client_channel_factory.cc \ src/core/ext/filters/client_channel/client_channel_plugin.cc \ - src/core/ext/filters/client_channel/connectivity_watcher.cc \ src/core/ext/filters/client_channel/connector.cc \ src/core/ext/filters/client_channel/http_connect_handshaker.cc \ src/core/ext/filters/client_channel/http_proxy.cc \ diff --git a/binding.gyp b/binding.gyp index ff7bf8fcdab..9a1e3dce516 100644 --- a/binding.gyp +++ b/binding.gyp @@ -853,12 +853,11 @@ 'src/core/tsi/transport_security_adapter.cc', 'src/core/ext/transport/chttp2/server/chttp2_server.cc', 'src/core/ext/transport/chttp2/client/secure/secure_channel_create.cc', + 'src/core/ext/filters/client_channel/backup_poller.cc', 'src/core/ext/filters/client_channel/channel_connectivity.cc', - 'src/core/ext/filters/client_channel/channel_connectivity_internal.cc', 'src/core/ext/filters/client_channel/client_channel.cc', 'src/core/ext/filters/client_channel/client_channel_factory.cc', 'src/core/ext/filters/client_channel/client_channel_plugin.cc', - 'src/core/ext/filters/client_channel/connectivity_watcher.cc', 'src/core/ext/filters/client_channel/connector.cc', 'src/core/ext/filters/client_channel/http_connect_handshaker.cc', 'src/core/ext/filters/client_channel/http_proxy.cc', diff --git a/build.yaml b/build.yaml index 6308b080400..9a3d76502cd 100644 --- a/build.yaml +++ b/build.yaml @@ -463,10 +463,9 @@ filegroups: - grpc_trace_headers - name: grpc_client_channel headers: - - src/core/ext/filters/client_channel/channel_connectivity_internal.h + - src/core/ext/filters/client_channel/backup_poller.h - src/core/ext/filters/client_channel/client_channel.h - src/core/ext/filters/client_channel/client_channel_factory.h - - src/core/ext/filters/client_channel/connectivity_watcher.h - src/core/ext/filters/client_channel/connector.h - src/core/ext/filters/client_channel/http_connect_handshaker.h - src/core/ext/filters/client_channel/http_proxy.h @@ -484,12 +483,11 @@ filegroups: - src/core/ext/filters/client_channel/subchannel_index.h - src/core/ext/filters/client_channel/uri_parser.h src: + - src/core/ext/filters/client_channel/backup_poller.cc - src/core/ext/filters/client_channel/channel_connectivity.cc - - src/core/ext/filters/client_channel/channel_connectivity_internal.cc - src/core/ext/filters/client_channel/client_channel.cc - src/core/ext/filters/client_channel/client_channel_factory.cc - src/core/ext/filters/client_channel/client_channel_plugin.cc - - src/core/ext/filters/client_channel/connectivity_watcher.cc - src/core/ext/filters/client_channel/connector.cc - src/core/ext/filters/client_channel/http_connect_handshaker.cc - src/core/ext/filters/client_channel/http_proxy.cc diff --git a/config.m4 b/config.m4 index ca374cec0d0..70abfafaca8 100644 --- a/config.m4 +++ b/config.m4 @@ -278,12 +278,11 @@ if test "$PHP_GRPC" != "no"; then src/core/tsi/transport_security_adapter.cc \ src/core/ext/transport/chttp2/server/chttp2_server.cc \ src/core/ext/transport/chttp2/client/secure/secure_channel_create.cc \ + src/core/ext/filters/client_channel/backup_poller.cc \ src/core/ext/filters/client_channel/channel_connectivity.cc \ - src/core/ext/filters/client_channel/channel_connectivity_internal.cc \ src/core/ext/filters/client_channel/client_channel.cc \ src/core/ext/filters/client_channel/client_channel_factory.cc \ src/core/ext/filters/client_channel/client_channel_plugin.cc \ - src/core/ext/filters/client_channel/connectivity_watcher.cc \ src/core/ext/filters/client_channel/connector.cc \ src/core/ext/filters/client_channel/http_connect_handshaker.cc \ src/core/ext/filters/client_channel/http_proxy.cc \ diff --git a/config.w32 b/config.w32 index 0db7620b30b..455d51cbdd3 100644 --- a/config.w32 +++ b/config.w32 @@ -255,12 +255,11 @@ if (PHP_GRPC != "no") { "src\\core\\tsi\\transport_security_adapter.cc " + "src\\core\\ext\\transport\\chttp2\\server\\chttp2_server.cc " + "src\\core\\ext\\transport\\chttp2\\client\\secure\\secure_channel_create.cc " + + "src\\core\\ext\\filters\\client_channel\\backup_poller.cc " + "src\\core\\ext\\filters\\client_channel\\channel_connectivity.cc " + - "src\\core\\ext\\filters\\client_channel\\channel_connectivity_internal.cc " + "src\\core\\ext\\filters\\client_channel\\client_channel.cc " + "src\\core\\ext\\filters\\client_channel\\client_channel_factory.cc " + "src\\core\\ext\\filters\\client_channel\\client_channel_plugin.cc " + - "src\\core\\ext\\filters\\client_channel\\connectivity_watcher.cc " + "src\\core\\ext\\filters\\client_channel\\connector.cc " + "src\\core\\ext\\filters\\client_channel\\http_connect_handshaker.cc " + "src\\core\\ext\\filters\\client_channel\\http_proxy.cc " + diff --git a/gRPC-Core.podspec b/gRPC-Core.podspec index b0ac155e543..d28ef4ca3eb 100644 --- a/gRPC-Core.podspec +++ b/gRPC-Core.podspec @@ -299,10 +299,9 @@ Pod::Spec.new do |s| 'src/core/tsi/transport_security_adapter.h', 'src/core/tsi/transport_security_interface.h', 'src/core/ext/transport/chttp2/server/chttp2_server.h', - 'src/core/ext/filters/client_channel/channel_connectivity_internal.h', + 'src/core/ext/filters/client_channel/backup_poller.h', 'src/core/ext/filters/client_channel/client_channel.h', 'src/core/ext/filters/client_channel/client_channel_factory.h', - 'src/core/ext/filters/client_channel/connectivity_watcher.h', 'src/core/ext/filters/client_channel/connector.h', 'src/core/ext/filters/client_channel/http_connect_handshaker.h', 'src/core/ext/filters/client_channel/http_proxy.h', @@ -670,12 +669,11 @@ Pod::Spec.new do |s| 'src/core/tsi/transport_security_adapter.cc', 'src/core/ext/transport/chttp2/server/chttp2_server.cc', 'src/core/ext/transport/chttp2/client/secure/secure_channel_create.cc', + 'src/core/ext/filters/client_channel/backup_poller.cc', 'src/core/ext/filters/client_channel/channel_connectivity.cc', - 'src/core/ext/filters/client_channel/channel_connectivity_internal.cc', 'src/core/ext/filters/client_channel/client_channel.cc', 'src/core/ext/filters/client_channel/client_channel_factory.cc', 'src/core/ext/filters/client_channel/client_channel_plugin.cc', - 'src/core/ext/filters/client_channel/connectivity_watcher.cc', 'src/core/ext/filters/client_channel/connector.cc', 'src/core/ext/filters/client_channel/http_connect_handshaker.cc', 'src/core/ext/filters/client_channel/http_proxy.cc', @@ -806,10 +804,9 @@ Pod::Spec.new do |s| 'src/core/tsi/transport_security_adapter.h', 'src/core/tsi/transport_security_interface.h', 'src/core/ext/transport/chttp2/server/chttp2_server.h', - 'src/core/ext/filters/client_channel/channel_connectivity_internal.h', + 'src/core/ext/filters/client_channel/backup_poller.h', 'src/core/ext/filters/client_channel/client_channel.h', 'src/core/ext/filters/client_channel/client_channel_factory.h', - 'src/core/ext/filters/client_channel/connectivity_watcher.h', 'src/core/ext/filters/client_channel/connector.h', 'src/core/ext/filters/client_channel/http_connect_handshaker.h', 'src/core/ext/filters/client_channel/http_proxy.h', diff --git a/grpc.gemspec b/grpc.gemspec index c791adf74b2..1d8776ad322 100644 --- a/grpc.gemspec +++ b/grpc.gemspec @@ -230,10 +230,9 @@ Gem::Specification.new do |s| s.files += %w( src/core/tsi/transport_security_adapter.h ) s.files += %w( src/core/tsi/transport_security_interface.h ) s.files += %w( src/core/ext/transport/chttp2/server/chttp2_server.h ) - s.files += %w( src/core/ext/filters/client_channel/channel_connectivity_internal.h ) + s.files += %w( src/core/ext/filters/client_channel/backup_poller.h ) s.files += %w( src/core/ext/filters/client_channel/client_channel.h ) s.files += %w( src/core/ext/filters/client_channel/client_channel_factory.h ) - s.files += %w( src/core/ext/filters/client_channel/connectivity_watcher.h ) s.files += %w( src/core/ext/filters/client_channel/connector.h ) s.files += %w( src/core/ext/filters/client_channel/http_connect_handshaker.h ) s.files += %w( src/core/ext/filters/client_channel/http_proxy.h ) @@ -605,12 +604,11 @@ Gem::Specification.new do |s| s.files += %w( src/core/tsi/transport_security_adapter.cc ) s.files += %w( src/core/ext/transport/chttp2/server/chttp2_server.cc ) s.files += %w( src/core/ext/transport/chttp2/client/secure/secure_channel_create.cc ) + s.files += %w( src/core/ext/filters/client_channel/backup_poller.cc ) s.files += %w( src/core/ext/filters/client_channel/channel_connectivity.cc ) - s.files += %w( src/core/ext/filters/client_channel/channel_connectivity_internal.cc ) s.files += %w( src/core/ext/filters/client_channel/client_channel.cc ) s.files += %w( src/core/ext/filters/client_channel/client_channel_factory.cc ) s.files += %w( src/core/ext/filters/client_channel/client_channel_plugin.cc ) - s.files += %w( src/core/ext/filters/client_channel/connectivity_watcher.cc ) s.files += %w( src/core/ext/filters/client_channel/connector.cc ) s.files += %w( src/core/ext/filters/client_channel/http_connect_handshaker.cc ) s.files += %w( src/core/ext/filters/client_channel/http_proxy.cc ) diff --git a/grpc.gyp b/grpc.gyp index 96224ab8890..2014f8acd82 100644 --- a/grpc.gyp +++ b/grpc.gyp @@ -419,12 +419,11 @@ 'src/core/tsi/transport_security_adapter.cc', 'src/core/ext/transport/chttp2/server/chttp2_server.cc', 'src/core/ext/transport/chttp2/client/secure/secure_channel_create.cc', + 'src/core/ext/filters/client_channel/backup_poller.cc', 'src/core/ext/filters/client_channel/channel_connectivity.cc', - 'src/core/ext/filters/client_channel/channel_connectivity_internal.cc', 'src/core/ext/filters/client_channel/client_channel.cc', 'src/core/ext/filters/client_channel/client_channel_factory.cc', 'src/core/ext/filters/client_channel/client_channel_plugin.cc', - 'src/core/ext/filters/client_channel/connectivity_watcher.cc', 'src/core/ext/filters/client_channel/connector.cc', 'src/core/ext/filters/client_channel/http_connect_handshaker.cc', 'src/core/ext/filters/client_channel/http_proxy.cc', @@ -663,12 +662,11 @@ 'src/core/lib/transport/transport.cc', 'src/core/lib/transport/transport_op_string.cc', 'src/core/lib/debug/trace.cc', + 'src/core/ext/filters/client_channel/backup_poller.cc', 'src/core/ext/filters/client_channel/channel_connectivity.cc', - 'src/core/ext/filters/client_channel/channel_connectivity_internal.cc', 'src/core/ext/filters/client_channel/client_channel.cc', 'src/core/ext/filters/client_channel/client_channel_factory.cc', 'src/core/ext/filters/client_channel/client_channel_plugin.cc', - 'src/core/ext/filters/client_channel/connectivity_watcher.cc', 'src/core/ext/filters/client_channel/connector.cc', 'src/core/ext/filters/client_channel/http_connect_handshaker.cc', 'src/core/ext/filters/client_channel/http_proxy.cc', @@ -872,12 +870,11 @@ 'src/core/lib/transport/transport.cc', 'src/core/lib/transport/transport_op_string.cc', 'src/core/lib/debug/trace.cc', + 'src/core/ext/filters/client_channel/backup_poller.cc', 'src/core/ext/filters/client_channel/channel_connectivity.cc', - 'src/core/ext/filters/client_channel/channel_connectivity_internal.cc', 'src/core/ext/filters/client_channel/client_channel.cc', 'src/core/ext/filters/client_channel/client_channel_factory.cc', 'src/core/ext/filters/client_channel/client_channel_plugin.cc', - 'src/core/ext/filters/client_channel/connectivity_watcher.cc', 'src/core/ext/filters/client_channel/connector.cc', 'src/core/ext/filters/client_channel/http_connect_handshaker.cc', 'src/core/ext/filters/client_channel/http_proxy.cc', @@ -1099,12 +1096,11 @@ 'src/core/ext/transport/chttp2/client/insecure/channel_create.cc', 'src/core/ext/transport/chttp2/client/insecure/channel_create_posix.cc', 'src/core/ext/transport/chttp2/client/chttp2_connector.cc', + 'src/core/ext/filters/client_channel/backup_poller.cc', 'src/core/ext/filters/client_channel/channel_connectivity.cc', - 'src/core/ext/filters/client_channel/channel_connectivity_internal.cc', 'src/core/ext/filters/client_channel/client_channel.cc', 'src/core/ext/filters/client_channel/client_channel_factory.cc', 'src/core/ext/filters/client_channel/client_channel_plugin.cc', - 'src/core/ext/filters/client_channel/connectivity_watcher.cc', 'src/core/ext/filters/client_channel/connector.cc', 'src/core/ext/filters/client_channel/http_connect_handshaker.cc', 'src/core/ext/filters/client_channel/http_proxy.cc', diff --git a/package.xml b/package.xml index b78b210069e..92fca551d8d 100644 --- a/package.xml +++ b/package.xml @@ -242,10 +242,9 @@ - + - @@ -617,12 +616,11 @@ + - - diff --git a/src/core/ext/filters/client_channel/backup_poller.cc b/src/core/ext/filters/client_channel/backup_poller.cc new file mode 100644 index 00000000000..36b55ebf9a6 --- /dev/null +++ b/src/core/ext/filters/client_channel/backup_poller.cc @@ -0,0 +1,143 @@ +/* + * + * 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 "src/core/ext/filters/client_channel/backup_poller.h" + +#include +#include +#include +#include +#include "src/core/ext/filters/client_channel/client_channel.h" +#include "src/core/lib/iomgr/error.h" +#include "src/core/lib/iomgr/pollset.h" +#include "src/core/lib/iomgr/timer.h" +#include "src/core/lib/support/env.h" +#include "src/core/lib/support/string.h" +#include "src/core/lib/surface/channel.h" +#include "src/core/lib/surface/completion_queue.h" + +#define DEFAULT_POLLING_INTERVAL_MS 500 + +typedef struct backup_poller { + grpc_timer polling_timer; + grpc_closure run_poller_closure; + grpc_closure shutdown_closure; + gpr_mu* pollset_mu; + grpc_pollset* pollset; + gpr_refcount refs; + gpr_refcount shutdown_refs; +} backup_poller; + +static gpr_once g_once = GPR_ONCE_INIT; +static gpr_mu g_poller_mu; +static backup_poller* g_poller = NULL; + +static void init_g_poller_mu() { gpr_mu_init(&g_poller_mu); } + +static bool is_disabled() { + char* env = gpr_getenv("GRPC_DISABLE_CHANNEL_backup_poller"); + bool disabled = gpr_is_true(env); + gpr_free(env); + return disabled; +} + +static bool backup_poller_shutdown_unref(grpc_exec_ctx* exec_ctx, + backup_poller* p) { + if (gpr_unref(&p->shutdown_refs)) { + grpc_pollset_destroy(exec_ctx, p->pollset); + gpr_free(p->pollset); + gpr_free(p); + } + return true; +} + +static void done_poller(grpc_exec_ctx* exec_ctx, void* arg, grpc_error* error) { + backup_poller_shutdown_unref(exec_ctx, (backup_poller*)arg); +} + +static void g_poller_unref(grpc_exec_ctx* exec_ctx) { + if (gpr_unref(&g_poller->refs)) { + gpr_mu_lock(&g_poller_mu); + backup_poller* p = g_poller; + g_poller = NULL; + gpr_mu_unlock(&g_poller_mu); + + grpc_timer_cancel(exec_ctx, &p->polling_timer); + gpr_mu_lock(p->pollset_mu); + grpc_pollset_shutdown(exec_ctx, p->pollset, + GRPC_CLOSURE_INIT(&p->shutdown_closure, done_poller, + p, grpc_schedule_on_exec_ctx)); + gpr_mu_unlock(p->pollset_mu); + } +} + +static void run_poller(grpc_exec_ctx* exec_ctx, void* arg, grpc_error* error) { + backup_poller* p = (backup_poller*)arg; + if (error != GRPC_ERROR_NONE) { + if (error != GRPC_ERROR_CANCELLED) { + GRPC_LOG_IF_ERROR("check_connectivity_state", error); + } + backup_poller_shutdown_unref(exec_ctx, p); + return; + } + gpr_timespec now = gpr_now(GPR_CLOCK_MONOTONIC); + gpr_mu_lock(p->pollset_mu); + grpc_error* err = grpc_pollset_work(exec_ctx, p->pollset, NULL, now, + gpr_inf_past(GPR_CLOCK_MONOTONIC)); + gpr_mu_unlock(p->pollset_mu); + GRPC_LOG_IF_ERROR("Run client channel backup poller", err); + grpc_timer_init( + exec_ctx, &p->polling_timer, + gpr_time_add( + now, gpr_time_from_millis(DEFAULT_POLLING_INTERVAL_MS, GPR_TIMESPAN)), + &p->run_poller_closure, now); +} + +void grpc_client_channel_start_backup_polling( + grpc_exec_ctx* exec_ctx, grpc_pollset_set* interested_parties) { + if (is_disabled()) return; + gpr_once_init(&g_once, init_g_poller_mu); + gpr_mu_lock(&g_poller_mu); + if (g_poller == NULL) { + g_poller = (backup_poller*)gpr_zalloc(sizeof(backup_poller)); + g_poller->pollset = (grpc_pollset*)gpr_malloc(grpc_pollset_size()); + grpc_pollset_init(g_poller->pollset, &g_poller->pollset_mu); + gpr_ref_init(&g_poller->refs, 0); + // one for timer cancellation, one for pollset shutdown + gpr_ref_init(&g_poller->shutdown_refs, 2); + GRPC_CLOSURE_INIT(&g_poller->run_poller_closure, run_poller, g_poller, + grpc_schedule_on_exec_ctx); + gpr_timespec now = gpr_now(GPR_CLOCK_MONOTONIC); + grpc_timer_init( + exec_ctx, &g_poller->polling_timer, + gpr_time_add(now, gpr_time_from_millis(DEFAULT_POLLING_INTERVAL_MS, + GPR_TIMESPAN)), + &g_poller->run_poller_closure, now); + } + gpr_ref(&g_poller->refs); + gpr_mu_unlock(&g_poller_mu); + + grpc_pollset_set_add_pollset(exec_ctx, interested_parties, g_poller->pollset); +} + +void grpc_client_channel_stop_backup_polling( + grpc_exec_ctx* exec_ctx, grpc_pollset_set* interested_parties) { + if (is_disabled()) return; + grpc_pollset_set_del_pollset(exec_ctx, interested_parties, g_poller->pollset); + g_poller_unref(exec_ctx); +} diff --git a/src/core/ext/filters/client_channel/connectivity_watcher.h b/src/core/ext/filters/client_channel/backup_poller.h similarity index 66% rename from src/core/ext/filters/client_channel/connectivity_watcher.h rename to src/core/ext/filters/client_channel/backup_poller.h index e12d6c284a1..3044f757118 100644 --- a/src/core/ext/filters/client_channel/connectivity_watcher.h +++ b/src/core/ext/filters/client_channel/backup_poller.h @@ -16,8 +16,8 @@ * */ -#ifndef GRPC_CORE_EXT_FILTERS_CLIENT_CHANNEL_CONNECTIVITY_WATCHER_H -#define GRPC_CORE_EXT_FILTERS_CLIENT_CHANNEL_CONNECTIVITY_WATCHER_H +#ifndef GRPC_CORE_EXT_FILTERS_CLIENT_CHANNEL_BACKUP_POLLER_H +#define GRPC_CORE_EXT_FILTERS_CLIENT_CHANNEL_BACKUP_POLLER_H #include #include "src/core/lib/channel/channel_stack.h" @@ -25,8 +25,10 @@ /* Constantly watches client channel connectivity status to reconnect a * transiently disconnected channel */ -void grpc_client_channel_start_watching_connectivity( - grpc_exec_ctx* exec_ctx, grpc_channel_element* client_channel_elem, - grpc_channel_stack* channel_stack); +void grpc_client_channel_start_backup_polling( + grpc_exec_ctx* exec_ctx, grpc_pollset_set* interested_parties); -#endif /* GRPC_CORE_EXT_FILTERS_CLIENT_CHANNEL_CONNECTIVITY_WATCHER_H */ +void grpc_client_channel_stop_backup_polling( + grpc_exec_ctx* exec_ctx, grpc_pollset_set* interested_parties); + +#endif /* GRPC_CORE_EXT_FILTERS_CLIENT_CHANNEL_BACKUP_POLLER_H */ diff --git a/src/core/ext/filters/client_channel/channel_connectivity.cc b/src/core/ext/filters/client_channel/channel_connectivity.cc index 4c36b0f97ab..31a8fc39ce6 100644 --- a/src/core/ext/filters/client_channel/channel_connectivity.cc +++ b/src/core/ext/filters/client_channel/channel_connectivity.cc @@ -23,8 +23,8 @@ #include #include -#include "src/core/ext/filters/client_channel/channel_connectivity_internal.h" #include "src/core/ext/filters/client_channel/client_channel.h" +#include "src/core/lib/iomgr/timer.h" #include "src/core/lib/surface/api_trace.h" #include "src/core/lib/surface/completion_queue.h" @@ -52,6 +52,125 @@ grpc_connectivity_state grpc_channel_check_connectivity_state( return GRPC_CHANNEL_SHUTDOWN; } +typedef enum { + WAITING, + READY_TO_CALL_BACK, + CALLING_BACK_AND_FINISHED, +} callback_phase; + +typedef struct { + gpr_mu mu; + callback_phase phase; + grpc_closure on_complete; + grpc_closure on_timeout; + grpc_closure watcher_timer_init; + grpc_timer alarm; + grpc_connectivity_state state; + grpc_completion_queue *cq; + grpc_cq_completion completion_storage; + grpc_channel *channel; + grpc_error *error; + void *tag; +} state_watcher; + +static void delete_state_watcher(grpc_exec_ctx *exec_ctx, state_watcher *w) { + grpc_channel_element *client_channel_elem = grpc_channel_stack_last_element( + grpc_channel_get_channel_stack(w->channel)); + if (client_channel_elem->filter == &grpc_client_channel_filter) { + GRPC_CHANNEL_INTERNAL_UNREF(exec_ctx, w->channel, + "watch_channel_connectivity"); + } else { + abort(); + } + gpr_mu_destroy(&w->mu); + gpr_free(w); +} + +static void finished_completion(grpc_exec_ctx *exec_ctx, void *pw, + grpc_cq_completion *ignored) { + bool should_delete = false; + state_watcher *w = (state_watcher *)pw; + gpr_mu_lock(&w->mu); + switch (w->phase) { + case WAITING: + case READY_TO_CALL_BACK: + GPR_UNREACHABLE_CODE(return ); + case CALLING_BACK_AND_FINISHED: + should_delete = true; + break; + } + gpr_mu_unlock(&w->mu); + + if (should_delete) { + delete_state_watcher(exec_ctx, w); + } +} + +static void partly_done(grpc_exec_ctx *exec_ctx, state_watcher *w, + bool due_to_completion, grpc_error *error) { + if (due_to_completion) { + grpc_timer_cancel(exec_ctx, &w->alarm); + } else { + grpc_channel_element *client_channel_elem = grpc_channel_stack_last_element( + grpc_channel_get_channel_stack(w->channel)); + grpc_client_channel_watch_connectivity_state( + exec_ctx, client_channel_elem, + grpc_polling_entity_create_from_pollset(grpc_cq_pollset(w->cq)), NULL, + &w->on_complete, NULL); + } + + gpr_mu_lock(&w->mu); + + if (due_to_completion) { + if (GRPC_TRACER_ON(grpc_trace_operation_failures)) { + GRPC_LOG_IF_ERROR("watch_completion_error", GRPC_ERROR_REF(error)); + } + GRPC_ERROR_UNREF(error); + error = GRPC_ERROR_NONE; + } else { + if (error == GRPC_ERROR_NONE) { + error = GRPC_ERROR_CREATE_FROM_STATIC_STRING( + "Timed out waiting for connection state change"); + } else if (error == GRPC_ERROR_CANCELLED) { + error = GRPC_ERROR_NONE; + } + } + switch (w->phase) { + case WAITING: + GRPC_ERROR_REF(error); + w->error = error; + w->phase = READY_TO_CALL_BACK; + break; + case READY_TO_CALL_BACK: + if (error != GRPC_ERROR_NONE) { + GPR_ASSERT(!due_to_completion); + GRPC_ERROR_UNREF(w->error); + GRPC_ERROR_REF(error); + w->error = error; + } + w->phase = CALLING_BACK_AND_FINISHED; + grpc_cq_end_op(exec_ctx, w->cq, w->tag, w->error, finished_completion, w, + &w->completion_storage); + break; + case CALLING_BACK_AND_FINISHED: + GPR_UNREACHABLE_CODE(return ); + break; + } + gpr_mu_unlock(&w->mu); + + GRPC_ERROR_UNREF(error); +} + +static void watch_complete(grpc_exec_ctx *exec_ctx, void *pw, + grpc_error *error) { + partly_done(exec_ctx, (state_watcher *)pw, true, GRPC_ERROR_REF(error)); +} + +static void timeout_complete(grpc_exec_ctx *exec_ctx, void *pw, + grpc_error *error) { + partly_done(exec_ctx, (state_watcher *)pw, false, GRPC_ERROR_REF(error)); +} + int grpc_channel_num_external_connectivity_watchers(grpc_channel *channel) { grpc_channel_element *client_channel_elem = grpc_channel_stack_last_element(grpc_channel_get_channel_stack(channel)); @@ -83,10 +202,10 @@ int grpc_channel_support_connectivity_watcher(grpc_channel *channel) { void grpc_channel_watch_connectivity_state( grpc_channel *channel, grpc_connectivity_state last_observed_state, gpr_timespec deadline, grpc_completion_queue *cq, void *tag) { - grpc_channel_stack *channel_stack = grpc_channel_get_channel_stack(channel); grpc_channel_element *client_channel_elem = - grpc_channel_stack_last_element(channel_stack); + grpc_channel_stack_last_element(grpc_channel_get_channel_stack(channel)); grpc_exec_ctx exec_ctx = GRPC_EXEC_CTX_INIT; + state_watcher *w = (state_watcher *)gpr_malloc(sizeof(*w)); GRPC_API_TRACE( "grpc_channel_watch_connectivity_state(" @@ -96,8 +215,37 @@ void grpc_channel_watch_connectivity_state( "cq=%p, tag=%p)", 7, (channel, (int)last_observed_state, deadline.tv_sec, deadline.tv_nsec, (int)deadline.clock_type, cq, tag)); - grpc_channel_watch_connectivity_state_internal( - &exec_ctx, client_channel_elem, channel_stack, last_observed_state, - deadline, cq, tag); + + GPR_ASSERT(grpc_cq_begin_op(cq, tag)); + + gpr_mu_init(&w->mu); + GRPC_CLOSURE_INIT(&w->on_complete, watch_complete, w, + grpc_schedule_on_exec_ctx); + GRPC_CLOSURE_INIT(&w->on_timeout, timeout_complete, w, + grpc_schedule_on_exec_ctx); + w->phase = WAITING; + w->state = last_observed_state; + w->cq = cq; + w->tag = tag; + w->channel = channel; + w->error = NULL; + + watcher_timer_init_arg *wa = + (watcher_timer_init_arg *)gpr_malloc(sizeof(watcher_timer_init_arg)); + wa->w = w; + wa->deadline = deadline; + GRPC_CLOSURE_INIT(&w->watcher_timer_init, watcher_timer_init, wa, + grpc_schedule_on_exec_ctx); + + if (client_channel_elem->filter == &grpc_client_channel_filter) { + GRPC_CHANNEL_INTERNAL_REF(channel, "watch_channel_connectivity"); + grpc_client_channel_watch_connectivity_state( + &exec_ctx, client_channel_elem, + grpc_polling_entity_create_from_pollset(grpc_cq_pollset(cq)), &w->state, + &w->on_complete, &w->watcher_timer_init); + } else { + abort(); + } + grpc_exec_ctx_finish(&exec_ctx); } diff --git a/src/core/ext/filters/client_channel/channel_connectivity_internal.cc b/src/core/ext/filters/client_channel/channel_connectivity_internal.cc deleted file mode 100644 index 06bcfe2ffbf..00000000000 --- a/src/core/ext/filters/client_channel/channel_connectivity_internal.cc +++ /dev/null @@ -1,195 +0,0 @@ -/* - * - * 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 "src/core/ext/filters/client_channel/channel_connectivity_internal.h" - -#include -#include - -#include "src/core/ext/filters/client_channel/client_channel.h" -#include "src/core/lib/iomgr/timer.h" -#include "src/core/lib/surface/api_trace.h" -#include "src/core/lib/surface/completion_queue.h" - -typedef enum { - WAITING, - READY_TO_CALL_BACK, - CALLING_BACK_AND_FINISHED, -} callback_phase; - -typedef struct { - gpr_mu mu; - callback_phase phase; - grpc_closure on_complete; - grpc_closure on_timeout; - grpc_closure watcher_timer_init; - grpc_timer alarm; - grpc_connectivity_state state; - grpc_completion_queue *cq; - grpc_cq_completion completion_storage; - grpc_channel_element *client_channel_elem; - grpc_channel_stack *channel_stack; - grpc_error *error; - void *tag; -} state_watcher; - -static void delete_state_watcher(grpc_exec_ctx *exec_ctx, state_watcher *w) { - GRPC_CHANNEL_STACK_UNREF(exec_ctx, w->channel_stack, - "watch_channel_connectivity"); - gpr_mu_destroy(&w->mu); - gpr_free(w); -} - -static void finished_completion(grpc_exec_ctx *exec_ctx, void *pw, - grpc_cq_completion *ignored) { - bool should_delete = false; - state_watcher *w = (state_watcher *)pw; - gpr_mu_lock(&w->mu); - switch (w->phase) { - case WAITING: - case READY_TO_CALL_BACK: - GPR_UNREACHABLE_CODE(return ); - case CALLING_BACK_AND_FINISHED: - should_delete = true; - break; - } - gpr_mu_unlock(&w->mu); - - if (should_delete) { - delete_state_watcher(exec_ctx, w); - } -} - -static void partly_done(grpc_exec_ctx *exec_ctx, state_watcher *w, - bool due_to_completion, grpc_error *error) { - if (due_to_completion) { - grpc_timer_cancel(exec_ctx, &w->alarm); - } else { - grpc_channel_element *client_channel_elem = w->client_channel_elem; - grpc_client_channel_watch_connectivity_state( - exec_ctx, client_channel_elem, - grpc_polling_entity_create_from_pollset(grpc_cq_pollset(w->cq)), NULL, - &w->on_complete, NULL); - } - - gpr_mu_lock(&w->mu); - - if (due_to_completion) { - if (GRPC_TRACER_ON(grpc_trace_operation_failures)) { - GRPC_LOG_IF_ERROR("watch_completion_error", GRPC_ERROR_REF(error)); - } - GRPC_ERROR_UNREF(error); - error = GRPC_ERROR_NONE; - } else { - if (error == GRPC_ERROR_NONE) { - error = GRPC_ERROR_CREATE_FROM_STATIC_STRING( - "Timed out waiting for connection state change"); - } else if (error == GRPC_ERROR_CANCELLED) { - error = GRPC_ERROR_NONE; - } - } - switch (w->phase) { - case WAITING: - GRPC_ERROR_REF(error); - w->error = error; - w->phase = READY_TO_CALL_BACK; - break; - case READY_TO_CALL_BACK: - if (error != GRPC_ERROR_NONE) { - GPR_ASSERT(!due_to_completion); - GRPC_ERROR_UNREF(w->error); - GRPC_ERROR_REF(error); - w->error = error; - } - w->phase = CALLING_BACK_AND_FINISHED; - grpc_cq_end_op(exec_ctx, w->cq, w->tag, w->error, finished_completion, w, - &w->completion_storage); - break; - case CALLING_BACK_AND_FINISHED: - GPR_UNREACHABLE_CODE(return ); - break; - } - gpr_mu_unlock(&w->mu); - - GRPC_ERROR_UNREF(error); -} - -static void watch_complete(grpc_exec_ctx *exec_ctx, void *pw, - grpc_error *error) { - partly_done(exec_ctx, (state_watcher *)pw, true, GRPC_ERROR_REF(error)); -} - -static void timeout_complete(grpc_exec_ctx *exec_ctx, void *pw, - grpc_error *error) { - partly_done(exec_ctx, (state_watcher *)pw, false, GRPC_ERROR_REF(error)); -} - -typedef struct watcher_timer_init_arg { - state_watcher *w; - gpr_timespec deadline; -} watcher_timer_init_arg; - -static void watcher_timer_init(grpc_exec_ctx *exec_ctx, void *arg, - grpc_error *error_ignored) { - watcher_timer_init_arg *wa = (watcher_timer_init_arg *)arg; - - grpc_timer_init(exec_ctx, &wa->w->alarm, - gpr_convert_clock_type(wa->deadline, GPR_CLOCK_MONOTONIC), - &wa->w->on_timeout, gpr_now(GPR_CLOCK_MONOTONIC)); - gpr_free(wa); -} - -void grpc_channel_watch_connectivity_state_internal( - grpc_exec_ctx *exec_ctx, grpc_channel_element *client_channel_elem, - grpc_channel_stack *channel_stack, - grpc_connectivity_state last_observed_state, gpr_timespec deadline, - grpc_completion_queue *cq, void *tag) { - state_watcher *w = (state_watcher *)gpr_malloc(sizeof(*w)); - - GPR_ASSERT(grpc_cq_begin_op(cq, tag)); - - gpr_mu_init(&w->mu); - GRPC_CLOSURE_INIT(&w->on_complete, watch_complete, w, - grpc_schedule_on_exec_ctx); - GRPC_CLOSURE_INIT(&w->on_timeout, timeout_complete, w, - grpc_schedule_on_exec_ctx); - w->phase = WAITING; - w->state = last_observed_state; - w->cq = cq; - w->tag = tag; - w->client_channel_elem = client_channel_elem; - w->channel_stack = channel_stack; - w->error = NULL; - - watcher_timer_init_arg *wa = - (watcher_timer_init_arg *)gpr_malloc(sizeof(watcher_timer_init_arg)); - wa->w = w; - wa->deadline = deadline; - GRPC_CLOSURE_INIT(&w->watcher_timer_init, watcher_timer_init, wa, - grpc_schedule_on_exec_ctx); - - if (client_channel_elem->filter == &grpc_client_channel_filter) { - GRPC_CHANNEL_STACK_REF(channel_stack, "watch_channel_connectivity"); - grpc_client_channel_watch_connectivity_state( - exec_ctx, client_channel_elem, - grpc_polling_entity_create_from_pollset(grpc_cq_pollset(cq)), &w->state, - &w->on_complete, &w->watcher_timer_init); - } else { - abort(); - } -} diff --git a/src/core/ext/filters/client_channel/channel_connectivity_internal.h b/src/core/ext/filters/client_channel/channel_connectivity_internal.h deleted file mode 100644 index d260a20c07b..00000000000 --- a/src/core/ext/filters/client_channel/channel_connectivity_internal.h +++ /dev/null @@ -1,33 +0,0 @@ -/* - * - * 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_CHANNEL_CONNECTIVITY_INTERNAL_H -#define GRPC_CORE_EXT_FILTERS_CLIENT_CHANNEL_CHANNEL_CONNECTIVITY_INTERNAL_H - -#include -#include "src/core/lib/channel/channel_stack.h" -#include "src/core/lib/iomgr/exec_ctx.h" - -void grpc_channel_watch_connectivity_state_internal( - grpc_exec_ctx *exec_ctx, grpc_channel_element *client_channel_elem, - grpc_channel_stack *channel_stack, - grpc_connectivity_state last_observed_state, gpr_timespec deadline, - grpc_completion_queue *cq, void *tag); - -#endif /* GRPC_CORE_EXT_FILTERS_CLIENT_CHANNEL_CHANNEL_CONNECTIVITY_INTERNAL_H \ - */ diff --git a/src/core/ext/filters/client_channel/client_channel.cc b/src/core/ext/filters/client_channel/client_channel.cc index be8ea81a020..8223f25a332 100644 --- a/src/core/ext/filters/client_channel/client_channel.cc +++ b/src/core/ext/filters/client_channel/client_channel.cc @@ -31,7 +31,7 @@ #include #include -#include "src/core/ext/filters/client_channel/connectivity_watcher.h" +#include "src/core/ext/filters/client_channel/backup_poller.h" #include "src/core/ext/filters/client_channel/http_connect_handshaker.h" #include "src/core/ext/filters/client_channel/lb_policy_registry.h" #include "src/core/ext/filters/client_channel/proxy_mapper_registry.h" @@ -754,8 +754,7 @@ static grpc_error *cc_init_channel_elem(grpc_exec_ctx *exec_ctx, } chand->deadline_checking_enabled = grpc_deadline_checking_enabled(args->channel_args); - grpc_client_channel_start_watching_connectivity(exec_ctx, elem, - chand->owning_stack); + grpc_client_channel_start_backup_polling(exec_ctx, chand->interested_parties); return GRPC_ERROR_NONE; } @@ -793,6 +792,7 @@ static void cc_destroy_channel_elem(grpc_exec_ctx *exec_ctx, if (chand->method_params_table != NULL) { grpc_slice_hash_table_unref(exec_ctx, chand->method_params_table); } + grpc_client_channel_stop_backup_polling(exec_ctx, chand->interested_parties); grpc_connectivity_state_destroy(exec_ctx, &chand->state_tracker); grpc_pollset_set_destroy(exec_ctx, chand->interested_parties); GRPC_COMBINER_UNREF(exec_ctx, chand->combiner, "client_channel"); diff --git a/src/core/ext/filters/client_channel/connectivity_watcher.cc b/src/core/ext/filters/client_channel/connectivity_watcher.cc deleted file mode 100644 index da45929f269..00000000000 --- a/src/core/ext/filters/client_channel/connectivity_watcher.cc +++ /dev/null @@ -1,179 +0,0 @@ -/* - * - * 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 "src/core/ext/filters/client_channel/connectivity_watcher.h" - -#include -#include -#include -#include -#include "src/core/ext/filters/client_channel/channel_connectivity_internal.h" -#include "src/core/ext/filters/client_channel/client_channel.h" -#include "src/core/lib/iomgr/timer.h" -#include "src/core/lib/support/env.h" -#include "src/core/lib/support/string.h" -#include "src/core/lib/surface/channel.h" -#include "src/core/lib/surface/completion_queue.h" - -#define DEFAULT_CONNECTIVITY_CHECK_INTERVAL_MS 500 - -typedef struct connectivity_watcher { - grpc_timer watcher_timer; - grpc_closure check_connectivity_closure; - grpc_completion_queue* cq; - gpr_refcount refs; - size_t channel_count; - bool shutting_down; -} connectivity_watcher; - -typedef struct channel_state { - grpc_channel_element* client_channel_elem; - grpc_channel_stack* channel_stack; - grpc_connectivity_state state; -} channel_state; - -static gpr_once g_once = GPR_ONCE_INIT; -static gpr_mu g_watcher_mu; -static connectivity_watcher* g_watcher = NULL; - -static void init_g_watcher_mu() { gpr_mu_init(&g_watcher_mu); } - -static void start_watching_locked(grpc_exec_ctx* exec_ctx, - grpc_channel_element* client_channel_elem, - grpc_channel_stack* channel_stack) { - gpr_ref(&g_watcher->refs); - ++g_watcher->channel_count; - channel_state* s = (channel_state*)gpr_zalloc(sizeof(channel_state)); - s->client_channel_elem = client_channel_elem; - s->channel_stack = channel_stack; - s->state = GRPC_CHANNEL_IDLE; - grpc_channel_watch_connectivity_state_internal( - exec_ctx, client_channel_elem, channel_stack, s->state, - gpr_inf_future(GPR_CLOCK_MONOTONIC), g_watcher->cq, (void*)s); -} - -static bool is_disabled() { - char* env = gpr_getenv("GRPC_DISABLE_CHANNEL_CONNECTIVITY_WATCHER"); - bool disabled = gpr_is_true(env); - gpr_free(env); - return disabled; -} - -static bool connectivity_watcher_unref(grpc_exec_ctx* exec_ctx) { - if (gpr_unref(&g_watcher->refs)) { - gpr_mu_lock(&g_watcher_mu); - grpc_completion_queue_destroy(g_watcher->cq); - gpr_free(g_watcher); - g_watcher = NULL; - gpr_mu_unlock(&g_watcher_mu); - return true; - } - return false; -} - -static void check_connectivity_state(grpc_exec_ctx* exec_ctx, void* ignored, - grpc_error* error) { - grpc_event ev; - while (true) { - gpr_mu_lock(&g_watcher_mu); - if (g_watcher->shutting_down) { - // Drain cq if the watcher is shutting down - ev = grpc_completion_queue_next( - g_watcher->cq, gpr_inf_future(GPR_CLOCK_MONOTONIC), NULL); - } else { - ev = grpc_completion_queue_next(g_watcher->cq, - gpr_inf_past(GPR_CLOCK_MONOTONIC), NULL); - // Make sure we've seen 2 TIMEOUTs before going to sleep - if (ev.type == GRPC_QUEUE_TIMEOUT) { - ev = grpc_completion_queue_next( - g_watcher->cq, gpr_inf_past(GPR_CLOCK_MONOTONIC), NULL); - if (ev.type == GRPC_QUEUE_TIMEOUT) { - gpr_timespec now = gpr_now(GPR_CLOCK_MONOTONIC); - grpc_timer_init( - exec_ctx, &g_watcher->watcher_timer, - gpr_time_add(now, gpr_time_from_millis( - DEFAULT_CONNECTIVITY_CHECK_INTERVAL_MS, - GPR_TIMESPAN)), - &g_watcher->check_connectivity_closure, now); - gpr_mu_unlock(&g_watcher_mu); - break; - } - } - } - gpr_mu_unlock(&g_watcher_mu); - if (ev.type != GRPC_OP_COMPLETE) { - break; - } - channel_state* s = (channel_state*)(ev.tag); - s->state = grpc_client_channel_check_connectivity_state( - exec_ctx, s->client_channel_elem, false /* try_to_connect */); - if (s->state == GRPC_CHANNEL_SHUTDOWN) { - GRPC_CHANNEL_STACK_UNREF(exec_ctx, s->channel_stack, - "connectivity_watcher_stop_watching"); - gpr_free(s); - if (connectivity_watcher_unref(exec_ctx)) { - break; - } - } else { - grpc_channel_watch_connectivity_state_internal( - exec_ctx, s->client_channel_elem, s->channel_stack, s->state, - gpr_inf_future(GPR_CLOCK_MONOTONIC), g_watcher->cq, s); - } - } -} - -void grpc_client_channel_start_watching_connectivity( - grpc_exec_ctx* exec_ctx, grpc_channel_element* client_channel_elem, - grpc_channel_stack* channel_stack) { - if (is_disabled()) return; - GRPC_CHANNEL_STACK_REF(channel_stack, "connectivity_watcher_start_watching"); - gpr_once_init(&g_once, init_g_watcher_mu); - gpr_mu_lock(&g_watcher_mu); - if (g_watcher == NULL) { - g_watcher = (connectivity_watcher*)gpr_zalloc(sizeof(connectivity_watcher)); - g_watcher->cq = grpc_completion_queue_create_internal( - GRPC_CQ_NEXT, GRPC_CQ_DEFAULT_POLLING); - gpr_ref_init(&g_watcher->refs, 0); - GRPC_CLOSURE_INIT(&g_watcher->check_connectivity_closure, - check_connectivity_state, NULL, - grpc_schedule_on_exec_ctx); - gpr_timespec now = gpr_now(GPR_CLOCK_MONOTONIC); - grpc_timer_init( - exec_ctx, &g_watcher->watcher_timer, - gpr_time_add( - now, gpr_time_from_millis(DEFAULT_CONNECTIVITY_CHECK_INTERVAL_MS, - GPR_TIMESPAN)), - &g_watcher->check_connectivity_closure, now); - } - start_watching_locked(exec_ctx, client_channel_elem, channel_stack); - gpr_mu_init(&g_watcher_mu); -} - -void grpc_client_channel_stop_watching_connectivity( - grpc_exec_ctx* exec_ctx, grpc_channel_element* client_channel_elem, - grpc_channel_stack* channel_stack) { - if (is_disabled()) return; - gpr_once_init(&g_once, init_g_watcher_mu); - gpr_mu_lock(&g_watcher_mu); - if (--g_watcher->channel_count == 0) { - g_watcher->shutting_down = true; - grpc_timer_cancel(exec_ctx, &g_watcher->watcher_timer); - connectivity_watcher_unref(exec_ctx); - } - gpr_mu_unlock(&g_watcher_mu); -} diff --git a/src/python/grpcio/grpc_core_dependencies.py b/src/python/grpcio/grpc_core_dependencies.py index 44a4f0401a0..cf2e244e1ed 100644 --- a/src/python/grpcio/grpc_core_dependencies.py +++ b/src/python/grpcio/grpc_core_dependencies.py @@ -254,12 +254,11 @@ CORE_SOURCE_FILES = [ 'src/core/tsi/transport_security_adapter.cc', 'src/core/ext/transport/chttp2/server/chttp2_server.cc', 'src/core/ext/transport/chttp2/client/secure/secure_channel_create.cc', + 'src/core/ext/filters/client_channel/backup_poller.cc', 'src/core/ext/filters/client_channel/channel_connectivity.cc', - 'src/core/ext/filters/client_channel/channel_connectivity_internal.cc', 'src/core/ext/filters/client_channel/client_channel.cc', 'src/core/ext/filters/client_channel/client_channel_factory.cc', 'src/core/ext/filters/client_channel/client_channel_plugin.cc', - 'src/core/ext/filters/client_channel/connectivity_watcher.cc', 'src/core/ext/filters/client_channel/connector.cc', 'src/core/ext/filters/client_channel/http_connect_handshaker.cc', 'src/core/ext/filters/client_channel/http_proxy.cc', diff --git a/test/cpp/end2end/async_end2end_test.cc b/test/cpp/end2end/async_end2end_test.cc index b7634d04381..4d1beb1d1db 100644 --- a/test/cpp/end2end/async_end2end_test.cc +++ b/test/cpp/end2end/async_end2end_test.cc @@ -470,8 +470,9 @@ TEST_P(AsyncEnd2endTest, ReconnectChannel) { BuildAndStartServer(); // It needs more than kConnectivityCheckIntervalMsec time to reconnect the // channel. - gpr_sleep_until(gpr_time_add(gpr_now(GPR_CLOCK_REALTIME), - gpr_time_from_millis(1600, GPR_TIMESPAN))); + gpr_sleep_until(gpr_time_add( + gpr_now(GPR_CLOCK_REALTIME), + gpr_time_from_millis(600 * grpc_test_slowdown_factor(), GPR_TIMESPAN))); SendRpc(1); } diff --git a/test/cpp/end2end/end2end_test.cc b/test/cpp/end2end/end2end_test.cc index 1aa547d4e33..73f55555390 100644 --- a/test/cpp/end2end/end2end_test.cc +++ b/test/cpp/end2end/end2end_test.cc @@ -709,8 +709,9 @@ TEST_P(End2endTest, ReconnectChannel) { RestartServer(std::shared_ptr()); // It needs more than kConnectivityCheckIntervalMsec time to reconnect the // channel. - gpr_sleep_until(gpr_time_add(gpr_now(GPR_CLOCK_REALTIME), - gpr_time_from_millis(1600, GPR_TIMESPAN))); + gpr_sleep_until(gpr_time_add( + gpr_now(GPR_CLOCK_REALTIME), + gpr_time_from_millis(600 * grpc_test_slowdown_factor(), GPR_TIMESPAN))); SendRpc(stub_.get(), 1, false); } diff --git a/tools/doxygen/Doxyfile.core.internal b/tools/doxygen/Doxyfile.core.internal index 15ec466ded9..46ca54bf761 100644 --- a/tools/doxygen/Doxyfile.core.internal +++ b/tools/doxygen/Doxyfile.core.internal @@ -907,16 +907,14 @@ src/core/ext/census/trace_string.h \ src/core/ext/census/tracing.cc \ src/core/ext/census/tracing.h \ src/core/ext/filters/client_channel/README.md \ +src/core/ext/filters/client_channel/backup_poller.cc \ +src/core/ext/filters/client_channel/backup_poller.h \ src/core/ext/filters/client_channel/channel_connectivity.cc \ -src/core/ext/filters/client_channel/channel_connectivity_internal.cc \ -src/core/ext/filters/client_channel/channel_connectivity_internal.h \ src/core/ext/filters/client_channel/client_channel.cc \ src/core/ext/filters/client_channel/client_channel.h \ src/core/ext/filters/client_channel/client_channel_factory.cc \ src/core/ext/filters/client_channel/client_channel_factory.h \ src/core/ext/filters/client_channel/client_channel_plugin.cc \ -src/core/ext/filters/client_channel/connectivity_watcher.cc \ -src/core/ext/filters/client_channel/connectivity_watcher.h \ src/core/ext/filters/client_channel/connector.cc \ src/core/ext/filters/client_channel/connector.h \ src/core/ext/filters/client_channel/http_connect_handshaker.cc \ diff --git a/tools/run_tests/generated/sources_and_headers.json b/tools/run_tests/generated/sources_and_headers.json index e6ee1cf7332..9cd200fe5a4 100644 --- a/tools/run_tests/generated/sources_and_headers.json +++ b/tools/run_tests/generated/sources_and_headers.json @@ -8467,10 +8467,9 @@ "grpc_deadline_filter" ], "headers": [ - "src/core/ext/filters/client_channel/channel_connectivity_internal.h", + "src/core/ext/filters/client_channel/backup_poller.h", "src/core/ext/filters/client_channel/client_channel.h", "src/core/ext/filters/client_channel/client_channel_factory.h", - "src/core/ext/filters/client_channel/connectivity_watcher.h", "src/core/ext/filters/client_channel/connector.h", "src/core/ext/filters/client_channel/http_connect_handshaker.h", "src/core/ext/filters/client_channel/http_proxy.h", @@ -8492,16 +8491,14 @@ "language": "c", "name": "grpc_client_channel", "src": [ + "src/core/ext/filters/client_channel/backup_poller.cc", + "src/core/ext/filters/client_channel/backup_poller.h", "src/core/ext/filters/client_channel/channel_connectivity.cc", - "src/core/ext/filters/client_channel/channel_connectivity_internal.cc", - "src/core/ext/filters/client_channel/channel_connectivity_internal.h", "src/core/ext/filters/client_channel/client_channel.cc", "src/core/ext/filters/client_channel/client_channel.h", "src/core/ext/filters/client_channel/client_channel_factory.cc", "src/core/ext/filters/client_channel/client_channel_factory.h", "src/core/ext/filters/client_channel/client_channel_plugin.cc", - "src/core/ext/filters/client_channel/connectivity_watcher.cc", - "src/core/ext/filters/client_channel/connectivity_watcher.h", "src/core/ext/filters/client_channel/connector.cc", "src/core/ext/filters/client_channel/connector.h", "src/core/ext/filters/client_channel/http_connect_handshaker.cc", From b41014eeefa682c80d8bf48c720b23d00de29e03 Mon Sep 17 00:00:00 2001 From: Yuchen Zeng Date: Thu, 5 Oct 2017 23:00:06 -0700 Subject: [PATCH 36/47] Add GRPC_CLIENT_CHANNEL_BACKUP_POLL_INTERVAL_MS --- doc/environment_variables.md | 14 +++---- .../filters/client_channel/backup_poller.cc | 38 +++++++++++-------- 2 files changed, 29 insertions(+), 23 deletions(-) diff --git a/doc/environment_variables.md b/doc/environment_variables.md index c5fb2664980..0163235d63e 100644 --- a/doc/environment_variables.md +++ b/doc/environment_variables.md @@ -120,10 +120,10 @@ some configuration as environment variables that can be set. perform name resolution - ares - a DNS resolver based around the c-ares library -* GRPC_DISABLE_CHANNEL_CONNECTIVITY_WATCHER - The channel connectivity watcher uses one extra thread to check the channel - state every 500 ms on the client side. It can help reconnect disconnected - client channels (mostly due to idleness), so that the next RPC on this channel - won't fail. Set to 1 to turn off this watcher and save a thread. Please note - this is a temporary work-around, it will be removed in the future once we have - support for automatically reestablishing failed connections. +* GRPC_CLIENT_CHANNEL_BACKUP_POLL_INTERVAL_MS + Default: 500 + Declares the interval between two backup polls on client channels. These polls + are run in the timer thread so that gRPC can process connection failures while + there is no active polling thread. They help reconnect disconnected client + channels (mostly due to idleness), so that the next RPC on this channel won't + fail. Set to 0 to turn off the backup polls. diff --git a/src/core/ext/filters/client_channel/backup_poller.cc b/src/core/ext/filters/client_channel/backup_poller.cc index 36b55ebf9a6..784e75624bb 100644 --- a/src/core/ext/filters/client_channel/backup_poller.cc +++ b/src/core/ext/filters/client_channel/backup_poller.cc @@ -31,7 +31,7 @@ #include "src/core/lib/surface/channel.h" #include "src/core/lib/surface/completion_queue.h" -#define DEFAULT_POLLING_INTERVAL_MS 500 +#define DEFAULT_POLL_INTERVAL_MS 500 typedef struct backup_poller { grpc_timer polling_timer; @@ -46,14 +46,18 @@ typedef struct backup_poller { static gpr_once g_once = GPR_ONCE_INIT; static gpr_mu g_poller_mu; static backup_poller* g_poller = NULL; +static int g_poll_interval_ms = DEFAULT_POLL_INTERVAL_MS; -static void init_g_poller_mu() { gpr_mu_init(&g_poller_mu); } - -static bool is_disabled() { - char* env = gpr_getenv("GRPC_DISABLE_CHANNEL_backup_poller"); - bool disabled = gpr_is_true(env); +static void init_g_poller_mu() { + gpr_mu_init(&g_poller_mu); + char* env = gpr_getenv("GRPC_CLIENT_CHANNEL_BACKUP_POLL_INTERVAL_MS"); + if (env != NULL) { + int poll_interval_ms = gpr_parse_nonnegative_int(env); + if (poll_interval_ms != -1) { + g_poll_interval_ms = poll_interval_ms; + } + } gpr_free(env); - return disabled; } static bool backup_poller_shutdown_unref(grpc_exec_ctx* exec_ctx, @@ -103,14 +107,15 @@ static void run_poller(grpc_exec_ctx* exec_ctx, void* arg, grpc_error* error) { GRPC_LOG_IF_ERROR("Run client channel backup poller", err); grpc_timer_init( exec_ctx, &p->polling_timer, - gpr_time_add( - now, gpr_time_from_millis(DEFAULT_POLLING_INTERVAL_MS, GPR_TIMESPAN)), + gpr_time_add(now, gpr_time_from_millis(g_poll_interval_ms, GPR_TIMESPAN)), &p->run_poller_closure, now); } void grpc_client_channel_start_backup_polling( grpc_exec_ctx* exec_ctx, grpc_pollset_set* interested_parties) { - if (is_disabled()) return; + if (g_poll_interval_ms == 0) { + return; + } gpr_once_init(&g_once, init_g_poller_mu); gpr_mu_lock(&g_poller_mu); if (g_poller == NULL) { @@ -123,11 +128,10 @@ void grpc_client_channel_start_backup_polling( GRPC_CLOSURE_INIT(&g_poller->run_poller_closure, run_poller, g_poller, grpc_schedule_on_exec_ctx); gpr_timespec now = gpr_now(GPR_CLOCK_MONOTONIC); - grpc_timer_init( - exec_ctx, &g_poller->polling_timer, - gpr_time_add(now, gpr_time_from_millis(DEFAULT_POLLING_INTERVAL_MS, - GPR_TIMESPAN)), - &g_poller->run_poller_closure, now); + grpc_timer_init(exec_ctx, &g_poller->polling_timer, + gpr_time_add(now, gpr_time_from_millis(g_poll_interval_ms, + GPR_TIMESPAN)), + &g_poller->run_poller_closure, now); } gpr_ref(&g_poller->refs); gpr_mu_unlock(&g_poller_mu); @@ -137,7 +141,9 @@ void grpc_client_channel_start_backup_polling( void grpc_client_channel_stop_backup_polling( grpc_exec_ctx* exec_ctx, grpc_pollset_set* interested_parties) { - if (is_disabled()) return; + if (g_poll_interval_ms == 0) { + return; + } grpc_pollset_set_del_pollset(exec_ctx, interested_parties, g_poller->pollset); g_poller_unref(exec_ctx); } From dd77922d271684b64908493181b2bb0559d97c96 Mon Sep 17 00:00:00 2001 From: Yuchen Zeng Date: Thu, 5 Oct 2017 23:22:11 -0700 Subject: [PATCH 37/47] Add comments, fix backup_poller_shutdown_unref --- .../filters/client_channel/backup_poller.cc | 21 +++++++++---------- .../filters/client_channel/backup_poller.h | 4 ++-- 2 files changed, 12 insertions(+), 13 deletions(-) diff --git a/src/core/ext/filters/client_channel/backup_poller.cc b/src/core/ext/filters/client_channel/backup_poller.cc index 784e75624bb..9d6719d47c5 100644 --- a/src/core/ext/filters/client_channel/backup_poller.cc +++ b/src/core/ext/filters/client_channel/backup_poller.cc @@ -60,14 +60,13 @@ static void init_g_poller_mu() { gpr_free(env); } -static bool backup_poller_shutdown_unref(grpc_exec_ctx* exec_ctx, +static void backup_poller_shutdown_unref(grpc_exec_ctx* exec_ctx, backup_poller* p) { if (gpr_unref(&p->shutdown_refs)) { grpc_pollset_destroy(exec_ctx, p->pollset); gpr_free(p->pollset); gpr_free(p); } - return true; } static void done_poller(grpc_exec_ctx* exec_ctx, void* arg, grpc_error* error) { @@ -90,6 +89,13 @@ static void g_poller_unref(grpc_exec_ctx* exec_ctx) { } } +static void schedule_polling_timer(gpr_timespec now) { + grpc_timer_init( + exec_ctx, &p->polling_timer, + gpr_time_add(now, gpr_time_from_millis(g_poll_interval_ms, GPR_TIMESPAN)), + &p->run_poller_closure, now); +} + static void run_poller(grpc_exec_ctx* exec_ctx, void* arg, grpc_error* error) { backup_poller* p = (backup_poller*)arg; if (error != GRPC_ERROR_NONE) { @@ -105,10 +111,7 @@ static void run_poller(grpc_exec_ctx* exec_ctx, void* arg, grpc_error* error) { gpr_inf_past(GPR_CLOCK_MONOTONIC)); gpr_mu_unlock(p->pollset_mu); GRPC_LOG_IF_ERROR("Run client channel backup poller", err); - grpc_timer_init( - exec_ctx, &p->polling_timer, - gpr_time_add(now, gpr_time_from_millis(g_poll_interval_ms, GPR_TIMESPAN)), - &p->run_poller_closure, now); + schedule_polling_timer(now); } void grpc_client_channel_start_backup_polling( @@ -127,11 +130,7 @@ void grpc_client_channel_start_backup_polling( gpr_ref_init(&g_poller->shutdown_refs, 2); GRPC_CLOSURE_INIT(&g_poller->run_poller_closure, run_poller, g_poller, grpc_schedule_on_exec_ctx); - gpr_timespec now = gpr_now(GPR_CLOCK_MONOTONIC); - grpc_timer_init(exec_ctx, &g_poller->polling_timer, - gpr_time_add(now, gpr_time_from_millis(g_poll_interval_ms, - GPR_TIMESPAN)), - &g_poller->run_poller_closure, now); + schedule_polling_timer(gpr_now(GPR_CLOCK_MONOTONIC)); } gpr_ref(&g_poller->refs); gpr_mu_unlock(&g_poller_mu); diff --git a/src/core/ext/filters/client_channel/backup_poller.h b/src/core/ext/filters/client_channel/backup_poller.h index 3044f757118..e993d506392 100644 --- a/src/core/ext/filters/client_channel/backup_poller.h +++ b/src/core/ext/filters/client_channel/backup_poller.h @@ -23,11 +23,11 @@ #include "src/core/lib/channel/channel_stack.h" #include "src/core/lib/iomgr/exec_ctx.h" -/* Constantly watches client channel connectivity status to reconnect a - * transiently disconnected channel */ +/* Start polling \a interested_parties periodically in the timer thread */ void grpc_client_channel_start_backup_polling( grpc_exec_ctx* exec_ctx, grpc_pollset_set* interested_parties); +/* Stop polling \a interested_parties */ void grpc_client_channel_stop_backup_polling( grpc_exec_ctx* exec_ctx, grpc_pollset_set* interested_parties); From 223f8d412be6713b6d12e4ef9076b4bb33b149a8 Mon Sep 17 00:00:00 2001 From: Yuchen Zeng Date: Thu, 5 Oct 2017 23:31:26 -0700 Subject: [PATCH 38/47] Remove schedule_polling_timer --- .../filters/client_channel/backup_poller.cc | 18 +++++++++--------- 1 file changed, 9 insertions(+), 9 deletions(-) diff --git a/src/core/ext/filters/client_channel/backup_poller.cc b/src/core/ext/filters/client_channel/backup_poller.cc index 9d6719d47c5..e9bae130561 100644 --- a/src/core/ext/filters/client_channel/backup_poller.cc +++ b/src/core/ext/filters/client_channel/backup_poller.cc @@ -89,13 +89,6 @@ static void g_poller_unref(grpc_exec_ctx* exec_ctx) { } } -static void schedule_polling_timer(gpr_timespec now) { - grpc_timer_init( - exec_ctx, &p->polling_timer, - gpr_time_add(now, gpr_time_from_millis(g_poll_interval_ms, GPR_TIMESPAN)), - &p->run_poller_closure, now); -} - static void run_poller(grpc_exec_ctx* exec_ctx, void* arg, grpc_error* error) { backup_poller* p = (backup_poller*)arg; if (error != GRPC_ERROR_NONE) { @@ -111,7 +104,10 @@ static void run_poller(grpc_exec_ctx* exec_ctx, void* arg, grpc_error* error) { gpr_inf_past(GPR_CLOCK_MONOTONIC)); gpr_mu_unlock(p->pollset_mu); GRPC_LOG_IF_ERROR("Run client channel backup poller", err); - schedule_polling_timer(now); + grpc_timer_init( + exec_ctx, &p->polling_timer, + gpr_time_add(now, gpr_time_from_millis(g_poll_interval_ms, GPR_TIMESPAN)), + &p->run_poller_closure, now); } void grpc_client_channel_start_backup_polling( @@ -130,7 +126,11 @@ void grpc_client_channel_start_backup_polling( gpr_ref_init(&g_poller->shutdown_refs, 2); GRPC_CLOSURE_INIT(&g_poller->run_poller_closure, run_poller, g_poller, grpc_schedule_on_exec_ctx); - schedule_polling_timer(gpr_now(GPR_CLOCK_MONOTONIC)); + gpr_timespec now = gpr_now(GPR_CLOCK_MONOTONIC); + grpc_timer_init(exec_ctx, &g_poller->polling_timer, + gpr_time_add(now, gpr_time_from_millis(g_poll_interval_ms, + GPR_TIMESPAN)), + &g_poller->run_poller_closure, now); } gpr_ref(&g_poller->refs); gpr_mu_unlock(&g_poller_mu); From c83ce41789d5ed1f65934bd6d0f8f16255911a45 Mon Sep 17 00:00:00 2001 From: Yuchen Zeng Date: Fri, 6 Oct 2017 14:40:25 -0700 Subject: [PATCH 39/47] Fix polling_timer shutdown process --- .../filters/client_channel/backup_poller.cc | 32 +++++++++++++------ 1 file changed, 23 insertions(+), 9 deletions(-) diff --git a/src/core/ext/filters/client_channel/backup_poller.cc b/src/core/ext/filters/client_channel/backup_poller.cc index e9bae130561..5f5995a7703 100644 --- a/src/core/ext/filters/client_channel/backup_poller.cc +++ b/src/core/ext/filters/client_channel/backup_poller.cc @@ -38,22 +38,31 @@ typedef struct backup_poller { grpc_closure run_poller_closure; grpc_closure shutdown_closure; gpr_mu* pollset_mu; - grpc_pollset* pollset; + grpc_pollset* pollset; // guarded by pollset_mu + bool shutting_down; // guarded by pollset_mu gpr_refcount refs; gpr_refcount shutdown_refs; } backup_poller; static gpr_once g_once = GPR_ONCE_INIT; static gpr_mu g_poller_mu; -static backup_poller* g_poller = NULL; +static backup_poller* g_poller = NULL; // guarded by g_poller_mu +// g_poll_interval_ms is set only once at the first time +// grpc_client_channel_start_backup_polling() is call, after that it is treated +// as const. static int g_poll_interval_ms = DEFAULT_POLL_INTERVAL_MS; -static void init_g_poller_mu() { +static void init_globals() { gpr_mu_init(&g_poller_mu); char* env = gpr_getenv("GRPC_CLIENT_CHANNEL_BACKUP_POLL_INTERVAL_MS"); if (env != NULL) { int poll_interval_ms = gpr_parse_nonnegative_int(env); - if (poll_interval_ms != -1) { + if (poll_interval_ms == -1) { + gpr_log(GPR_ERROR, + "Invalid GRPC_CLIENT_CHANNEL_BACKUP_POLL_INTERVAL_MS: %s, " + "default value %d will be used.", + env, g_poll_interval_ms); + } else { g_poll_interval_ms = poll_interval_ms; } } @@ -79,13 +88,13 @@ static void g_poller_unref(grpc_exec_ctx* exec_ctx) { backup_poller* p = g_poller; g_poller = NULL; gpr_mu_unlock(&g_poller_mu); - - grpc_timer_cancel(exec_ctx, &p->polling_timer); gpr_mu_lock(p->pollset_mu); + p->shutting_down = true; grpc_pollset_shutdown(exec_ctx, p->pollset, GRPC_CLOSURE_INIT(&p->shutdown_closure, done_poller, p, grpc_schedule_on_exec_ctx)); gpr_mu_unlock(p->pollset_mu); + grpc_timer_cancel(exec_ctx, &p->polling_timer); } } @@ -93,13 +102,18 @@ static void run_poller(grpc_exec_ctx* exec_ctx, void* arg, grpc_error* error) { backup_poller* p = (backup_poller*)arg; if (error != GRPC_ERROR_NONE) { if (error != GRPC_ERROR_CANCELLED) { - GRPC_LOG_IF_ERROR("check_connectivity_state", error); + GRPC_LOG_IF_ERROR("run_poller", error); } backup_poller_shutdown_unref(exec_ctx, p); return; } gpr_timespec now = gpr_now(GPR_CLOCK_MONOTONIC); gpr_mu_lock(p->pollset_mu); + if (p->shutting_down) { + gpr_mu_unlock(p->pollset_mu); + backup_poller_shutdown_unref(exec_ctx, p); + return; + } grpc_error* err = grpc_pollset_work(exec_ctx, p->pollset, NULL, now, gpr_inf_past(GPR_CLOCK_MONOTONIC)); gpr_mu_unlock(p->pollset_mu); @@ -112,14 +126,15 @@ static void run_poller(grpc_exec_ctx* exec_ctx, void* arg, grpc_error* error) { void grpc_client_channel_start_backup_polling( grpc_exec_ctx* exec_ctx, grpc_pollset_set* interested_parties) { + gpr_once_init(&g_once, init_globals); if (g_poll_interval_ms == 0) { return; } - gpr_once_init(&g_once, init_g_poller_mu); gpr_mu_lock(&g_poller_mu); if (g_poller == NULL) { g_poller = (backup_poller*)gpr_zalloc(sizeof(backup_poller)); g_poller->pollset = (grpc_pollset*)gpr_malloc(grpc_pollset_size()); + g_poller->shutting_down = false; grpc_pollset_init(g_poller->pollset, &g_poller->pollset_mu); gpr_ref_init(&g_poller->refs, 0); // one for timer cancellation, one for pollset shutdown @@ -134,7 +149,6 @@ void grpc_client_channel_start_backup_polling( } gpr_ref(&g_poller->refs); gpr_mu_unlock(&g_poller_mu); - grpc_pollset_set_add_pollset(exec_ctx, interested_parties, g_poller->pollset); } From d573861506ae91d4ae96144911d1382d27f71831 Mon Sep 17 00:00:00 2001 From: Yuchen Zeng Date: Fri, 6 Oct 2017 16:17:04 -0700 Subject: [PATCH 40/47] Update with grpc_millis --- .../filters/client_channel/backup_poller.cc | 20 ++++++++----------- 1 file changed, 8 insertions(+), 12 deletions(-) diff --git a/src/core/ext/filters/client_channel/backup_poller.cc b/src/core/ext/filters/client_channel/backup_poller.cc index 5f5995a7703..3e314c74faa 100644 --- a/src/core/ext/filters/client_channel/backup_poller.cc +++ b/src/core/ext/filters/client_channel/backup_poller.cc @@ -102,26 +102,24 @@ static void run_poller(grpc_exec_ctx* exec_ctx, void* arg, grpc_error* error) { backup_poller* p = (backup_poller*)arg; if (error != GRPC_ERROR_NONE) { if (error != GRPC_ERROR_CANCELLED) { - GRPC_LOG_IF_ERROR("run_poller", error); + GRPC_LOG_IF_ERROR("run_poller", GRPC_ERROR_REF(error)); } backup_poller_shutdown_unref(exec_ctx, p); return; } - gpr_timespec now = gpr_now(GPR_CLOCK_MONOTONIC); gpr_mu_lock(p->pollset_mu); if (p->shutting_down) { gpr_mu_unlock(p->pollset_mu); backup_poller_shutdown_unref(exec_ctx, p); return; } - grpc_error* err = grpc_pollset_work(exec_ctx, p->pollset, NULL, now, - gpr_inf_past(GPR_CLOCK_MONOTONIC)); + grpc_error* err = + grpc_pollset_work(exec_ctx, p->pollset, NULL, GRPC_MILLIS_INF_PAST); gpr_mu_unlock(p->pollset_mu); GRPC_LOG_IF_ERROR("Run client channel backup poller", err); - grpc_timer_init( - exec_ctx, &p->polling_timer, - gpr_time_add(now, gpr_time_from_millis(g_poll_interval_ms, GPR_TIMESPAN)), - &p->run_poller_closure, now); + grpc_timer_init(exec_ctx, &p->polling_timer, + grpc_exec_ctx_now(exec_ctx) + g_poll_interval_ms, + &p->run_poller_closure); } void grpc_client_channel_start_backup_polling( @@ -141,11 +139,9 @@ void grpc_client_channel_start_backup_polling( gpr_ref_init(&g_poller->shutdown_refs, 2); GRPC_CLOSURE_INIT(&g_poller->run_poller_closure, run_poller, g_poller, grpc_schedule_on_exec_ctx); - gpr_timespec now = gpr_now(GPR_CLOCK_MONOTONIC); grpc_timer_init(exec_ctx, &g_poller->polling_timer, - gpr_time_add(now, gpr_time_from_millis(g_poll_interval_ms, - GPR_TIMESPAN)), - &g_poller->run_poller_closure, now); + grpc_exec_ctx_now(exec_ctx) + g_poll_interval_ms, + &g_poller->run_poller_closure); } gpr_ref(&g_poller->refs); gpr_mu_unlock(&g_poller_mu); From 6f9985e5513c40242afb74301a96f78bc790c2a1 Mon Sep 17 00:00:00 2001 From: Yuchen Zeng Date: Tue, 10 Oct 2017 19:00:01 -0700 Subject: [PATCH 41/47] Fix SIGV when grpc_channel_stack_init returns errors --- src/core/ext/filters/client_channel/backup_poller.cc | 4 ++-- src/core/ext/filters/client_channel/client_channel.cc | 2 +- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/src/core/ext/filters/client_channel/backup_poller.cc b/src/core/ext/filters/client_channel/backup_poller.cc index 3e314c74faa..3b47b6630b4 100644 --- a/src/core/ext/filters/client_channel/backup_poller.cc +++ b/src/core/ext/filters/client_channel/backup_poller.cc @@ -48,8 +48,8 @@ static gpr_once g_once = GPR_ONCE_INIT; static gpr_mu g_poller_mu; static backup_poller* g_poller = NULL; // guarded by g_poller_mu // g_poll_interval_ms is set only once at the first time -// grpc_client_channel_start_backup_polling() is call, after that it is treated -// as const. +// grpc_client_channel_start_backup_polling() is called, after that it is +// treated as const. static int g_poll_interval_ms = DEFAULT_POLL_INTERVAL_MS; static void init_globals() { diff --git a/src/core/ext/filters/client_channel/client_channel.cc b/src/core/ext/filters/client_channel/client_channel.cc index 8223f25a332..4332bfd470c 100644 --- a/src/core/ext/filters/client_channel/client_channel.cc +++ b/src/core/ext/filters/client_channel/client_channel.cc @@ -713,6 +713,7 @@ static grpc_error *cc_init_channel_elem(grpc_exec_ctx *exec_ctx, chand->interested_parties = grpc_pollset_set_create(); grpc_connectivity_state_init(&chand->state_tracker, GRPC_CHANNEL_IDLE, "client_channel"); + grpc_client_channel_start_backup_polling(exec_ctx, chand->interested_parties); // Record client channel factory. const grpc_arg *arg = grpc_channel_args_find(args->channel_args, GRPC_ARG_CLIENT_CHANNEL_FACTORY); @@ -754,7 +755,6 @@ static grpc_error *cc_init_channel_elem(grpc_exec_ctx *exec_ctx, } chand->deadline_checking_enabled = grpc_deadline_checking_enabled(args->channel_args); - grpc_client_channel_start_backup_polling(exec_ctx, chand->interested_parties); return GRPC_ERROR_NONE; } From 7fa814fbeb9599d9d921a705438d254cc1920781 Mon Sep 17 00:00:00 2001 From: Yuchen Zeng Date: Sun, 15 Oct 2017 19:00:16 -0700 Subject: [PATCH 42/47] Fix timeouts --- .../ext/filters/client_channel/backup_poller.cc | 4 ++-- test/cpp/end2end/async_end2end_test.cc | 14 +++++++++++++- test/cpp/end2end/end2end_test.cc | 14 +++++++++++++- 3 files changed, 28 insertions(+), 4 deletions(-) diff --git a/src/core/ext/filters/client_channel/backup_poller.cc b/src/core/ext/filters/client_channel/backup_poller.cc index 3b47b6630b4..dc1f87bc6c2 100644 --- a/src/core/ext/filters/client_channel/backup_poller.cc +++ b/src/core/ext/filters/client_channel/backup_poller.cc @@ -113,8 +113,8 @@ static void run_poller(grpc_exec_ctx* exec_ctx, void* arg, grpc_error* error) { backup_poller_shutdown_unref(exec_ctx, p); return; } - grpc_error* err = - grpc_pollset_work(exec_ctx, p->pollset, NULL, GRPC_MILLIS_INF_PAST); + grpc_error* err = grpc_pollset_work(exec_ctx, p->pollset, NULL, + grpc_exec_ctx_now(exec_ctx)); gpr_mu_unlock(p->pollset_mu); GRPC_LOG_IF_ERROR("Run client channel backup poller", err); grpc_timer_init(exec_ctx, &p->polling_timer, diff --git a/test/cpp/end2end/async_end2end_test.cc b/test/cpp/end2end/async_end2end_test.cc index 4d1beb1d1db..f8ad4c333c1 100644 --- a/test/cpp/end2end/async_end2end_test.cc +++ b/test/cpp/end2end/async_end2end_test.cc @@ -28,12 +28,14 @@ #include #include #include +#include #include #include #include #include #include "src/core/lib/iomgr/port.h" +#include "src/core/lib/support/env.h" #include "src/proto/grpc/health/v1/health.grpc.pb.h" #include "src/proto/grpc/testing/duplicate/echo_duplicate.grpc.pb.h" #include "src/proto/grpc/testing/echo.grpc.pb.h" @@ -459,6 +461,14 @@ TEST_P(AsyncEnd2endTest, ReconnectChannel) { if (GetParam().inproc) { return; } + int poller_slowdown_factor = 1; + // It needs 2 pollset_works to reconnect the channel with polling engine + // "poll" + char* s = gpr_getenv("GRPC_POLL_STRATEGY"); + if (s != NULL && 0 == strcmp(s, "poll")) { + poller_slowdown_factor = 2; + } + gpr_free(s); ResetStub(); SendRpc(1); server_->Shutdown(); @@ -472,7 +482,9 @@ TEST_P(AsyncEnd2endTest, ReconnectChannel) { // channel. gpr_sleep_until(gpr_time_add( gpr_now(GPR_CLOCK_REALTIME), - gpr_time_from_millis(600 * grpc_test_slowdown_factor(), GPR_TIMESPAN))); + gpr_time_from_millis( + 600 * poller_slowdown_factor * grpc_test_slowdown_factor(), + GPR_TIMESPAN))); SendRpc(1); } diff --git a/test/cpp/end2end/end2end_test.cc b/test/cpp/end2end/end2end_test.cc index 73f55555390..2272c9945ee 100644 --- a/test/cpp/end2end/end2end_test.cc +++ b/test/cpp/end2end/end2end_test.cc @@ -30,11 +30,13 @@ #include #include #include +#include #include #include #include #include "src/core/lib/security/credentials/credentials.h" +#include "src/core/lib/support/env.h" #include "src/proto/grpc/testing/duplicate/echo_duplicate.grpc.pb.h" #include "src/proto/grpc/testing/echo.grpc.pb.h" #include "test/core/util/port.h" @@ -704,6 +706,14 @@ TEST_P(End2endTest, ReconnectChannel) { if (GetParam().inproc) { return; } + int poller_slowdown_factor = 1; + // It needs 2 pollset_works to reconnect the channel with polling engine + // "poll" + char* s = gpr_getenv("GRPC_POLL_STRATEGY"); + if (s != NULL && 0 == strcmp(s, "poll")) { + poller_slowdown_factor = 2; + } + gpr_free(s); ResetStub(); SendRpc(stub_.get(), 1, false); RestartServer(std::shared_ptr()); @@ -711,7 +721,9 @@ TEST_P(End2endTest, ReconnectChannel) { // channel. gpr_sleep_until(gpr_time_add( gpr_now(GPR_CLOCK_REALTIME), - gpr_time_from_millis(600 * grpc_test_slowdown_factor(), GPR_TIMESPAN))); + gpr_time_from_millis( + 600 * poller_slowdown_factor * grpc_test_slowdown_factor(), + GPR_TIMESPAN))); SendRpc(stub_.get(), 1, false); } From cbb9296b729a312ca9ea59ef53cf022994c31dff Mon Sep 17 00:00:00 2001 From: Yuchen Zeng Date: Wed, 18 Oct 2017 11:47:10 -0700 Subject: [PATCH 43/47] Change the default interval to 5 seconds --- doc/environment_variables.md | 2 +- src/core/ext/filters/client_channel/backup_poller.cc | 2 +- test/cpp/end2end/async_end2end_test.cc | 7 ++++--- test/cpp/end2end/end2end_test.cc | 7 ++++--- 4 files changed, 10 insertions(+), 8 deletions(-) diff --git a/doc/environment_variables.md b/doc/environment_variables.md index 0163235d63e..40af758f693 100644 --- a/doc/environment_variables.md +++ b/doc/environment_variables.md @@ -121,7 +121,7 @@ some configuration as environment variables that can be set. - ares - a DNS resolver based around the c-ares library * GRPC_CLIENT_CHANNEL_BACKUP_POLL_INTERVAL_MS - Default: 500 + Default: 5000 Declares the interval between two backup polls on client channels. These polls are run in the timer thread so that gRPC can process connection failures while there is no active polling thread. They help reconnect disconnected client diff --git a/src/core/ext/filters/client_channel/backup_poller.cc b/src/core/ext/filters/client_channel/backup_poller.cc index dc1f87bc6c2..e717c4eb7e9 100644 --- a/src/core/ext/filters/client_channel/backup_poller.cc +++ b/src/core/ext/filters/client_channel/backup_poller.cc @@ -31,7 +31,7 @@ #include "src/core/lib/surface/channel.h" #include "src/core/lib/surface/completion_queue.h" -#define DEFAULT_POLL_INTERVAL_MS 500 +#define DEFAULT_POLL_INTERVAL_MS 5000 typedef struct backup_poller { grpc_timer polling_timer; diff --git a/test/cpp/end2end/async_end2end_test.cc b/test/cpp/end2end/async_end2end_test.cc index f8ad4c333c1..af3bdb25ac7 100644 --- a/test/cpp/end2end/async_end2end_test.cc +++ b/test/cpp/end2end/async_end2end_test.cc @@ -461,6 +461,7 @@ TEST_P(AsyncEnd2endTest, ReconnectChannel) { if (GetParam().inproc) { return; } + gpr_setenv("GRPC_CLIENT_CHANNEL_BACKUP_POLL_INTERVAL_MS", "200"); int poller_slowdown_factor = 1; // It needs 2 pollset_works to reconnect the channel with polling engine // "poll" @@ -478,12 +479,12 @@ TEST_P(AsyncEnd2endTest, ReconnectChannel) { while (cq_->Next(&ignored_tag, &ignored_ok)) ; BuildAndStartServer(); - // It needs more than kConnectivityCheckIntervalMsec time to reconnect the - // channel. + // It needs more than GRPC_CLIENT_CHANNEL_BACKUP_POLL_INTERVAL_MS time to + // reconnect the channel. gpr_sleep_until(gpr_time_add( gpr_now(GPR_CLOCK_REALTIME), gpr_time_from_millis( - 600 * poller_slowdown_factor * grpc_test_slowdown_factor(), + 300 * poller_slowdown_factor * grpc_test_slowdown_factor(), GPR_TIMESPAN))); SendRpc(1); } diff --git a/test/cpp/end2end/end2end_test.cc b/test/cpp/end2end/end2end_test.cc index 2272c9945ee..82ca39466ef 100644 --- a/test/cpp/end2end/end2end_test.cc +++ b/test/cpp/end2end/end2end_test.cc @@ -706,6 +706,7 @@ TEST_P(End2endTest, ReconnectChannel) { if (GetParam().inproc) { return; } + gpr_setenv("GRPC_CLIENT_CHANNEL_BACKUP_POLL_INTERVAL_MS", "200"); int poller_slowdown_factor = 1; // It needs 2 pollset_works to reconnect the channel with polling engine // "poll" @@ -717,12 +718,12 @@ TEST_P(End2endTest, ReconnectChannel) { ResetStub(); SendRpc(stub_.get(), 1, false); RestartServer(std::shared_ptr()); - // It needs more than kConnectivityCheckIntervalMsec time to reconnect the - // channel. + // It needs more than GRPC_CLIENT_CHANNEL_BACKUP_POLL_INTERVAL_MS time to + // reconnect the channel. gpr_sleep_until(gpr_time_add( gpr_now(GPR_CLOCK_REALTIME), gpr_time_from_millis( - 600 * poller_slowdown_factor * grpc_test_slowdown_factor(), + 300 * poller_slowdown_factor * grpc_test_slowdown_factor(), GPR_TIMESPAN))); SendRpc(stub_.get(), 1, false); } From d38214045930020f546517e3bc5fab3626053ebb Mon Sep 17 00:00:00 2001 From: Yuchen Zeng Date: Fri, 20 Oct 2017 18:08:04 -0700 Subject: [PATCH 44/47] Fix crash in epollex --- src/core/ext/filters/client_channel/backup_poller.cc | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/core/ext/filters/client_channel/backup_poller.cc b/src/core/ext/filters/client_channel/backup_poller.cc index e717c4eb7e9..466bf86bc00 100644 --- a/src/core/ext/filters/client_channel/backup_poller.cc +++ b/src/core/ext/filters/client_channel/backup_poller.cc @@ -131,7 +131,7 @@ void grpc_client_channel_start_backup_polling( gpr_mu_lock(&g_poller_mu); if (g_poller == NULL) { g_poller = (backup_poller*)gpr_zalloc(sizeof(backup_poller)); - g_poller->pollset = (grpc_pollset*)gpr_malloc(grpc_pollset_size()); + g_poller->pollset = (grpc_pollset*)gpr_zalloc(grpc_pollset_size()); g_poller->shutting_down = false; grpc_pollset_init(g_poller->pollset, &g_poller->pollset_mu); gpr_ref_init(&g_poller->refs, 0); From b16df7547149f42e32cfca3cf99280a2df3bb180 Mon Sep 17 00:00:00 2001 From: Yuchen Zeng Date: Mon, 30 Oct 2017 12:09:16 -0700 Subject: [PATCH 45/47] Update with internal C++ interfaces --- src/cpp/client/channel_cc.cc | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/cpp/client/channel_cc.cc b/src/cpp/client/channel_cc.cc index 1509a92d268..9df531066e2 100644 --- a/src/cpp/client/channel_cc.cc +++ b/src/cpp/client/channel_cc.cc @@ -143,7 +143,7 @@ grpc_connectivity_state Channel::GetState(bool try_to_connect) { namespace { -class TagSaver final : public CompletionQueueTag { +class TagSaver final : public internal::CompletionQueueTag { public: explicit TagSaver(void* tag) : tag_(tag) {} ~TagSaver() override {} From cb36615ddd0d8446032c2fda936337b330cd3f7f Mon Sep 17 00:00:00 2001 From: Vijay Pai Date: Fri, 20 Oct 2017 06:09:44 -0700 Subject: [PATCH 46/47] GPR_ATTRIBUTE_NO_TSAN doesn't reach through function calls, so use a friend --- .../transport/chttp2/transport/flow_control.h | 8 +++++++ .../microbenchmarks/bm_fullstack_trickle.cc | 21 ++++++++++--------- 2 files changed, 19 insertions(+), 10 deletions(-) diff --git a/src/core/ext/transport/chttp2/transport/flow_control.h b/src/core/ext/transport/chttp2/transport/flow_control.h index d5107d467b9..905161497de 100644 --- a/src/core/ext/transport/chttp2/transport/flow_control.h +++ b/src/core/ext/transport/chttp2/transport/flow_control.h @@ -32,6 +32,12 @@ struct grpc_chttp2_stream; extern "C" grpc_tracer_flag grpc_flowctl_trace; +namespace grpc { +namespace testing { + class TrickledCHTTP2; // to make this a friend +} // namespace testing +} // namespace grpc + namespace grpc_core { namespace chttp2 { @@ -203,6 +209,7 @@ class TransportFlowControl { } private: + friend class ::grpc::testing::TrickledCHTTP2; double TargetLogBdp(); double SmoothLogBdp(grpc_exec_ctx* exec_ctx, double value); FlowControlAction::Urgency DeltaUrgency(int32_t value, @@ -297,6 +304,7 @@ class StreamFlowControl { } private: + friend class ::grpc::testing::TrickledCHTTP2; TransportFlowControl* const tfc_; const grpc_chttp2_stream* const s_; diff --git a/test/cpp/microbenchmarks/bm_fullstack_trickle.cc b/test/cpp/microbenchmarks/bm_fullstack_trickle.cc index 389b8c90ab7..25d243a104c 100644 --- a/test/cpp/microbenchmarks/bm_fullstack_trickle.cc +++ b/test/cpp/microbenchmarks/bm_fullstack_trickle.cc @@ -21,6 +21,7 @@ #include #include #include + #include "src/core/ext/transport/chttp2/transport/chttp2_transport.h" #include "src/core/ext/transport/chttp2/transport/internal.h" #include "src/core/lib/iomgr/timer_manager.h" @@ -142,17 +143,17 @@ class TrickledCHTTP2 : public EndpointPairFixture { client->lists[GRPC_CHTTP2_LIST_STALLED_BY_STREAM].head != nullptr, server->lists[GRPC_CHTTP2_LIST_STALLED_BY_TRANSPORT].head != nullptr, server->lists[GRPC_CHTTP2_LIST_STALLED_BY_STREAM].head != nullptr, - client->flow_control->remote_window(), - server->flow_control->remote_window(), - client->flow_control->announced_window(), - server->flow_control->announced_window(), - client_stream ? client_stream->flow_control->remote_window_delta() : -1, - server_stream ? server_stream->flow_control->remote_window_delta() : -1, - client_stream ? client_stream->flow_control->local_window_delta() : -1, - server_stream ? server_stream->flow_control->local_window_delta() : -1, - client_stream ? client_stream->flow_control->announced_window_delta() + client->flow_control->remote_window_, + server->flow_control->remote_window_, + client->flow_control->announced_window_, + server->flow_control->announced_window_, + client_stream ? client_stream->flow_control->remote_window_delta_ : -1, + server_stream ? server_stream->flow_control->remote_window_delta_ : -1, + client_stream ? client_stream->flow_control->local_window_delta_ : -1, + server_stream ? server_stream->flow_control->local_window_delta_ : -1, + client_stream ? client_stream->flow_control->announced_window_delta_ : -1, - server_stream ? server_stream->flow_control->announced_window_delta() + server_stream ? server_stream->flow_control->announced_window_delta_ : -1, client->settings[GRPC_PEER_SETTINGS] [GRPC_CHTTP2_SETTINGS_INITIAL_WINDOW_SIZE], From e9f5c9058b72298ef857f4f7716d61d03f289d1b Mon Sep 17 00:00:00 2001 From: Vijay Pai Date: Fri, 20 Oct 2017 14:21:42 -0700 Subject: [PATCH 47/47] clang-fmt --- src/core/ext/transport/chttp2/transport/flow_control.h | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/core/ext/transport/chttp2/transport/flow_control.h b/src/core/ext/transport/chttp2/transport/flow_control.h index 905161497de..7dd348ed5f1 100644 --- a/src/core/ext/transport/chttp2/transport/flow_control.h +++ b/src/core/ext/transport/chttp2/transport/flow_control.h @@ -34,7 +34,7 @@ extern "C" grpc_tracer_flag grpc_flowctl_trace; namespace grpc { namespace testing { - class TrickledCHTTP2; // to make this a friend +class TrickledCHTTP2; // to make this a friend } // namespace testing } // namespace grpc