From 8a507811ff14502131474eb3bf799c14419579a6 Mon Sep 17 00:00:00 2001 From: Jan Tattermusch Date: Mon, 8 May 2017 16:30:12 +0200 Subject: [PATCH 01/45] C# workaround for unavailable on idle channels --- src/csharp/Grpc.Core/Channel.cs | 41 ++++++++++++++++++++++++++++++++- 1 file changed, 40 insertions(+), 1 deletion(-) diff --git a/src/csharp/Grpc.Core/Channel.cs b/src/csharp/Grpc.Core/Channel.cs index 4f29c35b321..51ae11fbdec 100644 --- a/src/csharp/Grpc.Core/Channel.cs +++ b/src/csharp/Grpc.Core/Channel.cs @@ -59,6 +59,8 @@ namespace Grpc.Core readonly ChannelSafeHandle handle; readonly Dictionary options; + readonly Task connectivityWatcherTask; + bool shutdownRequested; /// @@ -99,6 +101,9 @@ namespace Grpc.Core this.handle = ChannelSafeHandle.CreateInsecure(target, nativeChannelArgs); } } + // TODO(jtattermusch): Workaround for https://github.com/GoogleCloudPlatform/google-cloud-dotnet/issues/822. + // Remove once retries are supported in C core + this.connectivityWatcherTask = RunConnectivityWatcherAsync(); GrpcEnvironment.RegisterChannel(this); } @@ -244,7 +249,7 @@ namespace Grpc.Core handle.Dispose(); - await GrpcEnvironment.ReleaseAsync().ConfigureAwait(false); + await Task.WhenAll(GrpcEnvironment.ReleaseAsync(), connectivityWatcherTask).ConfigureAwait(false); } internal ChannelSafeHandle Handle @@ -299,6 +304,40 @@ namespace Grpc.Core } } + /// + /// Constantly Watches channel connectivity status to work around https://github.com/GoogleCloudPlatform/google-cloud-dotnet/issues/822 + /// + private async Task RunConnectivityWatcherAsync() + { + try + { + var lastState = State; + while (lastState != ChannelState.Shutdown) + { + lock (myLock) + { + if (shutdownRequested) + { + break; + } + } + + try + { + await WaitForStateChangedAsync(lastState, DateTime.UtcNow.AddSeconds(1)).ConfigureAwait(false); + } + catch (TaskCanceledException) + { + // ignore timeout + } + lastState = State; + } + } + catch (ObjectDisposedException) { + // during shutdown, channel is going to be disposed. + } + } + private static void EnsureUserAgentChannelOption(Dictionary options) { var key = ChannelOptions.PrimaryUserAgentString; From b2c0b7bc7411c0914e2f65d56096ecde1a207b53 Mon Sep 17 00:00:00 2001 From: Alexander Polcyn Date: Thu, 27 Apr 2017 00:26:25 -0700 Subject: [PATCH 02/45] constant state watch without timeouts --- src/ruby/end2end/channel_closing_driver.rb | 5 + src/ruby/end2end/channel_state_driver.rb | 3 + src/ruby/end2end/grpc_class_init_client.rb | 65 ++- src/ruby/end2end/grpc_class_init_driver.rb | 51 +- .../sig_int_during_channel_watch_client.rb | 2 + .../sig_int_during_channel_watch_driver.rb | 5 + src/ruby/ext/grpc/rb_call.c | 2 +- src/ruby/ext/grpc/rb_channel.c | 494 ++++++++++++------ src/ruby/ext/grpc/rb_completion_queue.c | 14 +- src/ruby/ext/grpc/rb_completion_queue.h | 2 +- src/ruby/ext/grpc/rb_event_thread.c | 12 +- src/ruby/ext/grpc/rb_server.c | 2 +- src/ruby/spec/channel_connection_spec.rb | 35 +- 13 files changed, 472 insertions(+), 220 deletions(-) diff --git a/src/ruby/end2end/channel_closing_driver.rb b/src/ruby/end2end/channel_closing_driver.rb index d3e5373b0bb..bed8c434058 100755 --- a/src/ruby/end2end/channel_closing_driver.rb +++ b/src/ruby/end2end/channel_closing_driver.rb @@ -61,6 +61,11 @@ def main 'channel is closed while connectivity is watched' end + client_exit_code = $CHILD_STATUS + if client_exit_code != 0 + fail "channel closing client failed, exit code #{client_exit_code}" + end + server_runner.stop end diff --git a/src/ruby/end2end/channel_state_driver.rb b/src/ruby/end2end/channel_state_driver.rb index 80fb62899e5..9910076dba1 100755 --- a/src/ruby/end2end/channel_state_driver.rb +++ b/src/ruby/end2end/channel_state_driver.rb @@ -58,6 +58,9 @@ def main 'It likely hangs when ended abruptly' end + # The interrupt in the child process should cause it to + # exit a non-zero status, so don't check it here. + # This test mainly tries to catch deadlock. server_runner.stop end diff --git a/src/ruby/end2end/grpc_class_init_client.rb b/src/ruby/end2end/grpc_class_init_client.rb index ee79292119a..8e46907368f 100755 --- a/src/ruby/end2end/grpc_class_init_client.rb +++ b/src/ruby/end2end/grpc_class_init_client.rb @@ -34,44 +34,81 @@ require_relative './end2end_common' -def main - grpc_class = '' - OptionParser.new do |opts| - opts.on('--grpc_class=P', String) do |p| - grpc_class = p +def construct_many(test_proc) + thds = [] + 4.times do + thds << Thread.new do + 20.times do + test_proc.call + end end - end.parse! + end + 20.times do + test_proc.call + end + thds.each(&:join) +end + +def run_gc_stress_test(test_proc) + GC.disable + construct_many(test_proc) - test_proc = nil + GC.enable + construct_many(test_proc) + GC.start(full_mark: true, immediate_sweep: true) + construct_many(test_proc) +end + +def get_test_proc(grpc_class) case grpc_class when 'channel' - test_proc = proc do + return proc do GRPC::Core::Channel.new('dummy_host', nil, :this_channel_is_insecure) end when 'server' - test_proc = proc do + return proc do GRPC::Core::Server.new({}) end when 'channel_credentials' - test_proc = proc do + return proc do GRPC::Core::ChannelCredentials.new end when 'call_credentials' - test_proc = proc do + return proc do GRPC::Core::CallCredentials.new(proc { |noop| noop }) end when 'compression_options' - test_proc = proc do + return proc do GRPC::Core::CompressionOptions.new end else fail "bad --grpc_class=#{grpc_class} param" end +end + +def main + grpc_class = '' + gc_stress = false + OptionParser.new do |opts| + opts.on('--grpc_class=P', String) do |p| + grpc_class = p + end + opts.on('--gc_stress=P') do |p| + gc_stress = p + end + end.parse! + + test_proc = get_test_proc(grpc_class) + + if gc_stress == 'true' + run_gc_stress_test(test_proc) + return + end - th = Thread.new { test_proc.call } + thd = Thread.new { test_proc.call } test_proc.call - th.join + thd.join end main diff --git a/src/ruby/end2end/grpc_class_init_driver.rb b/src/ruby/end2end/grpc_class_init_driver.rb index 764d029f149..0e330a493f5 100755 --- a/src/ruby/end2end/grpc_class_init_driver.rb +++ b/src/ruby/end2end/grpc_class_init_driver.rb @@ -38,29 +38,38 @@ def main call_credentials compression_options ) - native_grpc_classes.each do |grpc_class| - STDERR.puts 'start client' - this_dir = File.expand_path(File.dirname(__FILE__)) - client_path = File.join(this_dir, 'grpc_class_init_client.rb') - client_pid = Process.spawn(RbConfig.ruby, - client_path, - "--grpc_class=#{grpc_class}") - begin - Timeout.timeout(10) do - Process.wait(client_pid) + # there is room for false positives in this test, + # do 10 runs for each config to reduce these. + [true, false].each do |gc_stress| + 10.times do + native_grpc_classes.each do |grpc_class| + STDERR.puts 'start client' + this_dir = File.expand_path(File.dirname(__FILE__)) + client_path = File.join(this_dir, 'grpc_class_init_client.rb') + client_pid = Process.spawn(RbConfig.ruby, + client_path, + "--grpc_class=#{grpc_class}", + "--gc_stress=#{gc_stress}") + begin + Timeout.timeout(10) do + Process.wait(client_pid) + end + rescue Timeout::Error + STDERR.puts "timeout waiting for client pid #{client_pid}" + Process.kill('SIGKILL', client_pid) + Process.wait(client_pid) + STDERR.puts 'killed client child' + raise 'Timed out waiting for client process. ' \ + 'It likely hangs when the first constructed gRPC object has ' \ + "type: #{grpc_class}" + end + + client_exit_code = $CHILD_STATUS + if client_exit_code != 0 + fail "client failed, exit code #{client_exit_code}" + end end - rescue Timeout::Error - STDERR.puts "timeout waiting for client pid #{client_pid}" - Process.kill('SIGKILL', client_pid) - Process.wait(client_pid) - STDERR.puts 'killed client child' - raise 'Timed out waiting for client process. ' \ - 'It likely hangs when the first constructed gRPC object has ' \ - "type: #{grpc_class}" end - - client_exit_code = $CHILD_STATUS - fail "client failed, exit code #{client_exit_code}" if client_exit_code != 0 end end diff --git a/src/ruby/end2end/sig_int_during_channel_watch_client.rb b/src/ruby/end2end/sig_int_during_channel_watch_client.rb index 389fc5ba332..0c6a3749254 100755 --- a/src/ruby/end2end/sig_int_during_channel_watch_client.rb +++ b/src/ruby/end2end/sig_int_during_channel_watch_client.rb @@ -46,6 +46,8 @@ def main end end.parse! + trap('SIGINT') { exit 0 } + thd = Thread.new do child_thread_channel = GRPC::Core::Channel.new("localhost:#{server_port}", {}, diff --git a/src/ruby/end2end/sig_int_during_channel_watch_driver.rb b/src/ruby/end2end/sig_int_during_channel_watch_driver.rb index 670cda0919f..79a8c133fa8 100755 --- a/src/ruby/end2end/sig_int_during_channel_watch_driver.rb +++ b/src/ruby/end2end/sig_int_during_channel_watch_driver.rb @@ -63,6 +63,11 @@ def main 'SIGINT is sent while there is an active connectivity_state call' end + client_exit_code = $CHILD_STATUS + if client_exit_code != 0 + fail "sig_int_during_channel_watch_client failed: #{client_exit_code}" + end + server_runner.stop end diff --git a/src/ruby/ext/grpc/rb_call.c b/src/ruby/ext/grpc/rb_call.c index 344cb941ffb..6cb71870f55 100644 --- a/src/ruby/ext/grpc/rb_call.c +++ b/src/ruby/ext/grpc/rb_call.c @@ -103,7 +103,7 @@ static void destroy_call(grpc_rb_call *call) { if (call->wrapped != NULL) { grpc_call_destroy(call->wrapped); call->wrapped = NULL; - grpc_rb_completion_queue_destroy(call->queue); + grpc_rb_completion_queue_safe_destroy(call->queue); call->queue = NULL; } } diff --git a/src/ruby/ext/grpc/rb_channel.c b/src/ruby/ext/grpc/rb_channel.c index fb610f548eb..973a45adf57 100644 --- a/src/ruby/ext/grpc/rb_channel.c +++ b/src/ruby/ext/grpc/rb_channel.c @@ -52,75 +52,131 @@ /* id_channel is the name of the hidden ivar that preserves a reference to the * channel on a call, so that calls are not GCed before their channel. */ -static ID id_channel; +ID id_channel; /* id_target is the name of the hidden ivar that preserves a reference to the * target string used to create the call, preserved so that it does not get * GCed before the channel */ -static ID id_target; +ID id_target; /* id_insecure_channel is used to indicate that a channel is insecure */ -static VALUE id_insecure_channel; +VALUE id_insecure_channel; /* grpc_rb_cChannel is the ruby class that proxies grpc_channel. */ -static VALUE grpc_rb_cChannel = Qnil; +VALUE grpc_rb_cChannel = Qnil; /* Used during the conversion of a hash to channel args during channel setup */ -static VALUE grpc_rb_cChannelArgs; +VALUE grpc_rb_cChannelArgs; + +typedef struct bg_watched_channel { + grpc_channel *channel; + struct bg_watched_channel *next; + int channel_destroyed; + int refcount; // must only be accessed under global_connection_polling_mu +} bg_watched_channel; /* grpc_rb_channel wraps a grpc_channel. */ typedef struct grpc_rb_channel { VALUE credentials; - /* The actual channel */ - grpc_channel *wrapped; - int request_safe_destroy; - int safe_to_destroy; - grpc_connectivity_state current_connectivity_state; - - int mu_init_done; - int abort_watch_connectivity_state; - gpr_mu channel_mu; - gpr_cv channel_cv; + /* The actual channel (protected in a wrapper to tell when it's safe to destroy) */ + bg_watched_channel *bg_wrapped; } grpc_rb_channel; -/* Forward declarations of functions involved in temporary fix to - * https://github.com/grpc/grpc/issues/9941 */ -static void grpc_rb_channel_try_register_connection_polling( - grpc_rb_channel *wrapper); -static void grpc_rb_channel_safe_destroy(grpc_rb_channel *wrapper); -static void *wait_until_channel_polling_thread_started_no_gil(void*); -static void wait_until_channel_polling_thread_started_unblocking_func(void*); +typedef enum { + CONTINUOUS_WATCH, + WATCH_STATE_API +} watch_state_op_type; + +typedef struct watch_state_op { + watch_state_op_type op_type; + // from event.success + union { + struct { + int success; + // has been called back due to a cq next call + int called_back; + } api_callback_args; + struct { + bg_watched_channel *bg; + } continuous_watch_callback_args; + } op; +} watch_state_op; + +bg_watched_channel *bg_watched_channel_list_head = NULL; + +void grpc_rb_channel_try_register_connection_polling(bg_watched_channel *bg); +void *wait_until_channel_polling_thread_started_no_gil(void*); +void wait_until_channel_polling_thread_started_unblocking_func(void*); +void *channel_init_try_register_connection_polling_without_gil(void *arg); + +typedef struct channel_init_try_register_stack { + grpc_channel *channel; + grpc_rb_channel *wrapper; +} channel_init_try_register_stack; + +grpc_completion_queue *channel_polling_cq; +gpr_mu global_connection_polling_mu; +gpr_cv global_connection_polling_cv; +int abort_channel_polling = 0; +int channel_polling_thread_started = 0; + +int bg_watched_channel_list_lookup(bg_watched_channel *bg); +bg_watched_channel *bg_watched_channel_list_create_and_add(grpc_channel *channel); +void bg_watched_channel_list_free_and_remove(bg_watched_channel *bg); +void run_poll_channels_loop_unblocking_func(void* arg); + +// Needs to be called under global_connection_polling_mu +void grpc_rb_channel_watch_connection_state_op_complete(watch_state_op* op, int success) { + GPR_ASSERT(!op->op.api_callback_args.called_back); + op->op.api_callback_args.called_back = 1; + op->op.api_callback_args.success = success; + // wake up the watch API call thats waiting on this op + gpr_cv_broadcast(&global_connection_polling_cv); +} + +/* Avoids destroying a channel twice. */ +void grpc_rb_channel_safe_destroy(bg_watched_channel *bg) { + gpr_mu_lock(&global_connection_polling_mu); + GPR_ASSERT(bg_watched_channel_list_lookup(bg)); + if (!bg->channel_destroyed) { + grpc_channel_destroy(bg->channel); + bg->channel_destroyed = 1; + } + bg->refcount--; + if (bg->refcount == 0) { + bg_watched_channel_list_free_and_remove(bg); + } + gpr_mu_unlock(&global_connection_polling_mu); +} -static grpc_completion_queue *channel_polling_cq; -static gpr_mu global_connection_polling_mu; -static gpr_cv global_connection_polling_cv; -static int abort_channel_polling = 0; -static int channel_polling_thread_started = 0; +void *channel_safe_destroy_without_gil(void *arg) { + grpc_rb_channel_safe_destroy((bg_watched_channel*)arg); + return NULL; +} /* Destroys Channel instances. */ -static void grpc_rb_channel_free(void *p) { +void grpc_rb_channel_free(void *p) { grpc_rb_channel *ch = NULL; if (p == NULL) { return; }; + gpr_log(GPR_DEBUG, "channel GC function called!"); ch = (grpc_rb_channel *)p; - if (ch->wrapped != NULL) { - grpc_rb_channel_safe_destroy(ch); - ch->wrapped = NULL; - } - - if (ch->mu_init_done) { - gpr_mu_destroy(&ch->channel_mu); - gpr_cv_destroy(&ch->channel_cv); + if (ch->bg_wrapped != NULL) { + /* assumption made here: it's ok to directly gpr_mu_lock the global + * connection polling mutex becuse we're in a finalizer, + * and we can count on this thread to not be interrupted. */ + grpc_rb_channel_safe_destroy(ch->bg_wrapped); + ch->bg_wrapped = NULL; } xfree(p); } /* Protects the mark object from GC */ -static void grpc_rb_channel_mark(void *p) { +void grpc_rb_channel_mark(void *p) { grpc_rb_channel *channel = NULL; if (p == NULL) { return; @@ -131,7 +187,7 @@ static void grpc_rb_channel_mark(void *p) { } } -static rb_data_type_t grpc_channel_data_type = {"grpc_channel", +rb_data_type_t grpc_channel_data_type = {"grpc_channel", {grpc_rb_channel_mark, grpc_rb_channel_free, GRPC_RB_MEMSIZE_UNAVAILABLE, @@ -144,9 +200,9 @@ static rb_data_type_t grpc_channel_data_type = {"grpc_channel", }; /* Allocates grpc_rb_channel instances. */ -static VALUE grpc_rb_channel_alloc(VALUE cls) { +VALUE grpc_rb_channel_alloc(VALUE cls) { grpc_rb_channel *wrapper = ALLOC(grpc_rb_channel); - wrapper->wrapped = NULL; + wrapper->bg_wrapped = NULL; wrapper->credentials = Qnil; return TypedData_Wrap_Struct(cls, &grpc_channel_data_type, wrapper); } @@ -159,7 +215,7 @@ static VALUE grpc_rb_channel_alloc(VALUE cls) { secure_channel = Channel:new("myhost:443", {'arg1': 'value1'}, creds) Creates channel instances. */ -static VALUE grpc_rb_channel_init(int argc, VALUE *argv, VALUE self) { +VALUE grpc_rb_channel_init(int argc, VALUE *argv, VALUE self) { VALUE channel_args = Qnil; VALUE credentials = Qnil; VALUE target = Qnil; @@ -168,6 +224,7 @@ static VALUE grpc_rb_channel_init(int argc, VALUE *argv, VALUE self) { grpc_channel_credentials *creds = NULL; char *target_chars = NULL; grpc_channel_args args; + channel_init_try_register_stack stack; MEMZERO(&args, grpc_channel_args, 1); grpc_ruby_once_init(); @@ -178,7 +235,6 @@ static VALUE grpc_rb_channel_init(int argc, VALUE *argv, VALUE self) { rb_scan_args(argc, argv, "3", &target, &channel_args, &credentials); TypedData_Get_Struct(self, grpc_rb_channel, &grpc_channel_data_type, wrapper); - wrapper->mu_init_done = 0; target_chars = StringValueCStr(target); grpc_rb_hash_convert_to_channel_args(channel_args, &args); if (TYPE(credentials) == T_SYMBOL) { @@ -195,24 +251,10 @@ static VALUE grpc_rb_channel_init(int argc, VALUE *argv, VALUE self) { } GPR_ASSERT(ch); - - wrapper->wrapped = ch; - - gpr_mu_init(&wrapper->channel_mu); - gpr_cv_init(&wrapper->channel_cv); - wrapper->mu_init_done = 1; - - gpr_mu_lock(&wrapper->channel_mu); - wrapper->abort_watch_connectivity_state = 0; - wrapper->current_connectivity_state = grpc_channel_check_connectivity_state(wrapper->wrapped, 0); - wrapper->safe_to_destroy = 0; - wrapper->request_safe_destroy = 0; - - gpr_cv_broadcast(&wrapper->channel_cv); - gpr_mu_unlock(&wrapper->channel_mu); - - - grpc_rb_channel_try_register_connection_polling(wrapper); + stack.channel = ch; + stack.wrapper = wrapper; + rb_thread_call_without_gvl( + channel_init_try_register_connection_polling_without_gil, &stack, NULL, NULL); if (args.args != NULL) { xfree(args.args); /* Allocated by grpc_rb_hash_convert_to_channel_args */ @@ -223,10 +265,32 @@ static VALUE grpc_rb_channel_init(int argc, VALUE *argv, VALUE self) { return Qnil; } rb_ivar_set(self, id_target, target); - wrapper->wrapped = ch; return self; } +typedef struct get_state_stack { + grpc_channel *channel; + int try_to_connect; + int out; +} get_state_stack; + +void *get_state_without_gil(void *arg) { + get_state_stack *stack = (get_state_stack*)arg; + + gpr_mu_lock(&global_connection_polling_mu); + GPR_ASSERT(abort_channel_polling || channel_polling_thread_started); + if (abort_channel_polling) { + // the case in which the channel polling thread + // failed to start just always shows shutdown state. + stack->out = GRPC_CHANNEL_SHUTDOWN; + } else { + stack->out = grpc_channel_check_connectivity_state(stack->channel, stack->try_to_connect); + } + gpr_mu_unlock(&global_connection_polling_mu); + + return NULL; +} + /* call-seq: ch.connectivity_state -> state @@ -236,62 +300,66 @@ static VALUE grpc_rb_channel_init(int argc, VALUE *argv, VALUE self) { constants defined in GRPC::Core::ConnectivityStates. It also tries to connect if the chennel is idle in the second form. */ -static VALUE grpc_rb_channel_get_connectivity_state(int argc, VALUE *argv, +VALUE grpc_rb_channel_get_connectivity_state(int argc, VALUE *argv, VALUE self) { VALUE try_to_connect_param = Qfalse; int grpc_try_to_connect = 0; grpc_rb_channel *wrapper = NULL; - grpc_channel *ch = NULL; + get_state_stack stack; /* "01" == 0 mandatory args, 1 (try_to_connect) is optional */ rb_scan_args(argc, argv, "01", &try_to_connect_param); grpc_try_to_connect = RTEST(try_to_connect_param) ? 1 : 0; TypedData_Get_Struct(self, grpc_rb_channel, &grpc_channel_data_type, wrapper); - ch = wrapper->wrapped; - if (ch == NULL) { + if (wrapper->bg_wrapped == NULL) { rb_raise(rb_eRuntimeError, "closed!"); return Qnil; } - return LONG2NUM(grpc_channel_check_connectivity_state(wrapper->wrapped, grpc_try_to_connect)); + + stack.channel = wrapper->bg_wrapped->channel; + stack.try_to_connect = grpc_try_to_connect; + rb_thread_call_without_gvl(get_state_without_gil, &stack, NULL, NULL); + + return LONG2NUM(stack.out); } typedef struct watch_state_stack { - grpc_rb_channel *wrapper; + grpc_channel *channel; gpr_timespec deadline; int last_state; } watch_state_stack; -static void *watch_channel_state_without_gvl(void *arg) { +void *wait_for_watch_state_op_complete_without_gvl(void *arg) { watch_state_stack *stack = (watch_state_stack*)arg; - gpr_timespec deadline = stack->deadline; - grpc_rb_channel *wrapper = stack->wrapper; - int last_state = stack->last_state; - void *return_value = (void*)0; + watch_state_op *op = NULL; + void *success = (void*)0; - gpr_mu_lock(&wrapper->channel_mu); - while(wrapper->current_connectivity_state == last_state && - !wrapper->request_safe_destroy && - !wrapper->safe_to_destroy && - !wrapper->abort_watch_connectivity_state && - gpr_time_cmp(deadline, gpr_now(GPR_CLOCK_REALTIME)) > 0) { - gpr_cv_wait(&wrapper->channel_cv, &wrapper->channel_mu, deadline); + gpr_mu_lock(&global_connection_polling_mu); + // its unsafe to do a "watch" after "channel polling abort" because the cq has + // been shut down. + if (abort_channel_polling) { + gpr_mu_unlock(&global_connection_polling_mu); + return (void*)0; + } + op = gpr_zalloc(sizeof(watch_state_op)); + op->op_type = WATCH_STATE_API; + // one ref for this thread and another for the callback-running thread + grpc_channel_watch_connectivity_state( + stack->channel, stack->last_state, stack->deadline, channel_polling_cq, op); + + while(!op->op.api_callback_args.called_back) { + gpr_cv_wait(&global_connection_polling_cv, + &global_connection_polling_mu, + gpr_inf_future(GPR_CLOCK_REALTIME)); } - if (wrapper->current_connectivity_state != last_state) { - return_value = (void*)1; + if (op->op.api_callback_args.success) { + success = (void*)1; } - gpr_mu_unlock(&wrapper->channel_mu); - - return return_value; -} + gpr_free(op); + gpr_mu_unlock(&global_connection_polling_mu); -static void watch_channel_state_unblocking_func(void *arg) { - grpc_rb_channel *wrapper = (grpc_rb_channel*)arg; - gpr_log(GPR_DEBUG, "GRPC_RUBY: watch channel state unblocking func called"); - gpr_mu_lock(&wrapper->channel_mu); - wrapper->abort_watch_connectivity_state = 1; - gpr_cv_broadcast(&wrapper->channel_cv); - gpr_mu_unlock(&wrapper->channel_mu); + return success; } /* Wait until the channel's connectivity state becomes different from @@ -301,16 +369,16 @@ static void watch_channel_state_unblocking_func(void *arg) { * Returns false if "deadline" expires before the channel's connectivity * state changes from "last_state". * */ -static VALUE grpc_rb_channel_watch_connectivity_state(VALUE self, +VALUE grpc_rb_channel_watch_connectivity_state(VALUE self, VALUE last_state, VALUE deadline) { grpc_rb_channel *wrapper = NULL; watch_state_stack stack; - void* out; + void* op_success = 0; TypedData_Get_Struct(self, grpc_rb_channel, &grpc_channel_data_type, wrapper); - if (wrapper->wrapped == NULL) { + if (wrapper->bg_wrapped == NULL) { rb_raise(rb_eRuntimeError, "closed!"); return Qnil; } @@ -320,26 +388,25 @@ static VALUE grpc_rb_channel_watch_connectivity_state(VALUE self, return Qnil; } - stack.wrapper = wrapper; - stack.deadline = grpc_rb_time_timeval(deadline, 0); + stack.channel = wrapper->bg_wrapped->channel; + stack.deadline = grpc_rb_time_timeval(deadline, 0), stack.last_state = NUM2LONG(last_state); - out = rb_thread_call_without_gvl(watch_channel_state_without_gvl, &stack, watch_channel_state_unblocking_func, wrapper); - if (out) { - return Qtrue; - } - return Qfalse; + + op_success = rb_thread_call_without_gvl( + wait_for_watch_state_op_complete_without_gvl, &stack, run_poll_channels_loop_unblocking_func, NULL); + + return op_success ? Qtrue : Qfalse; } /* Create a call given a grpc_channel, in order to call method. The request is not sent until grpc_call_invoke is called. */ -static VALUE grpc_rb_channel_create_call(VALUE self, VALUE parent, VALUE mask, +VALUE grpc_rb_channel_create_call(VALUE self, VALUE parent, VALUE mask, VALUE method, VALUE host, VALUE deadline) { VALUE res = Qnil; grpc_rb_channel *wrapper = NULL; grpc_call *call = NULL; grpc_call *parent_call = NULL; - grpc_channel *ch = NULL; grpc_completion_queue *cq = NULL; int flags = GRPC_PROPAGATE_DEFAULTS; grpc_slice method_slice; @@ -361,8 +428,7 @@ static VALUE grpc_rb_channel_create_call(VALUE self, VALUE parent, VALUE mask, cq = grpc_completion_queue_create(NULL); TypedData_Get_Struct(self, grpc_rb_channel, &grpc_channel_data_type, wrapper); - ch = wrapper->wrapped; - if (ch == NULL) { + if (wrapper->bg_wrapped == NULL) { rb_raise(rb_eRuntimeError, "closed!"); return Qnil; } @@ -370,7 +436,7 @@ static VALUE grpc_rb_channel_create_call(VALUE self, VALUE parent, VALUE mask, method_slice = grpc_slice_from_copied_buffer(RSTRING_PTR(method), RSTRING_LEN(method)); - call = grpc_channel_create_call(ch, parent_call, flags, cq, method_slice, + call = grpc_channel_create_call(wrapper->bg_wrapped->channel, parent_call, flags, cq, method_slice, host_slice_ptr, grpc_rb_time_timeval(deadline, /* absolute time */ 0), @@ -396,85 +462,132 @@ static VALUE grpc_rb_channel_create_call(VALUE self, VALUE parent, VALUE mask, } /* Closes the channel, calling it's destroy method */ -static VALUE grpc_rb_channel_destroy(VALUE self) { +/* Note this is an API-level call; a wrapped channel's finalizer doesn't call + * this */ +VALUE grpc_rb_channel_destroy(VALUE self) { grpc_rb_channel *wrapper = NULL; - grpc_channel *ch = NULL; TypedData_Get_Struct(self, grpc_rb_channel, &grpc_channel_data_type, wrapper); - ch = wrapper->wrapped; - if (ch != NULL) { - grpc_rb_channel_safe_destroy(wrapper); - wrapper->wrapped = NULL; + if (wrapper->bg_wrapped != NULL) { + rb_thread_call_without_gvl( + channel_safe_destroy_without_gil, wrapper->bg_wrapped, NULL, NULL); + wrapper->bg_wrapped = NULL; } return Qnil; } /* Called to obtain the target that this channel accesses. */ -static VALUE grpc_rb_channel_get_target(VALUE self) { +VALUE grpc_rb_channel_get_target(VALUE self) { grpc_rb_channel *wrapper = NULL; VALUE res = Qnil; char *target = NULL; TypedData_Get_Struct(self, grpc_rb_channel, &grpc_channel_data_type, wrapper); - target = grpc_channel_get_target(wrapper->wrapped); + target = grpc_channel_get_target(wrapper->bg_wrapped->channel); res = rb_str_new2(target); gpr_free(target); return res; } -// Either start polling channel connection state or signal that it's free to -// destroy. -// Not safe to call while a channel's connection state is polled. -static void grpc_rb_channel_try_register_connection_polling( - grpc_rb_channel *wrapper) { - grpc_connectivity_state conn_state; - gpr_timespec sleep_time = gpr_time_add( - gpr_now(GPR_CLOCK_REALTIME), gpr_time_from_millis(20, GPR_TIMESPAN)); - - GPR_ASSERT(wrapper); - GPR_ASSERT(wrapper->wrapped); - gpr_mu_lock(&wrapper->channel_mu); - if (wrapper->request_safe_destroy) { - wrapper->safe_to_destroy = 1; - gpr_cv_broadcast(&wrapper->channel_cv); - gpr_mu_unlock(&wrapper->channel_mu); - return; +/* Needs to be called under global_connection_polling_mu */ +int bg_watched_channel_list_lookup(bg_watched_channel *target) { + bg_watched_channel *cur = bg_watched_channel_list_head; + + gpr_log(GPR_DEBUG, "check contains"); + while (cur != NULL) { + if (cur == target) { + return 1; + } + cur = cur->next; } - gpr_mu_lock(&global_connection_polling_mu); - GPR_ASSERT(channel_polling_thread_started || abort_channel_polling); - conn_state = grpc_channel_check_connectivity_state(wrapper->wrapped, 0); - if (conn_state != wrapper->current_connectivity_state) { - wrapper->current_connectivity_state = conn_state; - gpr_cv_broadcast(&wrapper->channel_cv); - } - // avoid posting work to the channel polling cq if it's been shutdown - if (!abort_channel_polling && conn_state != GRPC_CHANNEL_SHUTDOWN) { - grpc_channel_watch_connectivity_state( - wrapper->wrapped, conn_state, sleep_time, channel_polling_cq, wrapper); - } else { - wrapper->safe_to_destroy = 1; - gpr_cv_broadcast(&wrapper->channel_cv); + return 0; +} + +/* Needs to be called under global_connection_polling_mu */ +bg_watched_channel *bg_watched_channel_list_create_and_add(grpc_channel *channel) { + bg_watched_channel *watched = gpr_zalloc(sizeof(bg_watched_channel)); + + gpr_log(GPR_DEBUG, "add bg"); + watched->channel = channel; + watched->next = bg_watched_channel_list_head; + watched->refcount = 1; + bg_watched_channel_list_head = watched; + return watched; +} + +/* Needs to be called under global_connection_polling_mu */ +void bg_watched_channel_list_free_and_remove(bg_watched_channel *target) { + bg_watched_channel *bg = NULL; + + gpr_log(GPR_DEBUG, "remove bg"); + GPR_ASSERT(bg_watched_channel_list_lookup(target)); + GPR_ASSERT(target->channel_destroyed && target->refcount == 0); + if (bg_watched_channel_list_head == target) { + bg_watched_channel_list_head = target->next; + gpr_free(target); + return; + } + bg = bg_watched_channel_list_head; + while (bg != NULL && bg->next != NULL) { + if (bg->next == target) { + bg->next = bg->next->next; + gpr_free(target); + return; + } + bg = bg->next; } + GPR_ASSERT(0); +} + +/* Initialize a grpc_rb_channel's "protected grpc_channel" and try to push + * it onto the background thread for constant watches. */ +void *channel_init_try_register_connection_polling_without_gil(void *arg) { + channel_init_try_register_stack *stack = (channel_init_try_register_stack*)arg; + + gpr_mu_lock(&global_connection_polling_mu); + stack->wrapper->bg_wrapped = bg_watched_channel_list_create_and_add(stack->channel); + grpc_rb_channel_try_register_connection_polling(stack->wrapper->bg_wrapped); gpr_mu_unlock(&global_connection_polling_mu); - gpr_mu_unlock(&wrapper->channel_mu); + return NULL; } -// Note requires wrapper->wrapped, wrapper->channel_mu/cv initialized -static void grpc_rb_channel_safe_destroy(grpc_rb_channel *wrapper) { - gpr_mu_lock(&wrapper->channel_mu); - wrapper->request_safe_destroy = 1; +// Needs to be called under global_connection_poolling_mu +void grpc_rb_channel_try_register_connection_polling(bg_watched_channel *bg) { + grpc_connectivity_state conn_state; + watch_state_op *op = NULL; - while (!wrapper->safe_to_destroy) { - gpr_cv_wait(&wrapper->channel_cv, &wrapper->channel_mu, - gpr_inf_future(GPR_CLOCK_REALTIME)); + GPR_ASSERT(channel_polling_thread_started || abort_channel_polling); + + if (bg->refcount == 0) { + GPR_ASSERT(bg->channel_destroyed); + bg_watched_channel_list_free_and_remove(bg); + return; + } + GPR_ASSERT(bg->refcount == 1); + if (bg->channel_destroyed) { + GPR_ASSERT(abort_channel_polling); + return; + } + if (abort_channel_polling) { + return; } - GPR_ASSERT(wrapper->safe_to_destroy); - gpr_mu_unlock(&wrapper->channel_mu); - grpc_channel_destroy(wrapper->wrapped); + conn_state = grpc_channel_check_connectivity_state(bg->channel, 0); + if (conn_state == GRPC_CHANNEL_SHUTDOWN) { + return; + } + GPR_ASSERT(bg_watched_channel_list_lookup(bg)); + // prevent bg from being free'd by GC while background thread is watching it + bg->refcount++; + + op = gpr_zalloc(sizeof(watch_state_op)); + op->op_type = CONTINUOUS_WATCH; + op->op.continuous_watch_callback_args.bg = bg; + grpc_channel_watch_connectivity_state( + bg->channel, conn_state, gpr_inf_future(GPR_CLOCK_REALTIME), channel_polling_cq, op); } // Note this loop breaks out with a single call of @@ -483,8 +596,10 @@ static void grpc_rb_channel_safe_destroy(grpc_rb_channel *wrapper) { // indicates process shutdown. // In the worst case, this stops polling channel connectivity // early and falls back to current behavior. -static void *run_poll_channels_loop_no_gil(void *arg) { +void *run_poll_channels_loop_no_gil(void *arg) { grpc_event event; + watch_state_op *op = NULL; + bg_watched_channel *bg = NULL; (void)arg; gpr_log(GPR_DEBUG, "GRPC_RUBY: run_poll_channels_loop_no_gil - begin"); @@ -500,9 +615,21 @@ static void *run_poll_channels_loop_no_gil(void *arg) { if (event.type == GRPC_QUEUE_SHUTDOWN) { break; } + gpr_mu_lock(&global_connection_polling_mu); if (event.type == GRPC_OP_COMPLETE) { - grpc_rb_channel_try_register_connection_polling((grpc_rb_channel *)event.tag); + op = (watch_state_op*)event.tag; + if (op->op_type == CONTINUOUS_WATCH) { + bg = (bg_watched_channel*)op->op.continuous_watch_callback_args.bg; + bg->refcount--; + grpc_rb_channel_try_register_connection_polling(bg); + gpr_free(op); + } else if(op->op_type == WATCH_STATE_API) { + grpc_rb_channel_watch_connection_state_op_complete((watch_state_op*)event.tag, event.success); + } else { + GPR_ASSERT(0); + } } + gpr_mu_unlock(&global_connection_polling_mu); } grpc_completion_queue_destroy(channel_polling_cq); gpr_log(GPR_DEBUG, "GRPC_RUBY: run_poll_channels_loop_no_gil - exit connection polling loop"); @@ -510,17 +637,37 @@ static void *run_poll_channels_loop_no_gil(void *arg) { } // Notify the channel polling loop to cleanup and shutdown. -static void run_poll_channels_loop_unblocking_func(void *arg) { +void run_poll_channels_loop_unblocking_func(void *arg) { + bg_watched_channel *bg = NULL; (void)arg; + gpr_mu_lock(&global_connection_polling_mu); gpr_log(GPR_DEBUG, "GRPC_RUBY: run_poll_channels_loop_unblocking_func - begin aborting connection polling"); + // early out after first time through + if (abort_channel_polling) { + gpr_mu_unlock(&global_connection_polling_mu); + return; + } abort_channel_polling = 1; + + // force pending watches to end by switching to shutdown state + bg = bg_watched_channel_list_head; + while(bg != NULL) { + if (!bg->channel_destroyed) { + grpc_channel_destroy(bg->channel); + bg->channel_destroyed = 1; + } + bg = bg->next; + } + grpc_completion_queue_shutdown(channel_polling_cq); + gpr_cv_broadcast(&global_connection_polling_cv); gpr_mu_unlock(&global_connection_polling_mu); + gpr_log(GPR_DEBUG, "GRPC_RUBY: run_poll_channels_loop_unblocking_func - begin aborting connection polling 22222"); } // Poll channel connectivity states in background thread without the GIL. -static VALUE run_poll_channels_loop(VALUE arg) { +VALUE run_poll_channels_loop(VALUE arg) { (void)arg; gpr_log(GPR_DEBUG, "GRPC_RUBY: run_poll_channels_loop - create connection polling thread"); rb_thread_call_without_gvl(run_poll_channels_loop_no_gil, NULL, @@ -529,7 +676,7 @@ static VALUE run_poll_channels_loop(VALUE arg) { return Qnil; } -static void *wait_until_channel_polling_thread_started_no_gil(void *arg) { +void *wait_until_channel_polling_thread_started_no_gil(void *arg) { (void)arg; gpr_log(GPR_DEBUG, "GRPC_RUBY: wait for channel polling thread to start"); gpr_mu_lock(&global_connection_polling_mu); @@ -542,7 +689,7 @@ static void *wait_until_channel_polling_thread_started_no_gil(void *arg) { return NULL; } -static void wait_until_channel_polling_thread_started_unblocking_func(void* arg) { +void wait_until_channel_polling_thread_started_unblocking_func(void* arg) { (void)arg; gpr_mu_lock(&global_connection_polling_mu); gpr_log(GPR_DEBUG, "GRPC_RUBY: wait_until_channel_polling_thread_started_unblocking_func - begin aborting connection polling"); @@ -551,6 +698,16 @@ static void wait_until_channel_polling_thread_started_unblocking_func(void* arg) gpr_mu_unlock(&global_connection_polling_mu); } +static void *set_abort_channel_polling_without_gil(void *arg) { + (void)arg; + gpr_mu_lock(&global_connection_polling_mu); + abort_channel_polling = 1; + gpr_cv_broadcast(&global_connection_polling_cv); + gpr_mu_unlock(&global_connection_polling_mu); + return NULL; +} + + /* Temporary fix for * https://github.com/GoogleCloudPlatform/google-cloud-ruby/issues/899. * Transports in idle channels can get destroyed. Normally c-core re-connects, @@ -576,14 +733,11 @@ void grpc_rb_channel_polling_thread_start() { if (!RTEST(background_thread)) { gpr_log(GPR_DEBUG, "GRPC_RUBY: failed to spawn channel polling thread"); - gpr_mu_lock(&global_connection_polling_mu); - abort_channel_polling = 1; - gpr_cv_broadcast(&global_connection_polling_cv); - gpr_mu_unlock(&global_connection_polling_mu); + rb_thread_call_without_gvl(set_abort_channel_polling_without_gil, NULL, NULL, NULL); } } -static void Init_grpc_propagate_masks() { +void Init_grpc_propagate_masks() { /* Constants representing call propagation masks in grpc.h */ VALUE grpc_rb_mPropagateMasks = rb_define_module_under(grpc_rb_mGrpcCore, "PropagateMasks"); @@ -599,7 +753,7 @@ static void Init_grpc_propagate_masks() { UINT2NUM(GRPC_PROPAGATE_DEFAULTS)); } -static void Init_grpc_connectivity_states() { +void Init_grpc_connectivity_states() { /* Constants representing call propagation masks in grpc.h */ VALUE grpc_rb_mConnectivityStates = rb_define_module_under(grpc_rb_mGrpcCore, "ConnectivityStates"); @@ -658,5 +812,5 @@ void Init_grpc_channel() { grpc_channel *grpc_rb_get_wrapped_channel(VALUE v) { grpc_rb_channel *wrapper = NULL; TypedData_Get_Struct(v, grpc_rb_channel, &grpc_channel_data_type, wrapper); - return wrapper->wrapped; + return wrapper->bg_wrapped->channel; } diff --git a/src/ruby/ext/grpc/rb_completion_queue.c b/src/ruby/ext/grpc/rb_completion_queue.c index fd75d2f691f..9f3a81b1a8b 100644 --- a/src/ruby/ext/grpc/rb_completion_queue.c +++ b/src/ruby/ext/grpc/rb_completion_queue.c @@ -71,12 +71,16 @@ static void *grpc_rb_completion_queue_pluck_no_gil(void *param) { } /* Helper function to free a completion queue. */ -void grpc_rb_completion_queue_destroy(grpc_completion_queue *cq) { - /* Every function that adds an event to a queue also synchronously plucks - that event from the queue, and holds a reference to the Ruby object that - holds the queue, so we only get to this point if all of those functions - have completed, and the queue is empty */ +void grpc_rb_completion_queue_safe_destroy(grpc_completion_queue *cq) { + grpc_event ev; + grpc_completion_queue_shutdown(cq); + for(;;) { + ev = grpc_completion_queue_pluck(cq, NULL, gpr_inf_future(GPR_CLOCK_REALTIME), NULL); + if (ev.type == GRPC_QUEUE_SHUTDOWN) { + break; + } + } grpc_completion_queue_destroy(cq); } diff --git a/src/ruby/ext/grpc/rb_completion_queue.h b/src/ruby/ext/grpc/rb_completion_queue.h index aa9dc6416af..eb041b28dfc 100644 --- a/src/ruby/ext/grpc/rb_completion_queue.h +++ b/src/ruby/ext/grpc/rb_completion_queue.h @@ -38,7 +38,7 @@ #include -void grpc_rb_completion_queue_destroy(grpc_completion_queue *cq); +void grpc_rb_completion_queue_safe_destroy(grpc_completion_queue *cq); /** * Makes the implementation of CompletionQueue#pluck available in other files diff --git a/src/ruby/ext/grpc/rb_event_thread.c b/src/ruby/ext/grpc/rb_event_thread.c index 9e85bbcfbf2..f1a08a7b23d 100644 --- a/src/ruby/ext/grpc/rb_event_thread.c +++ b/src/ruby/ext/grpc/rb_event_thread.c @@ -106,17 +106,17 @@ static void *grpc_rb_wait_for_event_no_gil(void *param) { grpc_rb_event *event = NULL; (void)param; gpr_mu_lock(&event_queue.mu); - while ((event = grpc_rb_event_queue_dequeue()) == NULL) { + while (!event_queue.abort) { + if ((event = grpc_rb_event_queue_dequeue()) != NULL) { + gpr_mu_unlock(&event_queue.mu); + return event; + } gpr_cv_wait(&event_queue.cv, &event_queue.mu, gpr_inf_future(GPR_CLOCK_REALTIME)); - if (event_queue.abort) { - gpr_mu_unlock(&event_queue.mu); - return NULL; - } } gpr_mu_unlock(&event_queue.mu); - return event; + return NULL; } static void grpc_rb_event_unblocking_func(void *arg) { diff --git a/src/ruby/ext/grpc/rb_server.c b/src/ruby/ext/grpc/rb_server.c index 2286a99f249..2b0858c247e 100644 --- a/src/ruby/ext/grpc/rb_server.c +++ b/src/ruby/ext/grpc/rb_server.c @@ -77,7 +77,7 @@ static void destroy_server(grpc_rb_server *server, gpr_timespec deadline) { gpr_inf_future(GPR_CLOCK_REALTIME), NULL); } grpc_server_destroy(server->wrapped); - grpc_rb_completion_queue_destroy(server->queue); + grpc_rb_completion_queue_safe_destroy(server->queue); server->wrapped = NULL; server->queue = NULL; } diff --git a/src/ruby/spec/channel_connection_spec.rb b/src/ruby/spec/channel_connection_spec.rb index 940d68b9b04..b3edec8f938 100644 --- a/src/ruby/spec/channel_connection_spec.rb +++ b/src/ruby/spec/channel_connection_spec.rb @@ -28,6 +28,10 @@ # OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. require 'grpc' +require 'timeout' + +include Timeout +include GRPC::Core # A test message class EchoMsg @@ -62,7 +66,7 @@ end EchoStub = EchoService.rpc_stub_class def start_server(port = 0) - @srv = GRPC::RpcServer.new + @srv = GRPC::RpcServer.new(pool_size: 1) server_port = @srv.add_http2_port("localhost:#{port}", :this_port_is_insecure) @srv.handle(EchoService) @server_thd = Thread.new { @srv.run } @@ -138,4 +142,33 @@ describe 'channel connection behavior' do stop_server end + + it 'observably connects and reconnects to transient server' \ + ' when using the channel state API' do + timeout(180) do + port = start_server + ch = GRPC::Core::Channel.new("localhost:#{port}", {}, + :this_channel_is_insecure) + stop_server + + thds = [] + 50.times do + thds << Thread.new do + while ch.connectivity_state(true) != ConnectivityStates::READY + ch.watch_connectivity_state( + ConnectivityStates::READY, Time.now + 60) + break + end + end + end + + sleep 0.01 + + start_server(port) + + thds.each(&:join) + + stop_server + end + end end From 8d18c6edfbe675cbee6c425690c2e32b7dccba9d Mon Sep 17 00:00:00 2001 From: murgatroid99 Date: Mon, 15 May 2017 14:39:05 -0700 Subject: [PATCH 03/45] Fix race between destroying call after status and handling write failure --- src/node/ext/call.cc | 8 ++++++++ src/node/src/client.js | 12 ++++++++++-- 2 files changed, 18 insertions(+), 2 deletions(-) diff --git a/src/node/ext/call.cc b/src/node/ext/call.cc index 8877995f8f2..2cc9f63b659 100644 --- a/src/node/ext/call.cc +++ b/src/node/ext/call.cc @@ -721,6 +721,14 @@ NAN_METHOD(Call::StartBatch) { } Local callback_func = info[1].As(); Call *call = ObjectWrap::Unwrap(info.This()); + if (call->wrapped_call == NULL) { + /* This implies that the call has completed and has been destroyed. To emulate + * previous behavior, we should call the callback immediately with an error, + * as though the batch had failed in core */ + Local argv[] = {Nan::Error("The async function failed because the call has completed")}; + Nan::Call(callback_func, Nan::New(), 1, argv); + return; + } Local obj = Nan::To(info[0]).ToLocalChecked(); Local keys = Nan::GetOwnPropertyNames(obj).ToLocalChecked(); size_t nops = keys->Length(); diff --git a/src/node/src/client.js b/src/node/src/client.js index 1aaf35c16cb..aa818349daa 100644 --- a/src/node/src/client.js +++ b/src/node/src/client.js @@ -100,6 +100,12 @@ function _write(chunk, encoding, callback) { /* jshint validthis: true */ var batch = {}; var message; + var self = this; + if (this.writeFailed) { + /* Once a write fails, just call the callback immediately to let the caller + flush any pending writes. */ + callback(); + } try { message = this.serialize(chunk); } catch (e) { @@ -119,8 +125,10 @@ function _write(chunk, encoding, callback) { batch[grpc.opType.SEND_MESSAGE] = message; this.call.startBatch(batch, function(err, event) { if (err) { - // Something has gone wrong. Stop writing by failing to call callback - return; + /* Assume that the call is complete and that writing failed because a + status was received. In that case, set a flag to discard all future + writes */ + self.writeFailed = true; } callback(); }); From 94ab1b55bfb29e19f5972d58b5cb7c194b9ae070 Mon Sep 17 00:00:00 2001 From: David Garcia Quintas Date: Mon, 15 May 2017 15:27:11 -0700 Subject: [PATCH 04/45] Make ServerBuilder accept (dns:///) URIs instead of just dns names --- include/grpc++/server_builder.h | 7 ++++--- src/cpp/server/server_builder.cc | 9 ++++++++- 2 files changed, 12 insertions(+), 4 deletions(-) diff --git a/include/grpc++/server_builder.h b/include/grpc++/server_builder.h index a56f81dc4b3..b29d9606bcd 100644 --- a/include/grpc++/server_builder.h +++ b/include/grpc++/server_builder.h @@ -142,14 +142,15 @@ class ServerBuilder { /// /// It can be invoked multiple times. /// - /// \param addr The address to try to bind to the server (eg, localhost:1234, - /// 192.168.1.1:31416, [::1]:27182, etc.). + /// \param addr_uri The address to try to bind to the server in URI form. If + /// the scheme name is omitted, "dns:///" is assumed. Valid values include + /// dns:///localhost:1234, / 192.168.1.1:31416, dns:///[::1]:27182, etc.). /// \params creds The credentials associated with the server. /// \param selected_port[out] Upon success, updated to contain the port /// number. \a nullptr otherwise. /// // TODO(dgq): the "port" part seems to be a misnomer. - ServerBuilder& AddListeningPort(const grpc::string& addr, + ServerBuilder& AddListeningPort(const grpc::string& addr_uri, std::shared_ptr creds, int* selected_port = nullptr); diff --git a/src/cpp/server/server_builder.cc b/src/cpp/server/server_builder.cc index 2ead048a1ff..87fa1dfb60c 100644 --- a/src/cpp/server/server_builder.cc +++ b/src/cpp/server/server_builder.cc @@ -172,8 +172,15 @@ ServerBuilder& ServerBuilder::SetResourceQuota( } ServerBuilder& ServerBuilder::AddListeningPort( - const grpc::string& addr, std::shared_ptr creds, + const grpc::string& addr_uri, std::shared_ptr creds, int* selected_port) { + const grpc::string uri_scheme = "dns:"; + grpc::string addr = addr_uri; + if (addr_uri.compare(0, uri_scheme.size(), uri_scheme) == 0) { + size_t pos = uri_scheme.size(); + while (addr_uri[pos] == '/') ++pos; // Skip slashes. + addr = addr_uri.substr(pos); + } Port port = {addr, creds, selected_port}; ports_.push_back(port); return *this; From d822e2f5cf8d32efd0008c967551e994046b2d73 Mon Sep 17 00:00:00 2001 From: murgatroid99 Date: Tue, 16 May 2017 12:53:57 -0700 Subject: [PATCH 05/45] Change write callback to asynchronous to avoid recursion --- src/node/src/client.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/node/src/client.js b/src/node/src/client.js index aa818349daa..2073d3eea8d 100644 --- a/src/node/src/client.js +++ b/src/node/src/client.js @@ -104,7 +104,7 @@ function _write(chunk, encoding, callback) { if (this.writeFailed) { /* Once a write fails, just call the callback immediately to let the caller flush any pending writes. */ - callback(); + setImmediate(callback); } try { message = this.serialize(chunk); From 0e2b6a2109fdb53884094de6c2395bd49fbf13e1 Mon Sep 17 00:00:00 2001 From: Alexander Polcyn Date: Tue, 16 May 2017 17:16:05 -0700 Subject: [PATCH 06/45] remove debug prints --- src/ruby/ext/grpc/rb_channel.c | 4 ---- 1 file changed, 4 deletions(-) diff --git a/src/ruby/ext/grpc/rb_channel.c b/src/ruby/ext/grpc/rb_channel.c index 973a45adf57..c96dc672ce2 100644 --- a/src/ruby/ext/grpc/rb_channel.c +++ b/src/ruby/ext/grpc/rb_channel.c @@ -161,7 +161,6 @@ void grpc_rb_channel_free(void *p) { if (p == NULL) { return; }; - gpr_log(GPR_DEBUG, "channel GC function called!"); ch = (grpc_rb_channel *)p; if (ch->bg_wrapped != NULL) { @@ -495,7 +494,6 @@ VALUE grpc_rb_channel_get_target(VALUE self) { int bg_watched_channel_list_lookup(bg_watched_channel *target) { bg_watched_channel *cur = bg_watched_channel_list_head; - gpr_log(GPR_DEBUG, "check contains"); while (cur != NULL) { if (cur == target) { return 1; @@ -510,7 +508,6 @@ int bg_watched_channel_list_lookup(bg_watched_channel *target) { bg_watched_channel *bg_watched_channel_list_create_and_add(grpc_channel *channel) { bg_watched_channel *watched = gpr_zalloc(sizeof(bg_watched_channel)); - gpr_log(GPR_DEBUG, "add bg"); watched->channel = channel; watched->next = bg_watched_channel_list_head; watched->refcount = 1; @@ -522,7 +519,6 @@ bg_watched_channel *bg_watched_channel_list_create_and_add(grpc_channel *channel void bg_watched_channel_list_free_and_remove(bg_watched_channel *target) { bg_watched_channel *bg = NULL; - gpr_log(GPR_DEBUG, "remove bg"); GPR_ASSERT(bg_watched_channel_list_lookup(target)); GPR_ASSERT(target->channel_destroyed && target->refcount == 0); if (bg_watched_channel_list_head == target) { From 7b3629e6c2570686701b4bdb6b171b219cbad06e Mon Sep 17 00:00:00 2001 From: Alexander Polcyn Date: Wed, 17 May 2017 00:29:10 -0700 Subject: [PATCH 07/45] fix lack-of-abort bug --- src/ruby/end2end/grpc_class_init_client.rb | 16 +++++++++++++--- src/ruby/ext/grpc/rb_channel.c | 12 +----------- 2 files changed, 14 insertions(+), 14 deletions(-) diff --git a/src/ruby/end2end/grpc_class_init_client.rb b/src/ruby/end2end/grpc_class_init_client.rb index 8e46907368f..62afc85b1d0 100755 --- a/src/ruby/end2end/grpc_class_init_client.rb +++ b/src/ruby/end2end/grpc_class_init_client.rb @@ -106,9 +106,19 @@ def main return end - thd = Thread.new { test_proc.call } - test_proc.call - thd.join +# test_proc.call + + thds = [] + 100.times do + thds << Thread.new do + test_proc.call + sleep 10 + end + end + + #test_proc.call + raise "something" + thds.each(&:join) end main diff --git a/src/ruby/ext/grpc/rb_channel.c b/src/ruby/ext/grpc/rb_channel.c index c96dc672ce2..748fe663ed9 100644 --- a/src/ruby/ext/grpc/rb_channel.c +++ b/src/ruby/ext/grpc/rb_channel.c @@ -107,7 +107,6 @@ bg_watched_channel *bg_watched_channel_list_head = NULL; void grpc_rb_channel_try_register_connection_polling(bg_watched_channel *bg); void *wait_until_channel_polling_thread_started_no_gil(void*); -void wait_until_channel_polling_thread_started_unblocking_func(void*); void *channel_init_try_register_connection_polling_without_gil(void *arg); typedef struct channel_init_try_register_stack { @@ -228,7 +227,7 @@ VALUE grpc_rb_channel_init(int argc, VALUE *argv, VALUE self) { grpc_ruby_once_init(); rb_thread_call_without_gvl(wait_until_channel_polling_thread_started_no_gil, NULL, - wait_until_channel_polling_thread_started_unblocking_func, NULL); + run_poll_channels_loop_unblocking_func, NULL); /* "3" == 3 mandatory args */ rb_scan_args(argc, argv, "3", &target, &channel_args, &credentials); @@ -685,15 +684,6 @@ void *wait_until_channel_polling_thread_started_no_gil(void *arg) { return NULL; } -void wait_until_channel_polling_thread_started_unblocking_func(void* arg) { - (void)arg; - gpr_mu_lock(&global_connection_polling_mu); - gpr_log(GPR_DEBUG, "GRPC_RUBY: wait_until_channel_polling_thread_started_unblocking_func - begin aborting connection polling"); - abort_channel_polling = 1; - gpr_cv_broadcast(&global_connection_polling_cv); - gpr_mu_unlock(&global_connection_polling_mu); -} - static void *set_abort_channel_polling_without_gil(void *arg) { (void)arg; gpr_mu_lock(&global_connection_polling_mu); From fd4cbb70774a943a790459c8ec54d8bb112a3ef2 Mon Sep 17 00:00:00 2001 From: Alexander Polcyn Date: Wed, 17 May 2017 09:57:25 -0700 Subject: [PATCH 08/45] cleanup test --- src/ruby/end2end/grpc_class_init_client.rb | 57 ++++++++++++++-------- src/ruby/end2end/grpc_class_init_driver.rb | 14 +++--- 2 files changed, 46 insertions(+), 25 deletions(-) diff --git a/src/ruby/end2end/grpc_class_init_client.rb b/src/ruby/end2end/grpc_class_init_client.rb index 62afc85b1d0..d9c23c38359 100755 --- a/src/ruby/end2end/grpc_class_init_client.rb +++ b/src/ruby/end2end/grpc_class_init_client.rb @@ -60,6 +60,27 @@ def run_gc_stress_test(test_proc) construct_many(test_proc) end +def run_concurrency_stress_test(test_proc) + test_proc.call + + thds = [] + 100.times do + thds << Thread.new do + test_proc.call + end + end + + raise "something" +end + +# default (no gc_stress and no concurrency_stress) +def run_default_test(test_proc) + thd = Thread.new do + test_proc.call + end + test_proc.call +end + def get_test_proc(grpc_class) case grpc_class when 'channel' @@ -89,36 +110,34 @@ end def main grpc_class = '' - gc_stress = false + stress_test = '' OptionParser.new do |opts| opts.on('--grpc_class=P', String) do |p| grpc_class = p end - opts.on('--gc_stress=P') do |p| - gc_stress = p + opts.on('--stress_test=P') do |p| + stress_test = p end end.parse! test_proc = get_test_proc(grpc_class) - if gc_stress == 'true' + # the different test configs need to be ran + # in separate processes, since each one tests + # clean shutdown in a different way + case stress_test + when 'gc' + p 'run gc stress' run_gc_stress_test(test_proc) - return - end - -# test_proc.call - - thds = [] - 100.times do - thds << Thread.new do - test_proc.call - sleep 10 - end + when 'concurrency' + p 'run concurrency stress' + run_concurrency_stress_test(test_proc) + when '' + p 'run default' + run_default_test(test_proc) + else + fail "bad --stress_test=#{stress_test} param" end - - #test_proc.call - raise "something" - thds.each(&:join) end main diff --git a/src/ruby/end2end/grpc_class_init_driver.rb b/src/ruby/end2end/grpc_class_init_driver.rb index 0e330a493f5..195da3cf9f8 100755 --- a/src/ruby/end2end/grpc_class_init_driver.rb +++ b/src/ruby/end2end/grpc_class_init_driver.rb @@ -39,17 +39,17 @@ def main compression_options ) # there is room for false positives in this test, - # do 10 runs for each config to reduce these. - [true, false].each do |gc_stress| - 10.times do - native_grpc_classes.each do |grpc_class| + # do a few runs for each config + 4.times do + native_grpc_classes.each do |grpc_class| + ['', 'gc', 'concurrency'].each do |stress_test_type| STDERR.puts 'start client' this_dir = File.expand_path(File.dirname(__FILE__)) client_path = File.join(this_dir, 'grpc_class_init_client.rb') client_pid = Process.spawn(RbConfig.ruby, client_path, "--grpc_class=#{grpc_class}", - "--gc_stress=#{gc_stress}") + "--stress_test=#{stress_test_type}") begin Timeout.timeout(10) do Process.wait(client_pid) @@ -65,7 +65,9 @@ def main end client_exit_code = $CHILD_STATUS - if client_exit_code != 0 + # concurrency stress test type is expected to exit with a + # non-zero status due to an exception being raised + if client_exit_code != 0 and stress_test_type != 'concurrency' fail "client failed, exit code #{client_exit_code}" end end From 916893b618d602fef2ec1dbf9821611f67a7a1d3 Mon Sep 17 00:00:00 2001 From: Alexander Polcyn Date: Wed, 17 May 2017 10:05:39 -0700 Subject: [PATCH 09/45] fix up the test --- src/ruby/end2end/grpc_class_init_client.rb | 9 ++++----- 1 file changed, 4 insertions(+), 5 deletions(-) diff --git a/src/ruby/end2end/grpc_class_init_client.rb b/src/ruby/end2end/grpc_class_init_client.rb index d9c23c38359..464c42d07a8 100755 --- a/src/ruby/end2end/grpc_class_init_client.rb +++ b/src/ruby/end2end/grpc_class_init_client.rb @@ -61,16 +61,15 @@ def run_gc_stress_test(test_proc) end def run_concurrency_stress_test(test_proc) - test_proc.call - - thds = [] 100.times do - thds << Thread.new do + Thread.new do test_proc.call end end - raise "something" + test_proc.call + + raise 'exception thrown while child thread initing class' end # default (no gc_stress and no concurrency_stress) From 5c6dda8639bd390565e794192ddfb15af0837c92 Mon Sep 17 00:00:00 2001 From: Alexander Polcyn Date: Wed, 17 May 2017 13:08:34 -0700 Subject: [PATCH 10/45] fix tentative startup bug --- src/ruby/end2end/grpc_class_init_client.rb | 3 ++- src/ruby/end2end/grpc_class_init_driver.rb | 6 +++--- src/ruby/ext/grpc/rb_channel.c | 5 ++--- src/ruby/ext/grpc/rb_grpc.c | 21 +++++++++++++++++++-- 4 files changed, 26 insertions(+), 9 deletions(-) diff --git a/src/ruby/end2end/grpc_class_init_client.rb b/src/ruby/end2end/grpc_class_init_client.rb index 464c42d07a8..e73ca76850f 100755 --- a/src/ruby/end2end/grpc_class_init_client.rb +++ b/src/ruby/end2end/grpc_class_init_client.rb @@ -69,7 +69,7 @@ def run_concurrency_stress_test(test_proc) test_proc.call - raise 'exception thrown while child thread initing class' + fail 'exception thrown while child thread initing class' end # default (no gc_stress and no concurrency_stress) @@ -78,6 +78,7 @@ def run_default_test(test_proc) test_proc.call end test_proc.call + thd.join end def get_test_proc(grpc_class) diff --git a/src/ruby/end2end/grpc_class_init_driver.rb b/src/ruby/end2end/grpc_class_init_driver.rb index 195da3cf9f8..c65ed547c54 100755 --- a/src/ruby/end2end/grpc_class_init_driver.rb +++ b/src/ruby/end2end/grpc_class_init_driver.rb @@ -65,9 +65,9 @@ def main end client_exit_code = $CHILD_STATUS - # concurrency stress test type is expected to exit with a - # non-zero status due to an exception being raised - if client_exit_code != 0 and stress_test_type != 'concurrency' + # concurrency stress test type is expected to exit with a + # non-zero status due to an exception being raised + if client_exit_code != 0 && stress_test_type != 'concurrency' fail "client failed, exit code #{client_exit_code}" end end diff --git a/src/ruby/ext/grpc/rb_channel.c b/src/ruby/ext/grpc/rb_channel.c index 748fe663ed9..4e59174c3b3 100644 --- a/src/ruby/ext/grpc/rb_channel.c +++ b/src/ruby/ext/grpc/rb_channel.c @@ -368,8 +368,8 @@ void *wait_for_watch_state_op_complete_without_gvl(void *arg) { * state changes from "last_state". * */ VALUE grpc_rb_channel_watch_connectivity_state(VALUE self, - VALUE last_state, - VALUE deadline) { + VALUE last_state, + VALUE deadline) { grpc_rb_channel *wrapper = NULL; watch_state_stack stack; void* op_success = 0; @@ -693,7 +693,6 @@ static void *set_abort_channel_polling_without_gil(void *arg) { return NULL; } - /* Temporary fix for * https://github.com/GoogleCloudPlatform/google-cloud-ruby/issues/899. * Transports in idle channels can get destroyed. Normally c-core re-connects, diff --git a/src/ruby/ext/grpc/rb_grpc.c b/src/ruby/ext/grpc/rb_grpc.c index 584b5dbc63d..2a3b3391027 100644 --- a/src/ruby/ext/grpc/rb_grpc.c +++ b/src/ruby/ext/grpc/rb_grpc.c @@ -42,6 +42,7 @@ #include #include +#include #include "rb_call.h" #include "rb_call_credentials.h" #include "rb_channel.h" @@ -295,11 +296,12 @@ static gpr_once g_once_init = GPR_ONCE_INIT; static void grpc_ruby_once_init_internal() { grpc_init(); - grpc_rb_event_queue_thread_start(); - grpc_rb_channel_polling_thread_start(); atexit(grpc_rb_shutdown); } +static VALUE bg_thread_init_rb_mu = Qundef; +static int bg_thread_init_done = 0; + void grpc_ruby_once_init() { /* ruby_vm_at_exit doesn't seem to be working. It would crash once every * blue moon, and some users are getting it repeatedly. See the discussions @@ -312,6 +314,18 @@ void grpc_ruby_once_init() { * schedule our initialization and destruction only once. */ gpr_once_init(&g_once_init, grpc_ruby_once_init_internal); + + // Avoid calling calling into ruby library (when creating threads here) + // in gpr_once_init. In general, it appears to be unsafe to call + // into the ruby library while holding a non-ruby mutex, because a gil yield + // could end up trying to lock onto that same mutex and deadlocking. + rb_mutex_lock(bg_thread_init_rb_mu); + if (!bg_thread_init_done) { + grpc_rb_event_queue_thread_start(); + grpc_rb_channel_polling_thread_start(); + bg_thread_init_done = 1; + } + rb_mutex_unlock(bg_thread_init_rb_mu); } void Init_grpc_c() { @@ -320,6 +334,9 @@ void Init_grpc_c() { return; } + bg_thread_init_rb_mu = rb_mutex_new(); + rb_global_variable(&bg_thread_init_rb_mu); + grpc_rb_mGRPC = rb_define_module("GRPC"); grpc_rb_mGrpcCore = rb_define_module_under(grpc_rb_mGRPC, "Core"); grpc_rb_sNewServerRpc = From 7e44480614e2615821dabbece98989721d0cf6f4 Mon Sep 17 00:00:00 2001 From: Alexander Polcyn Date: Wed, 17 May 2017 13:13:55 -0700 Subject: [PATCH 11/45] clang format --- src/ruby/ext/grpc/rb_channel.c | 138 +++++++++++++++++++-------------- 1 file changed, 78 insertions(+), 60 deletions(-) diff --git a/src/ruby/ext/grpc/rb_channel.c b/src/ruby/ext/grpc/rb_channel.c index 4e59174c3b3..449c91a0f98 100644 --- a/src/ruby/ext/grpc/rb_channel.c +++ b/src/ruby/ext/grpc/rb_channel.c @@ -34,9 +34,9 @@ #include #include -#include "rb_grpc_imports.generated.h" #include "rb_byte_buffer.h" #include "rb_channel.h" +#include "rb_grpc_imports.generated.h" #include #include @@ -72,21 +72,19 @@ typedef struct bg_watched_channel { grpc_channel *channel; struct bg_watched_channel *next; int channel_destroyed; - int refcount; // must only be accessed under global_connection_polling_mu + int refcount; // must only be accessed under global_connection_polling_mu } bg_watched_channel; /* grpc_rb_channel wraps a grpc_channel. */ typedef struct grpc_rb_channel { VALUE credentials; - /* The actual channel (protected in a wrapper to tell when it's safe to destroy) */ + /* The actual channel (protected in a wrapper to tell when it's safe to + * destroy) */ bg_watched_channel *bg_wrapped; } grpc_rb_channel; -typedef enum { - CONTINUOUS_WATCH, - WATCH_STATE_API -} watch_state_op_type; +typedef enum { CONTINUOUS_WATCH, WATCH_STATE_API } watch_state_op_type; typedef struct watch_state_op { watch_state_op_type op_type; @@ -106,7 +104,7 @@ typedef struct watch_state_op { bg_watched_channel *bg_watched_channel_list_head = NULL; void grpc_rb_channel_try_register_connection_polling(bg_watched_channel *bg); -void *wait_until_channel_polling_thread_started_no_gil(void*); +void *wait_until_channel_polling_thread_started_no_gil(void *); void *channel_init_try_register_connection_polling_without_gil(void *arg); typedef struct channel_init_try_register_stack { @@ -121,12 +119,14 @@ int abort_channel_polling = 0; int channel_polling_thread_started = 0; int bg_watched_channel_list_lookup(bg_watched_channel *bg); -bg_watched_channel *bg_watched_channel_list_create_and_add(grpc_channel *channel); +bg_watched_channel *bg_watched_channel_list_create_and_add( + grpc_channel *channel); void bg_watched_channel_list_free_and_remove(bg_watched_channel *bg); -void run_poll_channels_loop_unblocking_func(void* arg); +void run_poll_channels_loop_unblocking_func(void *arg); // Needs to be called under global_connection_polling_mu -void grpc_rb_channel_watch_connection_state_op_complete(watch_state_op* op, int success) { +void grpc_rb_channel_watch_connection_state_op_complete(watch_state_op *op, + int success) { GPR_ASSERT(!op->op.api_callback_args.called_back); op->op.api_callback_args.called_back = 1; op->op.api_callback_args.success = success; @@ -150,7 +150,7 @@ void grpc_rb_channel_safe_destroy(bg_watched_channel *bg) { } void *channel_safe_destroy_without_gil(void *arg) { - grpc_rb_channel_safe_destroy((bg_watched_channel*)arg); + grpc_rb_channel_safe_destroy((bg_watched_channel *)arg); return NULL; } @@ -186,14 +186,14 @@ void grpc_rb_channel_mark(void *p) { } rb_data_type_t grpc_channel_data_type = {"grpc_channel", - {grpc_rb_channel_mark, - grpc_rb_channel_free, - GRPC_RB_MEMSIZE_UNAVAILABLE, - {NULL, NULL}}, - NULL, - NULL, + {grpc_rb_channel_mark, + grpc_rb_channel_free, + GRPC_RB_MEMSIZE_UNAVAILABLE, + {NULL, NULL}}, + NULL, + NULL, #ifdef RUBY_TYPED_FREE_IMMEDIATELY - RUBY_TYPED_FREE_IMMEDIATELY + RUBY_TYPED_FREE_IMMEDIATELY #endif }; @@ -226,8 +226,9 @@ VALUE grpc_rb_channel_init(int argc, VALUE *argv, VALUE self) { MEMZERO(&args, grpc_channel_args, 1); grpc_ruby_once_init(); - rb_thread_call_without_gvl(wait_until_channel_polling_thread_started_no_gil, NULL, - run_poll_channels_loop_unblocking_func, NULL); + rb_thread_call_without_gvl(wait_until_channel_polling_thread_started_no_gil, + NULL, run_poll_channels_loop_unblocking_func, + NULL); /* "3" == 3 mandatory args */ rb_scan_args(argc, argv, "3", &target, &channel_args, &credentials); @@ -252,7 +253,8 @@ VALUE grpc_rb_channel_init(int argc, VALUE *argv, VALUE self) { stack.channel = ch; stack.wrapper = wrapper; rb_thread_call_without_gvl( - channel_init_try_register_connection_polling_without_gil, &stack, NULL, NULL); + channel_init_try_register_connection_polling_without_gil, &stack, NULL, + NULL); if (args.args != NULL) { xfree(args.args); /* Allocated by grpc_rb_hash_convert_to_channel_args */ @@ -273,7 +275,7 @@ typedef struct get_state_stack { } get_state_stack; void *get_state_without_gil(void *arg) { - get_state_stack *stack = (get_state_stack*)arg; + get_state_stack *stack = (get_state_stack *)arg; gpr_mu_lock(&global_connection_polling_mu); GPR_ASSERT(abort_channel_polling || channel_polling_thread_started); @@ -282,7 +284,8 @@ void *get_state_without_gil(void *arg) { // failed to start just always shows shutdown state. stack->out = GRPC_CHANNEL_SHUTDOWN; } else { - stack->out = grpc_channel_check_connectivity_state(stack->channel, stack->try_to_connect); + stack->out = grpc_channel_check_connectivity_state(stack->channel, + stack->try_to_connect); } gpr_mu_unlock(&global_connection_polling_mu); @@ -299,7 +302,7 @@ void *get_state_without_gil(void *arg) { It also tries to connect if the chennel is idle in the second form. */ VALUE grpc_rb_channel_get_connectivity_state(int argc, VALUE *argv, - VALUE self) { + VALUE self) { VALUE try_to_connect_param = Qfalse; int grpc_try_to_connect = 0; grpc_rb_channel *wrapper = NULL; @@ -329,30 +332,30 @@ typedef struct watch_state_stack { } watch_state_stack; void *wait_for_watch_state_op_complete_without_gvl(void *arg) { - watch_state_stack *stack = (watch_state_stack*)arg; + watch_state_stack *stack = (watch_state_stack *)arg; watch_state_op *op = NULL; - void *success = (void*)0; + void *success = (void *)0; gpr_mu_lock(&global_connection_polling_mu); // its unsafe to do a "watch" after "channel polling abort" because the cq has // been shut down. if (abort_channel_polling) { gpr_mu_unlock(&global_connection_polling_mu); - return (void*)0; + return (void *)0; } op = gpr_zalloc(sizeof(watch_state_op)); op->op_type = WATCH_STATE_API; // one ref for this thread and another for the callback-running thread - grpc_channel_watch_connectivity_state( - stack->channel, stack->last_state, stack->deadline, channel_polling_cq, op); + grpc_channel_watch_connectivity_state(stack->channel, stack->last_state, + stack->deadline, channel_polling_cq, + op); - while(!op->op.api_callback_args.called_back) { - gpr_cv_wait(&global_connection_polling_cv, - &global_connection_polling_mu, + while (!op->op.api_callback_args.called_back) { + gpr_cv_wait(&global_connection_polling_cv, &global_connection_polling_mu, gpr_inf_future(GPR_CLOCK_REALTIME)); } if (op->op.api_callback_args.success) { - success = (void*)1; + success = (void *)1; } gpr_free(op); gpr_mu_unlock(&global_connection_polling_mu); @@ -367,12 +370,11 @@ void *wait_for_watch_state_op_complete_without_gvl(void *arg) { * Returns false if "deadline" expires before the channel's connectivity * state changes from "last_state". * */ -VALUE grpc_rb_channel_watch_connectivity_state(VALUE self, - VALUE last_state, +VALUE grpc_rb_channel_watch_connectivity_state(VALUE self, VALUE last_state, VALUE deadline) { grpc_rb_channel *wrapper = NULL; watch_state_stack stack; - void* op_success = 0; + void *op_success = 0; TypedData_Get_Struct(self, grpc_rb_channel, &grpc_channel_data_type, wrapper); @@ -382,7 +384,9 @@ VALUE grpc_rb_channel_watch_connectivity_state(VALUE self, } if (!FIXNUM_P(last_state)) { - rb_raise(rb_eTypeError, "bad type for last_state. want a GRPC::Core::ChannelState constant"); + rb_raise( + rb_eTypeError, + "bad type for last_state. want a GRPC::Core::ChannelState constant"); return Qnil; } @@ -391,7 +395,8 @@ VALUE grpc_rb_channel_watch_connectivity_state(VALUE self, stack.last_state = NUM2LONG(last_state); op_success = rb_thread_call_without_gvl( - wait_for_watch_state_op_complete_without_gvl, &stack, run_poll_channels_loop_unblocking_func, NULL); + wait_for_watch_state_op_complete_without_gvl, &stack, + run_poll_channels_loop_unblocking_func, NULL); return op_success ? Qtrue : Qfalse; } @@ -399,8 +404,7 @@ VALUE grpc_rb_channel_watch_connectivity_state(VALUE self, /* Create a call given a grpc_channel, in order to call method. The request is not sent until grpc_call_invoke is called. */ VALUE grpc_rb_channel_create_call(VALUE self, VALUE parent, VALUE mask, - VALUE method, VALUE host, - VALUE deadline) { + VALUE method, VALUE host, VALUE deadline) { VALUE res = Qnil; grpc_rb_channel *wrapper = NULL; grpc_call *call = NULL; @@ -434,8 +438,8 @@ VALUE grpc_rb_channel_create_call(VALUE self, VALUE parent, VALUE mask, method_slice = grpc_slice_from_copied_buffer(RSTRING_PTR(method), RSTRING_LEN(method)); - call = grpc_channel_create_call(wrapper->bg_wrapped->channel, parent_call, flags, cq, method_slice, - host_slice_ptr, + call = grpc_channel_create_call(wrapper->bg_wrapped->channel, parent_call, + flags, cq, method_slice, host_slice_ptr, grpc_rb_time_timeval(deadline, /* absolute time */ 0), NULL); @@ -467,8 +471,8 @@ VALUE grpc_rb_channel_destroy(VALUE self) { TypedData_Get_Struct(self, grpc_rb_channel, &grpc_channel_data_type, wrapper); if (wrapper->bg_wrapped != NULL) { - rb_thread_call_without_gvl( - channel_safe_destroy_without_gil, wrapper->bg_wrapped, NULL, NULL); + rb_thread_call_without_gvl(channel_safe_destroy_without_gil, + wrapper->bg_wrapped, NULL, NULL); wrapper->bg_wrapped = NULL; } @@ -504,7 +508,8 @@ int bg_watched_channel_list_lookup(bg_watched_channel *target) { } /* Needs to be called under global_connection_polling_mu */ -bg_watched_channel *bg_watched_channel_list_create_and_add(grpc_channel *channel) { +bg_watched_channel *bg_watched_channel_list_create_and_add( + grpc_channel *channel) { bg_watched_channel *watched = gpr_zalloc(sizeof(bg_watched_channel)); watched->channel = channel; @@ -540,10 +545,12 @@ void bg_watched_channel_list_free_and_remove(bg_watched_channel *target) { /* Initialize a grpc_rb_channel's "protected grpc_channel" and try to push * it onto the background thread for constant watches. */ void *channel_init_try_register_connection_polling_without_gil(void *arg) { - channel_init_try_register_stack *stack = (channel_init_try_register_stack*)arg; + channel_init_try_register_stack *stack = + (channel_init_try_register_stack *)arg; gpr_mu_lock(&global_connection_polling_mu); - stack->wrapper->bg_wrapped = bg_watched_channel_list_create_and_add(stack->channel); + stack->wrapper->bg_wrapped = + bg_watched_channel_list_create_and_add(stack->channel); grpc_rb_channel_try_register_connection_polling(stack->wrapper->bg_wrapped); gpr_mu_unlock(&global_connection_polling_mu); return NULL; @@ -581,8 +588,9 @@ void grpc_rb_channel_try_register_connection_polling(bg_watched_channel *bg) { op = gpr_zalloc(sizeof(watch_state_op)); op->op_type = CONTINUOUS_WATCH; op->op.continuous_watch_callback_args.bg = bg; - grpc_channel_watch_connectivity_state( - bg->channel, conn_state, gpr_inf_future(GPR_CLOCK_REALTIME), channel_polling_cq, op); + grpc_channel_watch_connectivity_state(bg->channel, conn_state, + gpr_inf_future(GPR_CLOCK_REALTIME), + channel_polling_cq, op); } // Note this loop breaks out with a single call of @@ -612,14 +620,15 @@ void *run_poll_channels_loop_no_gil(void *arg) { } gpr_mu_lock(&global_connection_polling_mu); if (event.type == GRPC_OP_COMPLETE) { - op = (watch_state_op*)event.tag; + op = (watch_state_op *)event.tag; if (op->op_type == CONTINUOUS_WATCH) { - bg = (bg_watched_channel*)op->op.continuous_watch_callback_args.bg; + bg = (bg_watched_channel *)op->op.continuous_watch_callback_args.bg; bg->refcount--; grpc_rb_channel_try_register_connection_polling(bg); gpr_free(op); - } else if(op->op_type == WATCH_STATE_API) { - grpc_rb_channel_watch_connection_state_op_complete((watch_state_op*)event.tag, event.success); + } else if (op->op_type == WATCH_STATE_API) { + grpc_rb_channel_watch_connection_state_op_complete( + (watch_state_op *)event.tag, event.success); } else { GPR_ASSERT(0); } @@ -627,7 +636,9 @@ void *run_poll_channels_loop_no_gil(void *arg) { gpr_mu_unlock(&global_connection_polling_mu); } grpc_completion_queue_destroy(channel_polling_cq); - gpr_log(GPR_DEBUG, "GRPC_RUBY: run_poll_channels_loop_no_gil - exit connection polling loop"); + gpr_log(GPR_DEBUG, + "GRPC_RUBY: run_poll_channels_loop_no_gil - exit connection polling " + "loop"); return NULL; } @@ -637,7 +648,9 @@ void run_poll_channels_loop_unblocking_func(void *arg) { (void)arg; gpr_mu_lock(&global_connection_polling_mu); - gpr_log(GPR_DEBUG, "GRPC_RUBY: run_poll_channels_loop_unblocking_func - begin aborting connection polling"); + gpr_log(GPR_DEBUG, + "GRPC_RUBY: run_poll_channels_loop_unblocking_func - begin aborting " + "connection polling"); // early out after first time through if (abort_channel_polling) { gpr_mu_unlock(&global_connection_polling_mu); @@ -647,7 +660,7 @@ void run_poll_channels_loop_unblocking_func(void *arg) { // force pending watches to end by switching to shutdown state bg = bg_watched_channel_list_head; - while(bg != NULL) { + while (bg != NULL) { if (!bg->channel_destroyed) { grpc_channel_destroy(bg->channel); bg->channel_destroyed = 1; @@ -658,13 +671,17 @@ void run_poll_channels_loop_unblocking_func(void *arg) { grpc_completion_queue_shutdown(channel_polling_cq); gpr_cv_broadcast(&global_connection_polling_cv); gpr_mu_unlock(&global_connection_polling_mu); - gpr_log(GPR_DEBUG, "GRPC_RUBY: run_poll_channels_loop_unblocking_func - begin aborting connection polling 22222"); + gpr_log(GPR_DEBUG, + "GRPC_RUBY: run_poll_channels_loop_unblocking_func - end aborting " + "connection polling"); } // Poll channel connectivity states in background thread without the GIL. VALUE run_poll_channels_loop(VALUE arg) { (void)arg; - gpr_log(GPR_DEBUG, "GRPC_RUBY: run_poll_channels_loop - create connection polling thread"); + gpr_log( + GPR_DEBUG, + "GRPC_RUBY: run_poll_channels_loop - create connection polling thread"); rb_thread_call_without_gvl(run_poll_channels_loop_no_gil, NULL, run_poll_channels_loop_unblocking_func, NULL); @@ -718,7 +735,8 @@ void grpc_rb_channel_polling_thread_start() { if (!RTEST(background_thread)) { gpr_log(GPR_DEBUG, "GRPC_RUBY: failed to spawn channel polling thread"); - rb_thread_call_without_gvl(set_abort_channel_polling_without_gil, NULL, NULL, NULL); + rb_thread_call_without_gvl(set_abort_channel_polling_without_gil, NULL, + NULL, NULL); } } From 032f398543676818b3e0761f8bdd899c8c3616eb Mon Sep 17 00:00:00 2001 From: Alexander Polcyn Date: Wed, 17 May 2017 13:22:55 -0700 Subject: [PATCH 12/45] cleanup --- src/ruby/ext/grpc/rb_call.c | 2 +- src/ruby/ext/grpc/rb_channel.c | 132 ++++++++++++----------- src/ruby/ext/grpc/rb_completion_queue.c | 14 +-- src/ruby/ext/grpc/rb_completion_queue.h | 2 +- src/ruby/ext/grpc/rb_grpc.c | 1 - src/ruby/ext/grpc/rb_server.c | 2 +- src/ruby/spec/channel_connection_spec.rb | 3 +- 7 files changed, 79 insertions(+), 77 deletions(-) diff --git a/src/ruby/ext/grpc/rb_call.c b/src/ruby/ext/grpc/rb_call.c index 6cb71870f55..344cb941ffb 100644 --- a/src/ruby/ext/grpc/rb_call.c +++ b/src/ruby/ext/grpc/rb_call.c @@ -103,7 +103,7 @@ static void destroy_call(grpc_rb_call *call) { if (call->wrapped != NULL) { grpc_call_destroy(call->wrapped); call->wrapped = NULL; - grpc_rb_completion_queue_safe_destroy(call->queue); + grpc_rb_completion_queue_destroy(call->queue); call->queue = NULL; } } diff --git a/src/ruby/ext/grpc/rb_channel.c b/src/ruby/ext/grpc/rb_channel.c index 449c91a0f98..e02dd0805d3 100644 --- a/src/ruby/ext/grpc/rb_channel.c +++ b/src/ruby/ext/grpc/rb_channel.c @@ -52,27 +52,28 @@ /* id_channel is the name of the hidden ivar that preserves a reference to the * channel on a call, so that calls are not GCed before their channel. */ -ID id_channel; +static ID id_channel; /* id_target is the name of the hidden ivar that preserves a reference to the * target string used to create the call, preserved so that it does not get * GCed before the channel */ -ID id_target; +static ID id_target; /* id_insecure_channel is used to indicate that a channel is insecure */ -VALUE id_insecure_channel; +static VALUE id_insecure_channel; /* grpc_rb_cChannel is the ruby class that proxies grpc_channel. */ -VALUE grpc_rb_cChannel = Qnil; +static VALUE grpc_rb_cChannel = Qnil; /* Used during the conversion of a hash to channel args during channel setup */ -VALUE grpc_rb_cChannelArgs; +static VALUE grpc_rb_cChannelArgs; typedef struct bg_watched_channel { grpc_channel *channel; + // these fields must only be accessed under global_connection_polling_mu struct bg_watched_channel *next; int channel_destroyed; - int refcount; // must only be accessed under global_connection_polling_mu + int refcount; } bg_watched_channel; /* grpc_rb_channel wraps a grpc_channel. */ @@ -101,32 +102,34 @@ typedef struct watch_state_op { } op; } watch_state_op; -bg_watched_channel *bg_watched_channel_list_head = NULL; +static bg_watched_channel *bg_watched_channel_list_head = NULL; -void grpc_rb_channel_try_register_connection_polling(bg_watched_channel *bg); -void *wait_until_channel_polling_thread_started_no_gil(void *); -void *channel_init_try_register_connection_polling_without_gil(void *arg); +static void grpc_rb_channel_try_register_connection_polling( + bg_watched_channel *bg); +static void *wait_until_channel_polling_thread_started_no_gil(void *); +static void *channel_init_try_register_connection_polling_without_gil( + void *arg); typedef struct channel_init_try_register_stack { grpc_channel *channel; grpc_rb_channel *wrapper; } channel_init_try_register_stack; -grpc_completion_queue *channel_polling_cq; -gpr_mu global_connection_polling_mu; -gpr_cv global_connection_polling_cv; -int abort_channel_polling = 0; -int channel_polling_thread_started = 0; +static grpc_completion_queue *channel_polling_cq; +static gpr_mu global_connection_polling_mu; +static gpr_cv global_connection_polling_cv; +static int abort_channel_polling = 0; +static int channel_polling_thread_started = 0; -int bg_watched_channel_list_lookup(bg_watched_channel *bg); -bg_watched_channel *bg_watched_channel_list_create_and_add( +static int bg_watched_channel_list_lookup(bg_watched_channel *bg); +static bg_watched_channel *bg_watched_channel_list_create_and_add( grpc_channel *channel); -void bg_watched_channel_list_free_and_remove(bg_watched_channel *bg); -void run_poll_channels_loop_unblocking_func(void *arg); +static void bg_watched_channel_list_free_and_remove(bg_watched_channel *bg); +static void run_poll_channels_loop_unblocking_func(void *arg); // Needs to be called under global_connection_polling_mu -void grpc_rb_channel_watch_connection_state_op_complete(watch_state_op *op, - int success) { +static void grpc_rb_channel_watch_connection_state_op_complete( + watch_state_op *op, int success) { GPR_ASSERT(!op->op.api_callback_args.called_back); op->op.api_callback_args.called_back = 1; op->op.api_callback_args.success = success; @@ -135,7 +138,7 @@ void grpc_rb_channel_watch_connection_state_op_complete(watch_state_op *op, } /* Avoids destroying a channel twice. */ -void grpc_rb_channel_safe_destroy(bg_watched_channel *bg) { +static void grpc_rb_channel_safe_destroy(bg_watched_channel *bg) { gpr_mu_lock(&global_connection_polling_mu); GPR_ASSERT(bg_watched_channel_list_lookup(bg)); if (!bg->channel_destroyed) { @@ -149,13 +152,13 @@ void grpc_rb_channel_safe_destroy(bg_watched_channel *bg) { gpr_mu_unlock(&global_connection_polling_mu); } -void *channel_safe_destroy_without_gil(void *arg) { +static void *channel_safe_destroy_without_gil(void *arg) { grpc_rb_channel_safe_destroy((bg_watched_channel *)arg); return NULL; } /* Destroys Channel instances. */ -void grpc_rb_channel_free(void *p) { +static void grpc_rb_channel_free(void *p) { grpc_rb_channel *ch = NULL; if (p == NULL) { return; @@ -165,7 +168,8 @@ void grpc_rb_channel_free(void *p) { if (ch->bg_wrapped != NULL) { /* assumption made here: it's ok to directly gpr_mu_lock the global * connection polling mutex becuse we're in a finalizer, - * and we can count on this thread to not be interrupted. */ + * and we can count on this thread to not be interrupted or + * yield the gil. */ grpc_rb_channel_safe_destroy(ch->bg_wrapped); ch->bg_wrapped = NULL; } @@ -174,7 +178,7 @@ void grpc_rb_channel_free(void *p) { } /* Protects the mark object from GC */ -void grpc_rb_channel_mark(void *p) { +static void grpc_rb_channel_mark(void *p) { grpc_rb_channel *channel = NULL; if (p == NULL) { return; @@ -185,20 +189,20 @@ void grpc_rb_channel_mark(void *p) { } } -rb_data_type_t grpc_channel_data_type = {"grpc_channel", - {grpc_rb_channel_mark, - grpc_rb_channel_free, - GRPC_RB_MEMSIZE_UNAVAILABLE, - {NULL, NULL}}, - NULL, - NULL, +static rb_data_type_t grpc_channel_data_type = {"grpc_channel", + {grpc_rb_channel_mark, + grpc_rb_channel_free, + GRPC_RB_MEMSIZE_UNAVAILABLE, + {NULL, NULL}}, + NULL, + NULL, #ifdef RUBY_TYPED_FREE_IMMEDIATELY - RUBY_TYPED_FREE_IMMEDIATELY + RUBY_TYPED_FREE_IMMEDIATELY #endif }; /* Allocates grpc_rb_channel instances. */ -VALUE grpc_rb_channel_alloc(VALUE cls) { +static VALUE grpc_rb_channel_alloc(VALUE cls) { grpc_rb_channel *wrapper = ALLOC(grpc_rb_channel); wrapper->bg_wrapped = NULL; wrapper->credentials = Qnil; @@ -213,7 +217,7 @@ VALUE grpc_rb_channel_alloc(VALUE cls) { secure_channel = Channel:new("myhost:443", {'arg1': 'value1'}, creds) Creates channel instances. */ -VALUE grpc_rb_channel_init(int argc, VALUE *argv, VALUE self) { +static VALUE grpc_rb_channel_init(int argc, VALUE *argv, VALUE self) { VALUE channel_args = Qnil; VALUE credentials = Qnil; VALUE target = Qnil; @@ -274,13 +278,15 @@ typedef struct get_state_stack { int out; } get_state_stack; -void *get_state_without_gil(void *arg) { +static void *get_state_without_gil(void *arg) { get_state_stack *stack = (get_state_stack *)arg; gpr_mu_lock(&global_connection_polling_mu); GPR_ASSERT(abort_channel_polling || channel_polling_thread_started); if (abort_channel_polling) { - // the case in which the channel polling thread + // Assume that this channel has been destroyed by the + // background thread. + // The case in which the channel polling thread // failed to start just always shows shutdown state. stack->out = GRPC_CHANNEL_SHUTDOWN; } else { @@ -301,16 +307,14 @@ void *get_state_without_gil(void *arg) { constants defined in GRPC::Core::ConnectivityStates. It also tries to connect if the chennel is idle in the second form. */ -VALUE grpc_rb_channel_get_connectivity_state(int argc, VALUE *argv, - VALUE self) { +static VALUE grpc_rb_channel_get_connectivity_state(int argc, VALUE *argv, + VALUE self) { VALUE try_to_connect_param = Qfalse; - int grpc_try_to_connect = 0; grpc_rb_channel *wrapper = NULL; get_state_stack stack; /* "01" == 0 mandatory args, 1 (try_to_connect) is optional */ rb_scan_args(argc, argv, "01", &try_to_connect_param); - grpc_try_to_connect = RTEST(try_to_connect_param) ? 1 : 0; TypedData_Get_Struct(self, grpc_rb_channel, &grpc_channel_data_type, wrapper); if (wrapper->bg_wrapped == NULL) { @@ -319,7 +323,7 @@ VALUE grpc_rb_channel_get_connectivity_state(int argc, VALUE *argv, } stack.channel = wrapper->bg_wrapped->channel; - stack.try_to_connect = grpc_try_to_connect; + stack.try_to_connect = RTEST(try_to_connect_param) ? 1 : 0; rb_thread_call_without_gvl(get_state_without_gil, &stack, NULL, NULL); return LONG2NUM(stack.out); @@ -331,7 +335,7 @@ typedef struct watch_state_stack { int last_state; } watch_state_stack; -void *wait_for_watch_state_op_complete_without_gvl(void *arg) { +static void *wait_for_watch_state_op_complete_without_gvl(void *arg) { watch_state_stack *stack = (watch_state_stack *)arg; watch_state_op *op = NULL; void *success = (void *)0; @@ -345,7 +349,6 @@ void *wait_for_watch_state_op_complete_without_gvl(void *arg) { } op = gpr_zalloc(sizeof(watch_state_op)); op->op_type = WATCH_STATE_API; - // one ref for this thread and another for the callback-running thread grpc_channel_watch_connectivity_state(stack->channel, stack->last_state, stack->deadline, channel_polling_cq, op); @@ -370,8 +373,9 @@ void *wait_for_watch_state_op_complete_without_gvl(void *arg) { * Returns false if "deadline" expires before the channel's connectivity * state changes from "last_state". * */ -VALUE grpc_rb_channel_watch_connectivity_state(VALUE self, VALUE last_state, - VALUE deadline) { +static VALUE grpc_rb_channel_watch_connectivity_state(VALUE self, + VALUE last_state, + VALUE deadline) { grpc_rb_channel *wrapper = NULL; watch_state_stack stack; void *op_success = 0; @@ -403,8 +407,9 @@ VALUE grpc_rb_channel_watch_connectivity_state(VALUE self, VALUE last_state, /* Create a call given a grpc_channel, in order to call method. The request is not sent until grpc_call_invoke is called. */ -VALUE grpc_rb_channel_create_call(VALUE self, VALUE parent, VALUE mask, - VALUE method, VALUE host, VALUE deadline) { +static VALUE grpc_rb_channel_create_call(VALUE self, VALUE parent, VALUE mask, + VALUE method, VALUE host, + VALUE deadline) { VALUE res = Qnil; grpc_rb_channel *wrapper = NULL; grpc_call *call = NULL; @@ -466,7 +471,7 @@ VALUE grpc_rb_channel_create_call(VALUE self, VALUE parent, VALUE mask, /* Closes the channel, calling it's destroy method */ /* Note this is an API-level call; a wrapped channel's finalizer doesn't call * this */ -VALUE grpc_rb_channel_destroy(VALUE self) { +static VALUE grpc_rb_channel_destroy(VALUE self) { grpc_rb_channel *wrapper = NULL; TypedData_Get_Struct(self, grpc_rb_channel, &grpc_channel_data_type, wrapper); @@ -480,7 +485,7 @@ VALUE grpc_rb_channel_destroy(VALUE self) { } /* Called to obtain the target that this channel accesses. */ -VALUE grpc_rb_channel_get_target(VALUE self) { +static VALUE grpc_rb_channel_get_target(VALUE self) { grpc_rb_channel *wrapper = NULL; VALUE res = Qnil; char *target = NULL; @@ -494,7 +499,7 @@ VALUE grpc_rb_channel_get_target(VALUE self) { } /* Needs to be called under global_connection_polling_mu */ -int bg_watched_channel_list_lookup(bg_watched_channel *target) { +static int bg_watched_channel_list_lookup(bg_watched_channel *target) { bg_watched_channel *cur = bg_watched_channel_list_head; while (cur != NULL) { @@ -508,7 +513,7 @@ int bg_watched_channel_list_lookup(bg_watched_channel *target) { } /* Needs to be called under global_connection_polling_mu */ -bg_watched_channel *bg_watched_channel_list_create_and_add( +static bg_watched_channel *bg_watched_channel_list_create_and_add( grpc_channel *channel) { bg_watched_channel *watched = gpr_zalloc(sizeof(bg_watched_channel)); @@ -520,7 +525,8 @@ bg_watched_channel *bg_watched_channel_list_create_and_add( } /* Needs to be called under global_connection_polling_mu */ -void bg_watched_channel_list_free_and_remove(bg_watched_channel *target) { +static void bg_watched_channel_list_free_and_remove( + bg_watched_channel *target) { bg_watched_channel *bg = NULL; GPR_ASSERT(bg_watched_channel_list_lookup(target)); @@ -544,7 +550,8 @@ void bg_watched_channel_list_free_and_remove(bg_watched_channel *target) { /* Initialize a grpc_rb_channel's "protected grpc_channel" and try to push * it onto the background thread for constant watches. */ -void *channel_init_try_register_connection_polling_without_gil(void *arg) { +static void *channel_init_try_register_connection_polling_without_gil( + void *arg) { channel_init_try_register_stack *stack = (channel_init_try_register_stack *)arg; @@ -557,7 +564,8 @@ void *channel_init_try_register_connection_polling_without_gil(void *arg) { } // Needs to be called under global_connection_poolling_mu -void grpc_rb_channel_try_register_connection_polling(bg_watched_channel *bg) { +static void grpc_rb_channel_try_register_connection_polling( + bg_watched_channel *bg) { grpc_connectivity_state conn_state; watch_state_op *op = NULL; @@ -599,7 +607,7 @@ void grpc_rb_channel_try_register_connection_polling(bg_watched_channel *bg) { // indicates process shutdown. // In the worst case, this stops polling channel connectivity // early and falls back to current behavior. -void *run_poll_channels_loop_no_gil(void *arg) { +static void *run_poll_channels_loop_no_gil(void *arg) { grpc_event event; watch_state_op *op = NULL; bg_watched_channel *bg = NULL; @@ -643,7 +651,7 @@ void *run_poll_channels_loop_no_gil(void *arg) { } // Notify the channel polling loop to cleanup and shutdown. -void run_poll_channels_loop_unblocking_func(void *arg) { +static void run_poll_channels_loop_unblocking_func(void *arg) { bg_watched_channel *bg = NULL; (void)arg; @@ -677,7 +685,7 @@ void run_poll_channels_loop_unblocking_func(void *arg) { } // Poll channel connectivity states in background thread without the GIL. -VALUE run_poll_channels_loop(VALUE arg) { +static VALUE run_poll_channels_loop(VALUE arg) { (void)arg; gpr_log( GPR_DEBUG, @@ -688,7 +696,7 @@ VALUE run_poll_channels_loop(VALUE arg) { return Qnil; } -void *wait_until_channel_polling_thread_started_no_gil(void *arg) { +static void *wait_until_channel_polling_thread_started_no_gil(void *arg) { (void)arg; gpr_log(GPR_DEBUG, "GRPC_RUBY: wait for channel polling thread to start"); gpr_mu_lock(&global_connection_polling_mu); @@ -740,7 +748,7 @@ void grpc_rb_channel_polling_thread_start() { } } -void Init_grpc_propagate_masks() { +static void Init_grpc_propagate_masks() { /* Constants representing call propagation masks in grpc.h */ VALUE grpc_rb_mPropagateMasks = rb_define_module_under(grpc_rb_mGrpcCore, "PropagateMasks"); @@ -756,7 +764,7 @@ void Init_grpc_propagate_masks() { UINT2NUM(GRPC_PROPAGATE_DEFAULTS)); } -void Init_grpc_connectivity_states() { +static void Init_grpc_connectivity_states() { /* Constants representing call propagation masks in grpc.h */ VALUE grpc_rb_mConnectivityStates = rb_define_module_under(grpc_rb_mGrpcCore, "ConnectivityStates"); diff --git a/src/ruby/ext/grpc/rb_completion_queue.c b/src/ruby/ext/grpc/rb_completion_queue.c index 9f3a81b1a8b..fd75d2f691f 100644 --- a/src/ruby/ext/grpc/rb_completion_queue.c +++ b/src/ruby/ext/grpc/rb_completion_queue.c @@ -71,16 +71,12 @@ static void *grpc_rb_completion_queue_pluck_no_gil(void *param) { } /* Helper function to free a completion queue. */ -void grpc_rb_completion_queue_safe_destroy(grpc_completion_queue *cq) { - grpc_event ev; - +void grpc_rb_completion_queue_destroy(grpc_completion_queue *cq) { + /* Every function that adds an event to a queue also synchronously plucks + that event from the queue, and holds a reference to the Ruby object that + holds the queue, so we only get to this point if all of those functions + have completed, and the queue is empty */ grpc_completion_queue_shutdown(cq); - for(;;) { - ev = grpc_completion_queue_pluck(cq, NULL, gpr_inf_future(GPR_CLOCK_REALTIME), NULL); - if (ev.type == GRPC_QUEUE_SHUTDOWN) { - break; - } - } grpc_completion_queue_destroy(cq); } diff --git a/src/ruby/ext/grpc/rb_completion_queue.h b/src/ruby/ext/grpc/rb_completion_queue.h index eb041b28dfc..aa9dc6416af 100644 --- a/src/ruby/ext/grpc/rb_completion_queue.h +++ b/src/ruby/ext/grpc/rb_completion_queue.h @@ -38,7 +38,7 @@ #include -void grpc_rb_completion_queue_safe_destroy(grpc_completion_queue *cq); +void grpc_rb_completion_queue_destroy(grpc_completion_queue *cq); /** * Makes the implementation of CompletionQueue#pluck available in other files diff --git a/src/ruby/ext/grpc/rb_grpc.c b/src/ruby/ext/grpc/rb_grpc.c index 2a3b3391027..e0be5d7f087 100644 --- a/src/ruby/ext/grpc/rb_grpc.c +++ b/src/ruby/ext/grpc/rb_grpc.c @@ -42,7 +42,6 @@ #include #include -#include #include "rb_call.h" #include "rb_call_credentials.h" #include "rb_channel.h" diff --git a/src/ruby/ext/grpc/rb_server.c b/src/ruby/ext/grpc/rb_server.c index 2b0858c247e..2286a99f249 100644 --- a/src/ruby/ext/grpc/rb_server.c +++ b/src/ruby/ext/grpc/rb_server.c @@ -77,7 +77,7 @@ static void destroy_server(grpc_rb_server *server, gpr_timespec deadline) { gpr_inf_future(GPR_CLOCK_REALTIME), NULL); } grpc_server_destroy(server->wrapped); - grpc_rb_completion_queue_safe_destroy(server->queue); + grpc_rb_completion_queue_destroy(server->queue); server->wrapped = NULL; server->queue = NULL; } diff --git a/src/ruby/spec/channel_connection_spec.rb b/src/ruby/spec/channel_connection_spec.rb index b3edec8f938..c8a7856a099 100644 --- a/src/ruby/spec/channel_connection_spec.rb +++ b/src/ruby/spec/channel_connection_spec.rb @@ -143,8 +143,7 @@ describe 'channel connection behavior' do stop_server end - it 'observably connects and reconnects to transient server' \ - ' when using the channel state API' do + it 'concurrent watches on the same channel' do timeout(180) do port = start_server ch = GRPC::Core::Channel.new("localhost:#{port}", {}, From 6bf7782ee12925b7baeb722082568999fc98fa7a Mon Sep 17 00:00:00 2001 From: Matt Kwong Date: Wed, 17 May 2017 16:51:50 -0700 Subject: [PATCH 13/45] Add Python GCP API library installation to Alpine Dockerfiles --- tools/dockerfile/test/cxx_alpine_x64/Dockerfile | 3 +++ tools/dockerfile/test/python_alpine_x64/Dockerfile | 3 +++ 2 files changed, 6 insertions(+) diff --git a/tools/dockerfile/test/cxx_alpine_x64/Dockerfile b/tools/dockerfile/test/cxx_alpine_x64/Dockerfile index b13157f2807..fc62d230fb1 100644 --- a/tools/dockerfile/test/cxx_alpine_x64/Dockerfile +++ b/tools/dockerfile/test/cxx_alpine_x64/Dockerfile @@ -55,6 +55,9 @@ RUN pip install pip --upgrade RUN pip install virtualenv RUN pip install futures==2.2.0 enum34==1.0.4 protobuf==3.2.0 six==1.10.0 +# Google Cloud platform API libraries +RUN pip install --upgrade google-api-python-client + # Prepare ccache RUN ln -s /usr/bin/ccache /usr/local/bin/gcc RUN ln -s /usr/bin/ccache /usr/local/bin/g++ diff --git a/tools/dockerfile/test/python_alpine_x64/Dockerfile b/tools/dockerfile/test/python_alpine_x64/Dockerfile index bdffbd35982..5d25ab0ebed 100644 --- a/tools/dockerfile/test/python_alpine_x64/Dockerfile +++ b/tools/dockerfile/test/python_alpine_x64/Dockerfile @@ -55,6 +55,9 @@ RUN pip install pip --upgrade RUN pip install virtualenv RUN pip install futures==2.2.0 enum34==1.0.4 protobuf==3.2.0 six==1.10.0 +# Google Cloud platform API libraries +RUN pip install --upgrade google-api-python-client + # Prepare ccache RUN ln -s /usr/bin/ccache /usr/local/bin/gcc RUN ln -s /usr/bin/ccache /usr/local/bin/g++ From c24d53b0cfffe2cd78d53c0c86de43346dcc7ee7 Mon Sep 17 00:00:00 2001 From: Alexander Polcyn Date: Wed, 17 May 2017 20:25:38 -0700 Subject: [PATCH 14/45] api watch unblock func kills only its own channel --- ...multiple_killed_watching_threads_driver.rb | 56 +++++++++++++++++++ src/ruby/ext/grpc/rb_channel.c | 18 ++++-- .../helper_scripts/run_ruby_end2end_tests.sh | 1 + 3 files changed, 69 insertions(+), 6 deletions(-) create mode 100755 src/ruby/end2end/multiple_killed_watching_threads_driver.rb diff --git a/src/ruby/end2end/multiple_killed_watching_threads_driver.rb b/src/ruby/end2end/multiple_killed_watching_threads_driver.rb new file mode 100755 index 00000000000..0c98915b7ee --- /dev/null +++ b/src/ruby/end2end/multiple_killed_watching_threads_driver.rb @@ -0,0 +1,56 @@ +#!/usr/bin/env ruby + +# Copyright 2016, Google Inc. +# All rights reserved. +# +# Redistribution and use in source and binary forms, with or without +# modification, are permitted provided that the following conditions are +# met: +# +# * Redistributions of source code must retain the above copyright +# notice, this list of conditions and the following disclaimer. +# * Redistributions in binary form must reproduce the above +# copyright notice, this list of conditions and the following disclaimer +# in the documentation and/or other materials provided with the +# distribution. +# * Neither the name of Google Inc. nor the names of its +# contributors may be used to endorse or promote products derived from +# this software without specific prior written permission. +# +# THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS +# "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT +# LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR +# A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT +# OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, +# SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT +# LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, +# DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY +# THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +# (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE +# OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + +require_relative './end2end_common' + +Thread.abort_on_exception = true + +include GRPC::Core::ConnectivityStates + +def watch_state(ch) + thd = Thread.new do + state = ch.connectivity_state(false) + fail "non-idle state: #{state}" unless state == IDLE + ch.watch_connectivity_state(IDLE, Time.now + 360) + end + sleep 0.1 + thd.kill +end + +def main + 10.times do + ch = GRPC::Core::Channel.new('dummy_host', + nil, :this_channel_is_insecure) + watch_state(ch) + end +end + +main diff --git a/src/ruby/ext/grpc/rb_channel.c b/src/ruby/ext/grpc/rb_channel.c index e02dd0805d3..6e7baa31220 100644 --- a/src/ruby/ext/grpc/rb_channel.c +++ b/src/ruby/ext/grpc/rb_channel.c @@ -366,6 +366,16 @@ static void *wait_for_watch_state_op_complete_without_gvl(void *arg) { return success; } +static void wait_for_watch_state_op_complete_unblocking_func(void *arg) { + bg_watched_channel *bg = (bg_watched_channel *)arg; + gpr_mu_lock(&global_connection_polling_mu); + if (!bg->channel_destroyed) { + grpc_channel_destroy(bg->channel); + bg->channel_destroyed = 1; + } + gpr_mu_unlock(&global_connection_polling_mu); +} + /* Wait until the channel's connectivity state becomes different from * "last_state", or "deadline" expires. * Returns true if the the channel's connectivity state becomes @@ -400,7 +410,7 @@ static VALUE grpc_rb_channel_watch_connectivity_state(VALUE self, op_success = rb_thread_call_without_gvl( wait_for_watch_state_op_complete_without_gvl, &stack, - run_poll_channels_loop_unblocking_func, NULL); + wait_for_watch_state_op_complete_unblocking_func, wrapper->bg_wrapped); return op_success ? Qtrue : Qfalse; } @@ -577,11 +587,7 @@ static void grpc_rb_channel_try_register_connection_polling( return; } GPR_ASSERT(bg->refcount == 1); - if (bg->channel_destroyed) { - GPR_ASSERT(abort_channel_polling); - return; - } - if (abort_channel_polling) { + if (bg->channel_destroyed || abort_channel_polling) { return; } diff --git a/tools/run_tests/helper_scripts/run_ruby_end2end_tests.sh b/tools/run_tests/helper_scripts/run_ruby_end2end_tests.sh index 6688025260f..ab882d62bc7 100755 --- a/tools/run_tests/helper_scripts/run_ruby_end2end_tests.sh +++ b/tools/run_tests/helper_scripts/run_ruby_end2end_tests.sh @@ -41,4 +41,5 @@ ruby src/ruby/end2end/sig_int_during_channel_watch_driver.rb || EXIT_CODE=1 ruby src/ruby/end2end/killed_client_thread_driver.rb || EXIT_CODE=1 ruby src/ruby/end2end/forking_client_driver.rb || EXIT_CODE=1 ruby src/ruby/end2end/grpc_class_init_driver.rb || EXIT_CODE=1 +ruby src/ruby/end2end/multiple_killed_watching_threads_driver.rb || EXIT_CODE=1 exit $EXIT_CODE From d7455abfbd1394a6984b901a305785e9cba7b2d6 Mon Sep 17 00:00:00 2001 From: Alexander Polcyn Date: Wed, 17 May 2017 21:39:09 -0700 Subject: [PATCH 15/45] make get conn state always safe to call --- .../multiple_killed_watching_threads_driver.rb | 7 +++++++ src/ruby/ext/grpc/rb_channel.c | 12 ++++-------- 2 files changed, 11 insertions(+), 8 deletions(-) diff --git a/src/ruby/end2end/multiple_killed_watching_threads_driver.rb b/src/ruby/end2end/multiple_killed_watching_threads_driver.rb index 0c98915b7ee..206ec8e801f 100755 --- a/src/ruby/end2end/multiple_killed_watching_threads_driver.rb +++ b/src/ruby/end2end/multiple_killed_watching_threads_driver.rb @@ -46,10 +46,17 @@ def watch_state(ch) end def main + channels = [] 10.times do ch = GRPC::Core::Channel.new('dummy_host', nil, :this_channel_is_insecure) watch_state(ch) + channels << ch + end + + # checking state should still be safe to call + channels.each do |c| + fail unless c.connectivity_state(false) == FATAL_FAILURE end end diff --git a/src/ruby/ext/grpc/rb_channel.c b/src/ruby/ext/grpc/rb_channel.c index 6e7baa31220..0524c497100 100644 --- a/src/ruby/ext/grpc/rb_channel.c +++ b/src/ruby/ext/grpc/rb_channel.c @@ -273,7 +273,7 @@ static VALUE grpc_rb_channel_init(int argc, VALUE *argv, VALUE self) { } typedef struct get_state_stack { - grpc_channel *channel; + bg_watched_channel *bg; int try_to_connect; int out; } get_state_stack; @@ -283,14 +283,10 @@ static void *get_state_without_gil(void *arg) { gpr_mu_lock(&global_connection_polling_mu); GPR_ASSERT(abort_channel_polling || channel_polling_thread_started); - if (abort_channel_polling) { - // Assume that this channel has been destroyed by the - // background thread. - // The case in which the channel polling thread - // failed to start just always shows shutdown state. + if (stack->bg->channel_destroyed) { stack->out = GRPC_CHANNEL_SHUTDOWN; } else { - stack->out = grpc_channel_check_connectivity_state(stack->channel, + stack->out = grpc_channel_check_connectivity_state(stack->bg->channel, stack->try_to_connect); } gpr_mu_unlock(&global_connection_polling_mu); @@ -322,7 +318,7 @@ static VALUE grpc_rb_channel_get_connectivity_state(int argc, VALUE *argv, return Qnil; } - stack.channel = wrapper->bg_wrapped->channel; + stack.bg = wrapper->bg_wrapped; stack.try_to_connect = RTEST(try_to_connect_param) ? 1 : 0; rb_thread_call_without_gvl(get_state_without_gil, &stack, NULL, NULL); From 82fef0bce75fd18fb468ad8a9363040e6c6e84fc Mon Sep 17 00:00:00 2001 From: Alexander Polcyn Date: Wed, 17 May 2017 23:42:38 -0700 Subject: [PATCH 16/45] tentative fix for global side effect on interrupted constructor --- src/ruby/ext/grpc/rb_channel.c | 26 +++++++++++++++++++++----- 1 file changed, 21 insertions(+), 5 deletions(-) diff --git a/src/ruby/ext/grpc/rb_channel.c b/src/ruby/ext/grpc/rb_channel.c index 0524c497100..7aaa71eeafc 100644 --- a/src/ruby/ext/grpc/rb_channel.c +++ b/src/ruby/ext/grpc/rb_channel.c @@ -107,6 +107,7 @@ static bg_watched_channel *bg_watched_channel_list_head = NULL; static void grpc_rb_channel_try_register_connection_polling( bg_watched_channel *bg); static void *wait_until_channel_polling_thread_started_no_gil(void *); +static void wait_until_channel_polling_thread_started_unblocking_func(void *); static void *channel_init_try_register_connection_polling_without_gil( void *arg); @@ -227,12 +228,15 @@ static VALUE grpc_rb_channel_init(int argc, VALUE *argv, VALUE self) { char *target_chars = NULL; grpc_channel_args args; channel_init_try_register_stack stack; + int stop_waiting_for_thread_start = 0; MEMZERO(&args, grpc_channel_args, 1); grpc_ruby_once_init(); - rb_thread_call_without_gvl(wait_until_channel_polling_thread_started_no_gil, - NULL, run_poll_channels_loop_unblocking_func, - NULL); + rb_thread_call_without_gvl( + wait_until_channel_polling_thread_started_no_gil, + &stop_waiting_for_thread_start, + wait_until_channel_polling_thread_started_unblocking_func, + &stop_waiting_for_thread_start); /* "3" == 3 mandatory args */ rb_scan_args(argc, argv, "3", &target, &channel_args, &credentials); @@ -699,10 +703,11 @@ static VALUE run_poll_channels_loop(VALUE arg) { } static void *wait_until_channel_polling_thread_started_no_gil(void *arg) { - (void)arg; + int *stop_waiting = (int *)arg; gpr_log(GPR_DEBUG, "GRPC_RUBY: wait for channel polling thread to start"); gpr_mu_lock(&global_connection_polling_mu); - while (!channel_polling_thread_started && !abort_channel_polling) { + while (!channel_polling_thread_started && !abort_channel_polling && + !*stop_waiting) { gpr_cv_wait(&global_connection_polling_cv, &global_connection_polling_mu, gpr_inf_future(GPR_CLOCK_REALTIME)); } @@ -711,6 +716,17 @@ static void *wait_until_channel_polling_thread_started_no_gil(void *arg) { return NULL; } +static void wait_until_channel_polling_thread_started_unblocking_func( + void *arg) { + int *stop_waiting = (int *)arg; + gpr_mu_lock(&global_connection_polling_mu); + gpr_log(GPR_DEBUG, + "GRPC_RUBY: interrupt wait for channel polling thread to start"); + *stop_waiting = 1; + gpr_cv_broadcast(&global_connection_polling_cv); + gpr_mu_unlock(&global_connection_polling_mu); +} + static void *set_abort_channel_polling_without_gil(void *arg) { (void)arg; gpr_mu_lock(&global_connection_polling_mu); From 92eb7fbc05903def20434c110193481913c2e38a Mon Sep 17 00:00:00 2001 From: Alexander Polcyn Date: Thu, 18 May 2017 11:49:15 -0700 Subject: [PATCH 17/45] Bump to version 1.3.4 --- BUILD | 2 +- CMakeLists.txt | 2 +- Makefile | 4 ++-- build.yaml | 2 +- gRPC-Core.podspec | 2 +- gRPC-ProtoRPC.podspec | 2 +- gRPC-RxLibrary.podspec | 2 +- gRPC.podspec | 2 +- package.json | 2 +- package.xml | 4 ++-- src/cpp/common/version_cc.cc | 2 +- src/csharp/Grpc.Core/Version.csproj.include | 2 +- src/csharp/Grpc.Core/VersionInfo.cs | 4 ++-- src/csharp/build_packages_dotnetcli.bat | 2 +- src/csharp/build_packages_dotnetcli.sh | 4 ++-- src/node/health_check/package.json | 4 ++-- src/node/tools/package.json | 2 +- src/objective-c/!ProtoCompiler-gRPCPlugin.podspec | 2 +- src/objective-c/GRPCClient/private/version.h | 2 +- src/php/composer.json | 2 +- src/python/grpcio/grpc_version.py | 2 +- src/python/grpcio_health_checking/grpc_version.py | 2 +- src/python/grpcio_reflection/grpc_version.py | 2 +- src/python/grpcio_tests/grpc_version.py | 2 +- src/ruby/lib/grpc/version.rb | 2 +- src/ruby/tools/version.rb | 2 +- tools/distrib/python/grpcio_tools/grpc_version.py | 2 +- tools/doxygen/Doxyfile.c++ | 2 +- tools/doxygen/Doxyfile.c++.internal | 2 +- 29 files changed, 34 insertions(+), 34 deletions(-) diff --git a/BUILD b/BUILD index a0d80cd5735..51314f645c0 100644 --- a/BUILD +++ b/BUILD @@ -42,7 +42,7 @@ g_stands_for = "gentle" core_version = "3.0.0" -version = "1.3.3" +version = "1.3.4" grpc_cc_library( name = "gpr", diff --git a/CMakeLists.txt b/CMakeLists.txt index 279e12bbd0b..e344e413d15 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -39,7 +39,7 @@ cmake_minimum_required(VERSION 2.8) set(PACKAGE_NAME "grpc") -set(PACKAGE_VERSION "1.3.3") +set(PACKAGE_VERSION "1.3.4") set(PACKAGE_STRING "${PACKAGE_NAME} ${PACKAGE_VERSION}") set(PACKAGE_TARNAME "${PACKAGE_NAME}-${PACKAGE_VERSION}") set(PACKAGE_BUGREPORT "https://github.com/grpc/grpc/issues/") diff --git a/Makefile b/Makefile index e5f23e75ad6..88bb5b5e5f9 100644 --- a/Makefile +++ b/Makefile @@ -420,8 +420,8 @@ Q = @ endif CORE_VERSION = 3.0.0 -CPP_VERSION = 1.3.3 -CSHARP_VERSION = 1.3.3 +CPP_VERSION = 1.3.4 +CSHARP_VERSION = 1.3.4 CPPFLAGS_NO_ARCH += $(addprefix -I, $(INCLUDES)) $(addprefix -D, $(DEFINES)) CPPFLAGS += $(CPPFLAGS_NO_ARCH) $(ARCH_FLAGS) diff --git a/build.yaml b/build.yaml index 5d1e74b93a8..a42c9cf5500 100644 --- a/build.yaml +++ b/build.yaml @@ -14,7 +14,7 @@ settings: '#10': See the expand_version.py for all the quirks here core_version: 3.0.0 g_stands_for: gentle - version: 1.3.3 + version: 1.3.4 filegroups: - name: census public_headers: diff --git a/gRPC-Core.podspec b/gRPC-Core.podspec index a2237ac0855..c8e50b577ac 100644 --- a/gRPC-Core.podspec +++ b/gRPC-Core.podspec @@ -37,7 +37,7 @@ Pod::Spec.new do |s| s.name = 'gRPC-Core' - version = '1.3.3' + version = '1.3.4' s.version = version s.summary = 'Core cross-platform gRPC library, written in C' s.homepage = 'http://www.grpc.io' diff --git a/gRPC-ProtoRPC.podspec b/gRPC-ProtoRPC.podspec index 1af811aa558..6737e0136a8 100644 --- a/gRPC-ProtoRPC.podspec +++ b/gRPC-ProtoRPC.podspec @@ -36,7 +36,7 @@ Pod::Spec.new do |s| s.name = 'gRPC-ProtoRPC' - version = '1.3.3' + version = '1.3.4' s.version = version s.summary = 'RPC library for Protocol Buffers, based on gRPC' s.homepage = 'http://www.grpc.io' diff --git a/gRPC-RxLibrary.podspec b/gRPC-RxLibrary.podspec index 3f720f2393f..0b338d44aaf 100644 --- a/gRPC-RxLibrary.podspec +++ b/gRPC-RxLibrary.podspec @@ -36,7 +36,7 @@ Pod::Spec.new do |s| s.name = 'gRPC-RxLibrary' - version = '1.3.3' + version = '1.3.4' s.version = version s.summary = 'Reactive Extensions library for iOS/OSX.' s.homepage = 'http://www.grpc.io' diff --git a/gRPC.podspec b/gRPC.podspec index b064c50ccfd..1783df67ef5 100644 --- a/gRPC.podspec +++ b/gRPC.podspec @@ -35,7 +35,7 @@ Pod::Spec.new do |s| s.name = 'gRPC' - version = '1.3.3' + version = '1.3.4' s.version = version s.summary = 'gRPC client library for iOS/OSX' s.homepage = 'http://www.grpc.io' diff --git a/package.json b/package.json index 2cb86a65a30..11e34416520 100644 --- a/package.json +++ b/package.json @@ -1,6 +1,6 @@ { "name": "grpc", - "version": "1.3.3", + "version": "1.3.4", "author": "Google Inc.", "description": "gRPC Library for Node", "homepage": "http://www.grpc.io/", diff --git a/package.xml b/package.xml index faf36657577..6b3eddadf6d 100644 --- a/package.xml +++ b/package.xml @@ -13,8 +13,8 @@ 2017-05-05 - 1.3.3 - 1.3.3 + 1.3.4 + 1.3.4 beta diff --git a/src/cpp/common/version_cc.cc b/src/cpp/common/version_cc.cc index 2d44fb9d084..97437ba5308 100644 --- a/src/cpp/common/version_cc.cc +++ b/src/cpp/common/version_cc.cc @@ -37,5 +37,5 @@ #include namespace grpc { -grpc::string Version() { return "1.3.3"; } +grpc::string Version() { return "1.3.4"; } } diff --git a/src/csharp/Grpc.Core/Version.csproj.include b/src/csharp/Grpc.Core/Version.csproj.include index 9ececc9b95a..881c311b17e 100755 --- a/src/csharp/Grpc.Core/Version.csproj.include +++ b/src/csharp/Grpc.Core/Version.csproj.include @@ -1,7 +1,7 @@ - 1.3.3 + 1.3.4 3.2.0 diff --git a/src/csharp/Grpc.Core/VersionInfo.cs b/src/csharp/Grpc.Core/VersionInfo.cs index 12cbc6f0491..bbe5a17d6b7 100644 --- a/src/csharp/Grpc.Core/VersionInfo.cs +++ b/src/csharp/Grpc.Core/VersionInfo.cs @@ -48,11 +48,11 @@ namespace Grpc.Core /// /// Current AssemblyFileVersion of gRPC C# assemblies /// - public const string CurrentAssemblyFileVersion = "1.3.3.0"; + public const string CurrentAssemblyFileVersion = "1.3.4.0"; /// /// Current version of gRPC C# /// - public const string CurrentVersion = "1.3.3"; + public const string CurrentVersion = "1.3.4"; } } diff --git a/src/csharp/build_packages_dotnetcli.bat b/src/csharp/build_packages_dotnetcli.bat index 6806bbd2ae5..a385ac74e3e 100755 --- a/src/csharp/build_packages_dotnetcli.bat +++ b/src/csharp/build_packages_dotnetcli.bat @@ -28,7 +28,7 @@ @rem OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. @rem Current package versions -set VERSION=1.3.3 +set VERSION=1.3.4 @rem Adjust the location of nuget.exe set NUGET=C:\nuget\nuget.exe diff --git a/src/csharp/build_packages_dotnetcli.sh b/src/csharp/build_packages_dotnetcli.sh index fc9fd50f596..66c41d4d940 100755 --- a/src/csharp/build_packages_dotnetcli.sh +++ b/src/csharp/build_packages_dotnetcli.sh @@ -70,7 +70,7 @@ dotnet pack --configuration Release --include-symbols --include-source Grpc.Auth dotnet pack --configuration Release --include-symbols --include-source Grpc.HealthCheck --output ../../../artifacts dotnet pack --configuration Release --include-symbols --include-source Grpc.Reflection --output ../../../artifacts -nuget pack Grpc.nuspec -Version "1.3.3" -OutputDirectory ../../artifacts -nuget pack Grpc.Tools.nuspec -Version "1.3.3" -OutputDirectory ../../artifacts +nuget pack Grpc.nuspec -Version "1.3.4" -OutputDirectory ../../artifacts +nuget pack Grpc.Tools.nuspec -Version "1.3.4" -OutputDirectory ../../artifacts (cd ../../artifacts && zip csharp_nugets_dotnetcli.zip *.nupkg) diff --git a/src/node/health_check/package.json b/src/node/health_check/package.json index fe36fb2693d..6329cd9c377 100644 --- a/src/node/health_check/package.json +++ b/src/node/health_check/package.json @@ -1,6 +1,6 @@ { "name": "grpc-health-check", - "version": "1.3.3", + "version": "1.3.4", "author": "Google Inc.", "description": "Health check service for use with gRPC", "repository": { @@ -15,7 +15,7 @@ } ], "dependencies": { - "grpc": "^1.3.3", + "grpc": "^1.3.4", "lodash": "^3.9.3", "google-protobuf": "^3.0.0" }, diff --git a/src/node/tools/package.json b/src/node/tools/package.json index caf2b5a5cb9..355ae2fdc1f 100644 --- a/src/node/tools/package.json +++ b/src/node/tools/package.json @@ -1,6 +1,6 @@ { "name": "grpc-tools", - "version": "1.3.3", + "version": "1.3.4", "author": "Google Inc.", "description": "Tools for developing with gRPC on Node.js", "homepage": "http://www.grpc.io/", diff --git a/src/objective-c/!ProtoCompiler-gRPCPlugin.podspec b/src/objective-c/!ProtoCompiler-gRPCPlugin.podspec index 4e93c0f1b53..b4fc9685049 100644 --- a/src/objective-c/!ProtoCompiler-gRPCPlugin.podspec +++ b/src/objective-c/!ProtoCompiler-gRPCPlugin.podspec @@ -42,7 +42,7 @@ Pod::Spec.new do |s| # exclamation mark ensures that other "regular" pods will be able to find it as it'll be installed # before them. s.name = '!ProtoCompiler-gRPCPlugin' - v = '1.3.3' + v = '1.3.4' s.version = v s.summary = 'The gRPC ProtoC plugin generates Objective-C files from .proto services.' s.description = <<-DESC diff --git a/src/objective-c/GRPCClient/private/version.h b/src/objective-c/GRPCClient/private/version.h index 66408f5bbb3..ccf96230bc1 100644 --- a/src/objective-c/GRPCClient/private/version.h +++ b/src/objective-c/GRPCClient/private/version.h @@ -38,4 +38,4 @@ // `tools/buildgen/generate_projects.sh`. -#define GRPC_OBJC_VERSION_STRING @"1.3.3" +#define GRPC_OBJC_VERSION_STRING @"1.3.4" diff --git a/src/php/composer.json b/src/php/composer.json index bbe33974d5e..562859e6b3d 100644 --- a/src/php/composer.json +++ b/src/php/composer.json @@ -2,7 +2,7 @@ "name": "grpc/grpc-dev", "description": "gRPC library for PHP - for Developement use only", "license": "BSD-3-Clause", - "version": "1.3.3", + "version": "1.3.4", "require": { "php": ">=5.5.0", "google/protobuf": "^v3.1.0" diff --git a/src/python/grpcio/grpc_version.py b/src/python/grpcio/grpc_version.py index 027f6caf28c..29ffcab1065 100644 --- a/src/python/grpcio/grpc_version.py +++ b/src/python/grpcio/grpc_version.py @@ -29,4 +29,4 @@ # AUTO-GENERATED FROM `$REPO_ROOT/templates/src/python/grpcio/grpc_version.py.template`!!! -VERSION='1.3.3' +VERSION='1.3.4' diff --git a/src/python/grpcio_health_checking/grpc_version.py b/src/python/grpcio_health_checking/grpc_version.py index f2db8bb056f..16e0dc13275 100644 --- a/src/python/grpcio_health_checking/grpc_version.py +++ b/src/python/grpcio_health_checking/grpc_version.py @@ -29,4 +29,4 @@ # AUTO-GENERATED FROM `$REPO_ROOT/templates/src/python/grpcio_health_checking/grpc_version.py.template`!!! -VERSION='1.3.3' +VERSION='1.3.4' diff --git a/src/python/grpcio_reflection/grpc_version.py b/src/python/grpcio_reflection/grpc_version.py index 3f33eb3ed55..5ef0ed8045e 100644 --- a/src/python/grpcio_reflection/grpc_version.py +++ b/src/python/grpcio_reflection/grpc_version.py @@ -29,4 +29,4 @@ # AUTO-GENERATED FROM `$REPO_ROOT/templates/src/python/grpcio_reflection/grpc_version.py.template`!!! -VERSION='1.3.3' +VERSION='1.3.4' diff --git a/src/python/grpcio_tests/grpc_version.py b/src/python/grpcio_tests/grpc_version.py index 1a681d01360..7e4c57e6ec6 100644 --- a/src/python/grpcio_tests/grpc_version.py +++ b/src/python/grpcio_tests/grpc_version.py @@ -29,4 +29,4 @@ # AUTO-GENERATED FROM `$REPO_ROOT/templates/src/python/grpcio_tests/grpc_version.py.template`!!! -VERSION='1.3.3' +VERSION='1.3.4' diff --git a/src/ruby/lib/grpc/version.rb b/src/ruby/lib/grpc/version.rb index 4ab94c91324..c03ec97196b 100644 --- a/src/ruby/lib/grpc/version.rb +++ b/src/ruby/lib/grpc/version.rb @@ -29,5 +29,5 @@ # GRPC contains the General RPC module. module GRPC - VERSION = '1.3.3' + VERSION = '1.3.4' end diff --git a/src/ruby/tools/version.rb b/src/ruby/tools/version.rb index 58e05d08143..fe0fb2cef21 100644 --- a/src/ruby/tools/version.rb +++ b/src/ruby/tools/version.rb @@ -29,6 +29,6 @@ module GRPC module Tools - VERSION = '1.3.3' + VERSION = '1.3.4' end end diff --git a/tools/distrib/python/grpcio_tools/grpc_version.py b/tools/distrib/python/grpcio_tools/grpc_version.py index ecfa9d85e36..020785aa730 100644 --- a/tools/distrib/python/grpcio_tools/grpc_version.py +++ b/tools/distrib/python/grpcio_tools/grpc_version.py @@ -29,4 +29,4 @@ # AUTO-GENERATED FROM `$REPO_ROOT/templates/tools/distrib/python/grpcio_tools/grpc_version.py.template`!!! -VERSION='1.3.3' +VERSION='1.3.4' diff --git a/tools/doxygen/Doxyfile.c++ b/tools/doxygen/Doxyfile.c++ index 8067aa764c1..5021a1a153b 100644 --- a/tools/doxygen/Doxyfile.c++ +++ b/tools/doxygen/Doxyfile.c++ @@ -40,7 +40,7 @@ PROJECT_NAME = "GRPC C++" # could be handy for archiving the generated documentation or if some version # control system is used. -PROJECT_NUMBER = 1.3.3 +PROJECT_NUMBER = 1.3.4 # Using the PROJECT_BRIEF tag one can provide an optional one line description # for a project that appears at the top of each page and should give viewer a diff --git a/tools/doxygen/Doxyfile.c++.internal b/tools/doxygen/Doxyfile.c++.internal index 1a94b01e35e..1df6951aef2 100644 --- a/tools/doxygen/Doxyfile.c++.internal +++ b/tools/doxygen/Doxyfile.c++.internal @@ -40,7 +40,7 @@ PROJECT_NAME = "GRPC C++" # could be handy for archiving the generated documentation or if some version # control system is used. -PROJECT_NUMBER = 1.3.3 +PROJECT_NUMBER = 1.3.4 # Using the PROJECT_BRIEF tag one can provide an optional one line description # for a project that appears at the top of each page and should give viewer a From c3b1f18a7e7f443329f95ff25485c503ab76cc69 Mon Sep 17 00:00:00 2001 From: Alexander Polcyn Date: Tue, 18 Apr 2017 13:51:36 -0700 Subject: [PATCH 18/45] get rid of connectivity state watchers right after timeout --- CMakeLists.txt | 32 +++ Makefile | 36 +++ build.yaml | 12 + grpc.def | 1 + include/grpc/grpc.h | 6 + .../client_channel/channel_connectivity.c | 77 ++++-- .../filters/client_channel/client_channel.c | 115 ++++++++- .../filters/client_channel/client_channel.h | 6 +- src/ruby/ext/grpc/rb_grpc_imports.generated.c | 2 + src/ruby/ext/grpc/rb_grpc_imports.generated.h | 3 + .../surface/concurrent_connectivity_test.c | 69 +++++- .../num_external_connectivity_watchers_test.c | 221 ++++++++++++++++++ .../surface/sequential_connectivity_test.c | 3 + .../generated/sources_and_headers.json | 17 ++ tools/run_tests/generated/tests.json | 24 ++ vsprojects/buildtests_c.sln | 27 +++ ...xternal_connectivity_watchers_test.vcxproj | 199 ++++++++++++++++ ...connectivity_watchers_test.vcxproj.filters | 21 ++ 18 files changed, 837 insertions(+), 34 deletions(-) create mode 100644 test/core/surface/num_external_connectivity_watchers_test.c create mode 100644 vsprojects/vcxproj/test/num_external_connectivity_watchers_test/num_external_connectivity_watchers_test.vcxproj create mode 100644 vsprojects/vcxproj/test/num_external_connectivity_watchers_test/num_external_connectivity_watchers_test.vcxproj.filters diff --git a/CMakeLists.txt b/CMakeLists.txt index 81dba56b9ef..553caab8806 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -475,6 +475,7 @@ add_dependencies(buildtests_c mlog_test) add_dependencies(buildtests_c multiple_server_queues_test) add_dependencies(buildtests_c murmur_hash_test) add_dependencies(buildtests_c no_server_test) +add_dependencies(buildtests_c num_external_connectivity_watchers_test) add_dependencies(buildtests_c parse_address_test) add_dependencies(buildtests_c percent_encoding_test) if(_gRPC_PLATFORM_LINUX) @@ -7580,6 +7581,37 @@ target_link_libraries(no_server_test endif (gRPC_BUILD_TESTS) if (gRPC_BUILD_TESTS) +add_executable(num_external_connectivity_watchers_test + test/core/surface/num_external_connectivity_watchers_test.c +) + + +target_include_directories(num_external_connectivity_watchers_test + PRIVATE ${CMAKE_CURRENT_SOURCE_DIR} + PRIVATE ${CMAKE_CURRENT_SOURCE_DIR}/include + PRIVATE ${BORINGSSL_ROOT_DIR}/include + PRIVATE ${PROTOBUF_ROOT_DIR}/src + PRIVATE ${BENCHMARK_ROOT_DIR}/include + PRIVATE ${ZLIB_ROOT_DIR} + PRIVATE ${CMAKE_CURRENT_BINARY_DIR}/third_party/zlib + PRIVATE ${CARES_BUILD_INCLUDE_DIR} + PRIVATE ${CARES_INCLUDE_DIR} + PRIVATE ${CARES_PLATFORM_INCLUDE_DIR} + PRIVATE ${CMAKE_CURRENT_BINARY_DIR}/third_party/cares/cares + PRIVATE ${CMAKE_CURRENT_BINARY_DIR}/third_party/gflags/include +) + +target_link_libraries(num_external_connectivity_watchers_test + ${_gRPC_ALLTARGETS_LIBRARIES} + grpc_test_util + grpc + gpr_test_util + gpr +) + +endif (gRPC_BUILD_TESTS) +if (gRPC_BUILD_TESTS) + add_executable(parse_address_test test/core/client_channel/parse_address_test.c ) diff --git a/Makefile b/Makefile index 9e3daabe405..68dc9de4926 100644 --- a/Makefile +++ b/Makefile @@ -1056,6 +1056,7 @@ murmur_hash_test: $(BINDIR)/$(CONFIG)/murmur_hash_test nanopb_fuzzer_response_test: $(BINDIR)/$(CONFIG)/nanopb_fuzzer_response_test nanopb_fuzzer_serverlist_test: $(BINDIR)/$(CONFIG)/nanopb_fuzzer_serverlist_test no_server_test: $(BINDIR)/$(CONFIG)/no_server_test +num_external_connectivity_watchers_test: $(BINDIR)/$(CONFIG)/num_external_connectivity_watchers_test parse_address_test: $(BINDIR)/$(CONFIG)/parse_address_test percent_decode_fuzzer: $(BINDIR)/$(CONFIG)/percent_decode_fuzzer percent_encode_fuzzer: $(BINDIR)/$(CONFIG)/percent_encode_fuzzer @@ -1427,6 +1428,7 @@ buildtests_c: privatelibs_c \ $(BINDIR)/$(CONFIG)/multiple_server_queues_test \ $(BINDIR)/$(CONFIG)/murmur_hash_test \ $(BINDIR)/$(CONFIG)/no_server_test \ + $(BINDIR)/$(CONFIG)/num_external_connectivity_watchers_test \ $(BINDIR)/$(CONFIG)/parse_address_test \ $(BINDIR)/$(CONFIG)/percent_encoding_test \ $(BINDIR)/$(CONFIG)/pollset_set_test \ @@ -1883,6 +1885,8 @@ test_c: buildtests_c $(Q) $(BINDIR)/$(CONFIG)/murmur_hash_test || ( echo test murmur_hash_test failed ; exit 1 ) $(E) "[RUN] Testing no_server_test" $(Q) $(BINDIR)/$(CONFIG)/no_server_test || ( echo test no_server_test failed ; exit 1 ) + $(E) "[RUN] Testing num_external_connectivity_watchers_test" + $(Q) $(BINDIR)/$(CONFIG)/num_external_connectivity_watchers_test || ( echo test num_external_connectivity_watchers_test failed ; exit 1 ) $(E) "[RUN] Testing parse_address_test" $(Q) $(BINDIR)/$(CONFIG)/parse_address_test || ( echo test parse_address_test failed ; exit 1 ) $(E) "[RUN] Testing percent_encoding_test" @@ -11810,6 +11814,38 @@ endif endif +NUM_EXTERNAL_CONNECTIVITY_WATCHERS_TEST_SRC = \ + test/core/surface/num_external_connectivity_watchers_test.c \ + +NUM_EXTERNAL_CONNECTIVITY_WATCHERS_TEST_OBJS = $(addprefix $(OBJDIR)/$(CONFIG)/, $(addsuffix .o, $(basename $(NUM_EXTERNAL_CONNECTIVITY_WATCHERS_TEST_SRC)))) +ifeq ($(NO_SECURE),true) + +# You can't build secure targets if you don't have OpenSSL. + +$(BINDIR)/$(CONFIG)/num_external_connectivity_watchers_test: openssl_dep_error + +else + + + +$(BINDIR)/$(CONFIG)/num_external_connectivity_watchers_test: $(NUM_EXTERNAL_CONNECTIVITY_WATCHERS_TEST_OBJS) $(LIBDIR)/$(CONFIG)/libgrpc_test_util.a $(LIBDIR)/$(CONFIG)/libgrpc.a $(LIBDIR)/$(CONFIG)/libgpr_test_util.a $(LIBDIR)/$(CONFIG)/libgpr.a + $(E) "[LD] Linking $@" + $(Q) mkdir -p `dirname $@` + $(Q) $(LD) $(LDFLAGS) $(NUM_EXTERNAL_CONNECTIVITY_WATCHERS_TEST_OBJS) $(LIBDIR)/$(CONFIG)/libgrpc_test_util.a $(LIBDIR)/$(CONFIG)/libgrpc.a $(LIBDIR)/$(CONFIG)/libgpr_test_util.a $(LIBDIR)/$(CONFIG)/libgpr.a $(LDLIBS) $(LDLIBS_SECURE) -o $(BINDIR)/$(CONFIG)/num_external_connectivity_watchers_test + +endif + +$(OBJDIR)/$(CONFIG)/test/core/surface/num_external_connectivity_watchers_test.o: $(LIBDIR)/$(CONFIG)/libgrpc_test_util.a $(LIBDIR)/$(CONFIG)/libgrpc.a $(LIBDIR)/$(CONFIG)/libgpr_test_util.a $(LIBDIR)/$(CONFIG)/libgpr.a + +deps_num_external_connectivity_watchers_test: $(NUM_EXTERNAL_CONNECTIVITY_WATCHERS_TEST_OBJS:.o=.dep) + +ifneq ($(NO_SECURE),true) +ifneq ($(NO_DEPS),true) +-include $(NUM_EXTERNAL_CONNECTIVITY_WATCHERS_TEST_OBJS:.o=.dep) +endif +endif + + PARSE_ADDRESS_TEST_SRC = \ test/core/client_channel/parse_address_test.c \ diff --git a/build.yaml b/build.yaml index 5f23562022a..cb9e67ff0b4 100644 --- a/build.yaml +++ b/build.yaml @@ -2586,6 +2586,18 @@ targets: - grpc - gpr_test_util - gpr +- name: num_external_connectivity_watchers_test + build: test + language: c + src: + - test/core/surface/num_external_connectivity_watchers_test.c + deps: + - grpc_test_util + - grpc + - gpr_test_util + - gpr + exclude_iomgrs: + - uv - name: parse_address_test build: test language: c diff --git a/grpc.def b/grpc.def index 1589316a588..534a23d6000 100644 --- a/grpc.def +++ b/grpc.def @@ -65,6 +65,7 @@ EXPORTS grpc_alarm_cancel grpc_alarm_destroy grpc_channel_check_connectivity_state + grpc_channel_num_external_connectivity_watchers grpc_channel_watch_connectivity_state grpc_channel_create_call grpc_channel_ping diff --git a/include/grpc/grpc.h b/include/grpc/grpc.h index e088435d6cc..bdb86174118 100644 --- a/include/grpc/grpc.h +++ b/include/grpc/grpc.h @@ -225,6 +225,12 @@ GRPCAPI void grpc_alarm_destroy(grpc_alarm *alarm); GRPCAPI grpc_connectivity_state grpc_channel_check_connectivity_state( grpc_channel *channel, int try_to_connect); +/** Number of active "external connectivity state watchers" attached to a + * channel. + * Useful for testing. **/ +GRPCAPI int grpc_channel_num_external_connectivity_watchers( + grpc_channel *channel); + /** Watch for a change in connectivity state. Once the channel connectivity state is different from last_observed_state, tag will be enqueued on cq with success=1. diff --git a/src/core/ext/filters/client_channel/channel_connectivity.c b/src/core/ext/filters/client_channel/channel_connectivity.c index 62f58fb278a..5f3ffd49470 100644 --- a/src/core/ext/filters/client_channel/channel_connectivity.c +++ b/src/core/ext/filters/client_channel/channel_connectivity.c @@ -67,9 +67,8 @@ grpc_connectivity_state grpc_channel_check_connectivity_state( typedef enum { WAITING, - CALLING_BACK, + READY_TO_CALL_BACK, CALLING_BACK_AND_FINISHED, - CALLED_BACK } callback_phase; typedef struct { @@ -77,11 +76,13 @@ typedef struct { 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; @@ -105,11 +106,8 @@ static void finished_completion(grpc_exec_ctx *exec_ctx, void *pw, gpr_mu_lock(&w->mu); switch (w->phase) { case WAITING: - case CALLED_BACK: + case READY_TO_CALL_BACK: GPR_UNREACHABLE_CODE(return ); - case CALLING_BACK: - w->phase = CALLED_BACK; - break; case CALLING_BACK_AND_FINISHED: delete = 1; break; @@ -123,10 +121,14 @@ static void finished_completion(grpc_exec_ctx *exec_ctx, void *pw, static void partly_done(grpc_exec_ctx *exec_ctx, state_watcher *w, bool due_to_completion, grpc_error *error) { - int delete = 0; - 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_cq_pollset(w->cq), NULL, + &w->on_complete, NULL); } gpr_mu_lock(&w->mu); @@ -147,25 +149,27 @@ static void partly_done(grpc_exec_ctx *exec_ctx, state_watcher *w, } switch (w->phase) { case WAITING: - w->phase = CALLING_BACK; - grpc_cq_end_op(exec_ctx, w->cq, w->tag, GRPC_ERROR_REF(error), - finished_completion, w, &w->completion_storage); + GRPC_ERROR_REF(error); + w->error = error; + w->phase = READY_TO_CALL_BACK; break; - case CALLING_BACK: + 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 ); - case CALLED_BACK: - delete = 1; break; } gpr_mu_unlock(&w->mu); - if (delete) { - delete_state_watcher(exec_ctx, w); - } - GRPC_ERROR_UNREF(error); } @@ -179,6 +183,28 @@ static void timeout_complete(grpc_exec_ctx *exec_ctx, void *pw, partly_done(exec_ctx, 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)); + return grpc_client_channel_num_external_connectivity_watchers( + client_channel_elem); +} + +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( grpc_channel *channel, grpc_connectivity_state last_observed_state, gpr_timespec deadline, grpc_completion_queue *cq, void *tag) { @@ -208,16 +234,19 @@ void grpc_channel_watch_connectivity_state( w->cq = cq; w->tag = tag; w->channel = channel; + w->error = NULL; - grpc_timer_init(&exec_ctx, &w->alarm, - gpr_convert_clock_type(deadline, GPR_CLOCK_MONOTONIC), - &w->on_timeout, gpr_now(GPR_CLOCK_MONOTONIC)); + watcher_timer_init_arg *wa = 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_cq_pollset(cq), &w->state, - &w->on_complete); + grpc_client_channel_watch_connectivity_state( + &exec_ctx, client_channel_elem, grpc_cq_pollset(cq), &w->state, + &w->on_complete, &w->watcher_timer_init); } else { abort(); } diff --git a/src/core/ext/filters/client_channel/client_channel.c b/src/core/ext/filters/client_channel/client_channel.c index 83e3b8f118d..4bd153e8ac7 100644 --- a/src/core/ext/filters/client_channel/client_channel.c +++ b/src/core/ext/filters/client_channel/client_channel.c @@ -174,6 +174,8 @@ static void *method_parameters_create_from_json(const grpc_json *json) { return value; } +struct external_connectivity_watcher; + /************************************************************************* * CHANNEL-WIDE FUNCTIONS */ @@ -209,6 +211,11 @@ typedef struct client_channel_channel_data { /** interested parties (owned) */ grpc_pollset_set *interested_parties; + /* external_connectivity_watcher_list head is guarded by its own mutex, since + * counts need to be grabbed immediately without polling on a cq */ + gpr_mu external_connectivity_watcher_list_mu; + struct external_connectivity_watcher *external_connectivity_watcher_list_head; + /* the following properties are guarded by a mutex since API's require them to be instantaneously available */ gpr_mu info_mu; @@ -632,6 +639,12 @@ static grpc_error *cc_init_channel_elem(grpc_exec_ctx *exec_ctx, // Initialize data members. chand->combiner = grpc_combiner_create(NULL); gpr_mu_init(&chand->info_mu); + gpr_mu_init(&chand->external_connectivity_watcher_list_mu); + + gpr_mu_lock(&chand->external_connectivity_watcher_list_mu); + chand->external_connectivity_watcher_list_head = NULL; + gpr_mu_unlock(&chand->external_connectivity_watcher_list_mu); + chand->owning_stack = args->channel_stack; grpc_closure_init(&chand->on_resolver_result_changed, on_resolver_result_changed_locked, chand, @@ -718,6 +731,7 @@ static void cc_destroy_channel_elem(grpc_exec_ctx *exec_ctx, grpc_pollset_set_destroy(exec_ctx, chand->interested_parties); GRPC_COMBINER_UNREF(exec_ctx, chand->combiner, "client_channel"); gpr_mu_destroy(&chand->info_mu); + gpr_mu_destroy(&chand->external_connectivity_watcher_list_mu); } /************************************************************************* @@ -1361,14 +1375,79 @@ grpc_connectivity_state grpc_client_channel_check_connectivity_state( return out; } -typedef struct { +typedef struct external_connectivity_watcher { channel_data *chand; grpc_pollset *pollset; grpc_closure *on_complete; + grpc_closure *watcher_timer_init; grpc_connectivity_state *state; grpc_closure my_closure; + struct external_connectivity_watcher *next; } external_connectivity_watcher; +static external_connectivity_watcher *lookup_external_connectivity_watcher( + channel_data *chand, grpc_closure *on_complete) { + gpr_mu_lock(&chand->external_connectivity_watcher_list_mu); + external_connectivity_watcher *w = + chand->external_connectivity_watcher_list_head; + while (w != NULL && w->on_complete != on_complete) { + w = w->next; + } + gpr_mu_unlock(&chand->external_connectivity_watcher_list_mu); + return w; +} + +static void external_connectivity_watcher_list_append( + channel_data *chand, external_connectivity_watcher *w) { + GPR_ASSERT(!lookup_external_connectivity_watcher(chand, w->on_complete)); + + gpr_mu_lock(&w->chand->external_connectivity_watcher_list_mu); + GPR_ASSERT(!w->next); + w->next = chand->external_connectivity_watcher_list_head; + chand->external_connectivity_watcher_list_head = w; + gpr_mu_unlock(&w->chand->external_connectivity_watcher_list_mu); +} + +static void external_connectivity_watcher_list_remove( + channel_data *chand, external_connectivity_watcher *too_remove) { + GPR_ASSERT( + lookup_external_connectivity_watcher(chand, too_remove->on_complete)); + gpr_mu_lock(&chand->external_connectivity_watcher_list_mu); + if (too_remove == chand->external_connectivity_watcher_list_head) { + chand->external_connectivity_watcher_list_head = too_remove->next; + gpr_mu_unlock(&chand->external_connectivity_watcher_list_mu); + return; + } + external_connectivity_watcher *w = + chand->external_connectivity_watcher_list_head; + while (w != NULL) { + if (w->next == too_remove) { + w->next = w->next->next; + gpr_mu_unlock(&chand->external_connectivity_watcher_list_mu); + return; + } + w = w->next; + } + GPR_UNREACHABLE_CODE(return ); +} + +int grpc_client_channel_num_external_connectivity_watchers( + grpc_channel_element *elem) { + channel_data *chand = elem->channel_data; + int count = 0; + + gpr_mu_lock(&chand->external_connectivity_watcher_list_mu); + external_connectivity_watcher *w = + chand->external_connectivity_watcher_list_head; + while (w != NULL) { + count++; + w = w->next; + } + gpr_mu_unlock(&chand->external_connectivity_watcher_list_mu); + + return count; +} + static void on_external_watch_complete(grpc_exec_ctx *exec_ctx, void *arg, grpc_error *error) { external_connectivity_watcher *w = arg; @@ -1377,6 +1456,7 @@ static void on_external_watch_complete(grpc_exec_ctx *exec_ctx, void *arg, w->pollset); GRPC_CHANNEL_STACK_UNREF(exec_ctx, w->chand->owning_stack, "external_connectivity_watcher"); + external_connectivity_watcher_list_remove(w->chand, w); gpr_free(w); grpc_closure_run(exec_ctx, follow_up, GRPC_ERROR_REF(error)); } @@ -1384,21 +1464,42 @@ static void on_external_watch_complete(grpc_exec_ctx *exec_ctx, void *arg, static void watch_connectivity_state_locked(grpc_exec_ctx *exec_ctx, void *arg, grpc_error *error_ignored) { external_connectivity_watcher *w = arg; - grpc_closure_init(&w->my_closure, on_external_watch_complete, w, - grpc_schedule_on_exec_ctx); - grpc_connectivity_state_notify_on_state_change( - exec_ctx, &w->chand->state_tracker, w->state, &w->my_closure); + external_connectivity_watcher *found = NULL; + if (w->state != NULL) { + external_connectivity_watcher_list_append(w->chand, w); + grpc_closure_run(exec_ctx, w->watcher_timer_init, GRPC_ERROR_NONE); + grpc_closure_init(&w->my_closure, on_external_watch_complete, w, + grpc_schedule_on_exec_ctx); + grpc_connectivity_state_notify_on_state_change( + exec_ctx, &w->chand->state_tracker, w->state, &w->my_closure); + } else { + GPR_ASSERT(w->watcher_timer_init == NULL); + found = lookup_external_connectivity_watcher(w->chand, w->on_complete); + if (found) { + GPR_ASSERT(found->on_complete == w->on_complete); + grpc_connectivity_state_notify_on_state_change( + exec_ctx, &found->chand->state_tracker, NULL, &found->my_closure); + } + grpc_pollset_set_del_pollset(exec_ctx, w->chand->interested_parties, + w->pollset); + GRPC_CHANNEL_STACK_UNREF(exec_ctx, w->chand->owning_stack, + "external_connectivity_watcher"); + gpr_free(w); + } } void grpc_client_channel_watch_connectivity_state( grpc_exec_ctx *exec_ctx, grpc_channel_element *elem, grpc_pollset *pollset, - grpc_connectivity_state *state, grpc_closure *on_complete) { + grpc_connectivity_state *state, grpc_closure *on_complete, + grpc_closure *watcher_timer_init) { channel_data *chand = elem->channel_data; - external_connectivity_watcher *w = gpr_malloc(sizeof(*w)); + external_connectivity_watcher *w = gpr_zalloc(sizeof(*w)); w->chand = chand; w->pollset = pollset; w->on_complete = on_complete; w->state = state; + w->watcher_timer_init = watcher_timer_init; + grpc_pollset_set_add_pollset(exec_ctx, chand->interested_parties, pollset); GRPC_CHANNEL_STACK_REF(w->chand->owning_stack, "external_connectivity_watcher"); diff --git a/src/core/ext/filters/client_channel/client_channel.h b/src/core/ext/filters/client_channel/client_channel.h index 8d2490ea55d..356a7ab0c15 100644 --- a/src/core/ext/filters/client_channel/client_channel.h +++ b/src/core/ext/filters/client_channel/client_channel.h @@ -53,9 +53,13 @@ extern const grpc_channel_filter grpc_client_channel_filter; grpc_connectivity_state grpc_client_channel_check_connectivity_state( grpc_exec_ctx *exec_ctx, grpc_channel_element *elem, int try_to_connect); +int grpc_client_channel_num_external_connectivity_watchers( + grpc_channel_element *elem); + void grpc_client_channel_watch_connectivity_state( grpc_exec_ctx *exec_ctx, grpc_channel_element *elem, grpc_pollset *pollset, - grpc_connectivity_state *state, grpc_closure *on_complete); + grpc_connectivity_state *state, grpc_closure *on_complete, + grpc_closure *watcher_timer_init); /* Debug helper: pull the subchannel call from a call stack element */ grpc_subchannel_call *grpc_client_channel_get_subchannel_call( diff --git a/src/ruby/ext/grpc/rb_grpc_imports.generated.c b/src/ruby/ext/grpc/rb_grpc_imports.generated.c index 063f92114c0..332907c0af2 100644 --- a/src/ruby/ext/grpc/rb_grpc_imports.generated.c +++ b/src/ruby/ext/grpc/rb_grpc_imports.generated.c @@ -103,6 +103,7 @@ grpc_alarm_create_type grpc_alarm_create_import; grpc_alarm_cancel_type grpc_alarm_cancel_import; grpc_alarm_destroy_type grpc_alarm_destroy_import; grpc_channel_check_connectivity_state_type grpc_channel_check_connectivity_state_import; +grpc_channel_num_external_connectivity_watchers_type grpc_channel_num_external_connectivity_watchers_import; grpc_channel_watch_connectivity_state_type grpc_channel_watch_connectivity_state_import; grpc_channel_create_call_type grpc_channel_create_call_import; grpc_channel_ping_type grpc_channel_ping_import; @@ -400,6 +401,7 @@ void grpc_rb_load_imports(HMODULE library) { grpc_alarm_cancel_import = (grpc_alarm_cancel_type) GetProcAddress(library, "grpc_alarm_cancel"); grpc_alarm_destroy_import = (grpc_alarm_destroy_type) GetProcAddress(library, "grpc_alarm_destroy"); grpc_channel_check_connectivity_state_import = (grpc_channel_check_connectivity_state_type) GetProcAddress(library, "grpc_channel_check_connectivity_state"); + grpc_channel_num_external_connectivity_watchers_import = (grpc_channel_num_external_connectivity_watchers_type) GetProcAddress(library, "grpc_channel_num_external_connectivity_watchers"); grpc_channel_watch_connectivity_state_import = (grpc_channel_watch_connectivity_state_type) GetProcAddress(library, "grpc_channel_watch_connectivity_state"); grpc_channel_create_call_import = (grpc_channel_create_call_type) GetProcAddress(library, "grpc_channel_create_call"); grpc_channel_ping_import = (grpc_channel_ping_type) GetProcAddress(library, "grpc_channel_ping"); diff --git a/src/ruby/ext/grpc/rb_grpc_imports.generated.h b/src/ruby/ext/grpc/rb_grpc_imports.generated.h index f5dcd68a8e9..e6a3f6d2f4f 100644 --- a/src/ruby/ext/grpc/rb_grpc_imports.generated.h +++ b/src/ruby/ext/grpc/rb_grpc_imports.generated.h @@ -260,6 +260,9 @@ extern grpc_alarm_destroy_type grpc_alarm_destroy_import; typedef grpc_connectivity_state(*grpc_channel_check_connectivity_state_type)(grpc_channel *channel, int try_to_connect); extern grpc_channel_check_connectivity_state_type grpc_channel_check_connectivity_state_import; #define grpc_channel_check_connectivity_state grpc_channel_check_connectivity_state_import +typedef int(*grpc_channel_num_external_connectivity_watchers_type)(grpc_channel *channel); +extern grpc_channel_num_external_connectivity_watchers_type grpc_channel_num_external_connectivity_watchers_import; +#define grpc_channel_num_external_connectivity_watchers grpc_channel_num_external_connectivity_watchers_import typedef void(*grpc_channel_watch_connectivity_state_type)(grpc_channel *channel, grpc_connectivity_state last_observed_state, gpr_timespec deadline, grpc_completion_queue *cq, void *tag); extern grpc_channel_watch_connectivity_state_type grpc_channel_watch_connectivity_state_import; #define grpc_channel_watch_connectivity_state grpc_channel_watch_connectivity_state_import diff --git a/test/core/surface/concurrent_connectivity_test.c b/test/core/surface/concurrent_connectivity_test.c index 2f7c3dfb856..73f2cd363eb 100644 --- a/test/core/surface/concurrent_connectivity_test.c +++ b/test/core/surface/concurrent_connectivity_test.c @@ -61,6 +61,14 @@ #define DELAY_MILLIS 10 #define POLL_MILLIS 3000 +#define NUM_OUTER_LOOPS_SHORT_TIMEOUTS 10 +#define NUM_INNER_LOOPS_SHORT_TIMEOUTS 100 +#define DELAY_MILLIS_SHORT_TIMEOUTS 1 +// in a successful test run, POLL_MILLIS should never be reached beause all runs +// should +// end after the shorter delay_millis +#define POLL_MILLIS_SHORT_TIMEOUTS 30000 + static void *tag(int n) { return (void *)(uintptr_t)n; } static int detag(void *p) { return (int)(uintptr_t)p; } @@ -79,6 +87,8 @@ void create_loop_destroy(void *addr) { grpc_timeout_milliseconds_to_deadline(POLL_MILLIS); GPR_ASSERT(grpc_completion_queue_next(cq, poll_time, NULL).type == GRPC_OP_COMPLETE); + /* check that the watcher from "watch state" was free'd */ + GPR_ASSERT(grpc_channel_num_external_connectivity_watchers(chan) == 0); } grpc_channel_destroy(chan); grpc_completion_queue_destroy(cq); @@ -166,11 +176,10 @@ static void done_pollset_shutdown(grpc_exec_ctx *exec_ctx, void *pollset, gpr_free(pollset); } -int main(int argc, char **argv) { +int run_concurrent_connectivity_test() { struct server_thread_args args; memset(&args, 0, sizeof(args)); - grpc_test_init(argc, argv); grpc_init(); gpr_thd_id threads[NUM_THREADS]; @@ -240,3 +249,59 @@ int main(int argc, char **argv) { grpc_shutdown(); return 0; } + +void watches_with_short_timeouts(void *addr) { + for (int i = 0; i < NUM_OUTER_LOOPS_SHORT_TIMEOUTS; ++i) { + grpc_completion_queue *cq = grpc_completion_queue_create(NULL); + grpc_channel *chan = grpc_insecure_channel_create((char *)addr, NULL, NULL); + + for (int j = 0; j < NUM_INNER_LOOPS_SHORT_TIMEOUTS; ++j) { + gpr_timespec later_time = + grpc_timeout_milliseconds_to_deadline(DELAY_MILLIS_SHORT_TIMEOUTS); + grpc_connectivity_state state = + grpc_channel_check_connectivity_state(chan, 0); + GPR_ASSERT(state == GRPC_CHANNEL_IDLE); + grpc_channel_watch_connectivity_state(chan, state, later_time, cq, NULL); + gpr_timespec poll_time = + grpc_timeout_milliseconds_to_deadline(POLL_MILLIS_SHORT_TIMEOUTS); + grpc_event ev = grpc_completion_queue_next(cq, poll_time, NULL); + GPR_ASSERT(ev.type == GRPC_OP_COMPLETE); + GPR_ASSERT(ev.success == false); + /* check that the watcher from "watch state" was free'd */ + GPR_ASSERT(grpc_channel_num_external_connectivity_watchers(chan) == 0); + } + grpc_channel_destroy(chan); + grpc_completion_queue_destroy(cq); + } +} + +// This test tries to catch deadlock situations. +// With short timeouts on "watches" and long timeouts on cq next calls, +// so that a QUEUE_TIMEOUT likely means that something is stuck. +int run_concurrent_watches_with_short_timeouts_test() { + grpc_init(); + + gpr_thd_id threads[NUM_THREADS]; + + char *localhost = gpr_strdup("localhost:54321"); + gpr_thd_options options = gpr_thd_options_default(); + gpr_thd_options_set_joinable(&options); + + for (size_t i = 0; i < NUM_THREADS; ++i) { + gpr_thd_new(&threads[i], watches_with_short_timeouts, localhost, &options); + } + for (size_t i = 0; i < NUM_THREADS; ++i) { + gpr_thd_join(threads[i]); + } + gpr_free(localhost); + + grpc_shutdown(); + return 0; +} + +int main(int argc, char **argv) { + grpc_test_init(argc, argv); + + run_concurrent_connectivity_test(); + run_concurrent_watches_with_short_timeouts_test(); +} diff --git a/test/core/surface/num_external_connectivity_watchers_test.c b/test/core/surface/num_external_connectivity_watchers_test.c new file mode 100644 index 00000000000..96288ab60db --- /dev/null +++ b/test/core/surface/num_external_connectivity_watchers_test.c @@ -0,0 +1,221 @@ +/* + * + * Copyright 2016, Google Inc. + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are + * met: + * + * * Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * * Redistributions in binary form must reproduce the above + * copyright notice, this list of conditions and the following disclaimer + * in the documentation and/or other materials provided with the + * distribution. + * * Neither the name of Google Inc. nor the names of its + * contributors may be used to endorse or promote products derived from + * this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT + * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR + * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT + * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, + * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT + * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, + * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY + * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE + * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + * + */ + +#include +#include +#include +#include +#include +#include + +#include "src/core/lib/channel/channel_args.h" +#include "src/core/lib/iomgr/exec_ctx.h" +#include "test/core/end2end/data/ssl_test_data.h" +#include "test/core/util/port.h" +#include "test/core/util/test_config.h" + +typedef struct test_fixture { + const char *name; + grpc_channel *(*create_channel)(const char *addr); +} test_fixture; + +static size_t next_tag = 1; + +static void channel_idle_start_watch(grpc_channel *channel, + grpc_completion_queue *cq) { + gpr_timespec connect_deadline = grpc_timeout_milliseconds_to_deadline(1); + GPR_ASSERT(grpc_channel_check_connectivity_state(channel, 0) == + GRPC_CHANNEL_IDLE); + + grpc_channel_watch_connectivity_state( + channel, GRPC_CHANNEL_IDLE, connect_deadline, cq, (void *)(next_tag++)); + gpr_log(GPR_DEBUG, "number of active connect watchers: %d", + grpc_channel_num_external_connectivity_watchers(channel)); +} + +static void channel_idle_poll_for_timeout(grpc_channel *channel, + grpc_completion_queue *cq) { + grpc_event ev = + grpc_completion_queue_next(cq, gpr_inf_future(GPR_CLOCK_REALTIME), NULL); + + /* expect watch_connectivity_state to end with a timeout */ + GPR_ASSERT(ev.type == GRPC_OP_COMPLETE); + GPR_ASSERT(ev.success == false); + GPR_ASSERT(grpc_channel_check_connectivity_state(channel, 0) == + GRPC_CHANNEL_IDLE); +} + +/* Test and use the "num_external_watchers" call to make sure + * that "connectivity watcher" structs are free'd just after, if + * their corresponding timeouts occur. */ +static void run_timeouts_test(const test_fixture *fixture) { + gpr_log(GPR_INFO, "TEST: %s", fixture->name); + + char *addr; + + grpc_init(); + + gpr_join_host_port(&addr, "localhost", grpc_pick_unused_port_or_die()); + + grpc_channel *channel = fixture->create_channel(addr); + grpc_completion_queue *cq = grpc_completion_queue_create_for_next(NULL); + + /* start 1 watcher and then let it time out */ + channel_idle_start_watch(channel, cq); + GPR_ASSERT(grpc_channel_num_external_connectivity_watchers(channel) == 1); + channel_idle_poll_for_timeout(channel, cq); + GPR_ASSERT(grpc_channel_num_external_connectivity_watchers(channel) == 0); + + /* start 3 watchers and then let them all time out */ + for (size_t i = 1; i <= 3; i++) { + channel_idle_start_watch(channel, cq); + GPR_ASSERT(grpc_channel_num_external_connectivity_watchers(channel) == + (int)i); + } + for (size_t i = 1; i <= 3; i++) { + channel_idle_poll_for_timeout(channel, cq); + } + GPR_ASSERT(grpc_channel_num_external_connectivity_watchers(channel) == 0); + + /* start 3 watchers, see one time out, start another 3, and then see them all + * time out */ + for (size_t i = 1; i <= 3; i++) { + channel_idle_start_watch(channel, cq); + GPR_ASSERT(grpc_channel_num_external_connectivity_watchers(channel) == + (int)i); + } + channel_idle_poll_for_timeout(channel, cq); + for (size_t i = 3; i <= 5; i++) { + channel_idle_start_watch(channel, cq); + } + GPR_ASSERT(grpc_channel_num_external_connectivity_watchers(channel) >= 3); + for (size_t i = 1; i <= 5; i++) { + channel_idle_poll_for_timeout(channel, cq); + } + GPR_ASSERT(grpc_channel_num_external_connectivity_watchers(channel) == 0); + + grpc_channel_destroy(channel); + grpc_completion_queue_shutdown(cq); + GPR_ASSERT( + grpc_completion_queue_next(cq, gpr_inf_future(GPR_CLOCK_REALTIME), NULL) + .type == GRPC_QUEUE_SHUTDOWN); + grpc_completion_queue_destroy(cq); + + grpc_shutdown(); + gpr_free(addr); +} + +/* An edge scenario; sets channel state to explicitly, and outside + * of a polling call. */ +static void run_channel_shutdown_before_timeout_test( + const test_fixture *fixture) { + gpr_log(GPR_INFO, "TEST: %s", fixture->name); + + char *addr; + + grpc_init(); + + gpr_join_host_port(&addr, "localhost", grpc_pick_unused_port_or_die()); + + grpc_channel *channel = fixture->create_channel(addr); + grpc_completion_queue *cq = grpc_completion_queue_create_for_next(NULL); + + /* start 1 watcher and then shut down the channel before the timer goes off */ + GPR_ASSERT(grpc_channel_num_external_connectivity_watchers(channel) == 0); + + /* expecting a 30 second timeout to go off much later than the shutdown. */ + gpr_timespec connect_deadline = grpc_timeout_seconds_to_deadline(30); + GPR_ASSERT(grpc_channel_check_connectivity_state(channel, 0) == + GRPC_CHANNEL_IDLE); + + grpc_channel_watch_connectivity_state(channel, GRPC_CHANNEL_IDLE, + connect_deadline, cq, (void *)1); + GPR_ASSERT(grpc_channel_num_external_connectivity_watchers(channel) == 1); + grpc_channel_destroy(channel); + + grpc_event ev = + grpc_completion_queue_next(cq, gpr_inf_future(GPR_CLOCK_REALTIME), NULL); + GPR_ASSERT(ev.type == GRPC_OP_COMPLETE); + /* expect success with a state transition to CHANNEL_SHUTDOWN */ + GPR_ASSERT(ev.success == true); + + grpc_completion_queue_shutdown(cq); + GPR_ASSERT( + grpc_completion_queue_next(cq, gpr_inf_future(GPR_CLOCK_REALTIME), NULL) + .type == GRPC_QUEUE_SHUTDOWN); + grpc_completion_queue_destroy(cq); + + grpc_shutdown(); + gpr_free(addr); +} + +static grpc_channel *insecure_test_create_channel(const char *addr) { + return grpc_insecure_channel_create(addr, NULL, NULL); +} + +static const test_fixture insecure_test = { + "insecure", insecure_test_create_channel, +}; + +static grpc_channel *secure_test_create_channel(const char *addr) { + grpc_channel_credentials *ssl_creds = + grpc_ssl_credentials_create(test_root_cert, NULL, NULL); + grpc_arg ssl_name_override = {GRPC_ARG_STRING, + GRPC_SSL_TARGET_NAME_OVERRIDE_ARG, + {"foo.test.google.fr"}}; + grpc_channel_args *new_client_args = + grpc_channel_args_copy_and_add(NULL, &ssl_name_override, 1); + grpc_channel *channel = + grpc_secure_channel_create(ssl_creds, addr, new_client_args, NULL); + { + grpc_exec_ctx exec_ctx = GRPC_EXEC_CTX_INIT; + grpc_channel_args_destroy(&exec_ctx, new_client_args); + grpc_exec_ctx_finish(&exec_ctx); + } + grpc_channel_credentials_release(ssl_creds); + return channel; +} + +static const test_fixture secure_test = { + "secure", secure_test_create_channel, +}; + +int main(int argc, char **argv) { + grpc_test_init(argc, argv); + + run_timeouts_test(&insecure_test); + run_timeouts_test(&secure_test); + + run_channel_shutdown_before_timeout_test(&insecure_test); + run_channel_shutdown_before_timeout_test(&secure_test); +} diff --git a/test/core/surface/sequential_connectivity_test.c b/test/core/surface/sequential_connectivity_test.c index 5f66f900372..8a6dd69c0fa 100644 --- a/test/core/surface/sequential_connectivity_test.c +++ b/test/core/surface/sequential_connectivity_test.c @@ -99,6 +99,9 @@ static void run_test(const test_fixture *fixture) { connect_deadline, cq, NULL); grpc_event ev = grpc_completion_queue_next( cq, gpr_inf_future(GPR_CLOCK_REALTIME), NULL); + /* check that the watcher from "watch state" was free'd */ + GPR_ASSERT(grpc_channel_num_external_connectivity_watchers(channels[i]) == + 0); GPR_ASSERT(ev.type == GRPC_OP_COMPLETE); GPR_ASSERT(ev.tag == NULL); GPR_ASSERT(ev.success == true); diff --git a/tools/run_tests/generated/sources_and_headers.json b/tools/run_tests/generated/sources_and_headers.json index f5653d6f9ef..5afeed3d252 100644 --- a/tools/run_tests/generated/sources_and_headers.json +++ b/tools/run_tests/generated/sources_and_headers.json @@ -1689,6 +1689,23 @@ "third_party": false, "type": "target" }, + { + "deps": [ + "gpr", + "gpr_test_util", + "grpc", + "grpc_test_util" + ], + "headers": [], + "is_filegroup": false, + "language": "c", + "name": "num_external_connectivity_watchers_test", + "src": [ + "test/core/surface/num_external_connectivity_watchers_test.c" + ], + "third_party": false, + "type": "target" + }, { "deps": [ "gpr", diff --git a/tools/run_tests/generated/tests.json b/tools/run_tests/generated/tests.json index a08caf30d36..7e350990c98 100644 --- a/tools/run_tests/generated/tests.json +++ b/tools/run_tests/generated/tests.json @@ -1763,6 +1763,30 @@ "windows" ] }, + { + "args": [], + "ci_platforms": [ + "linux", + "mac", + "posix", + "windows" + ], + "cpu_cost": 1.0, + "exclude_configs": [], + "exclude_iomgrs": [ + "uv" + ], + "flaky": false, + "gtest": false, + "language": "c", + "name": "num_external_connectivity_watchers_test", + "platforms": [ + "linux", + "mac", + "posix", + "windows" + ] + }, { "args": [], "ci_platforms": [ diff --git a/vsprojects/buildtests_c.sln b/vsprojects/buildtests_c.sln index c8fcacf75b1..9cb966de488 100644 --- a/vsprojects/buildtests_c.sln +++ b/vsprojects/buildtests_c.sln @@ -1284,6 +1284,17 @@ Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "no_server_test", "vcxproj\t {B23D3D1A-9438-4EDA-BEB6-9A0A03D17792} = {B23D3D1A-9438-4EDA-BEB6-9A0A03D17792} EndProjectSection EndProject +Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "num_external_connectivity_watchers_test", "vcxproj\test\num_external_connectivity_watchers_test\num_external_connectivity_watchers_test.vcxproj", "{4E856E4A-7497-1B1A-1AED-D4C01E5D873A}" + ProjectSection(myProperties) = preProject + lib = "False" + EndProjectSection + ProjectSection(ProjectDependencies) = postProject + {17BCAFC0-5FDC-4C94-AEB9-95F3E220614B} = {17BCAFC0-5FDC-4C94-AEB9-95F3E220614B} + {29D16885-7228-4C31-81ED-5F9187C7F2A9} = {29D16885-7228-4C31-81ED-5F9187C7F2A9} + {EAB0A629-17A9-44DB-B5FF-E91A721FE037} = {EAB0A629-17A9-44DB-B5FF-E91A721FE037} + {B23D3D1A-9438-4EDA-BEB6-9A0A03D17792} = {B23D3D1A-9438-4EDA-BEB6-9A0A03D17792} + EndProjectSection +EndProject Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "parse_address_test", "vcxproj\test\parse_address_test\parse_address_test.vcxproj", "{EDEA8257-AEA8-1B0A-F95B-8D6CD7286463}" ProjectSection(myProperties) = preProject lib = "False" @@ -3577,6 +3588,22 @@ Global {A66AC548-E2B9-74CD-293C-43526EE51DCE}.Release-DLL|Win32.Build.0 = Release|Win32 {A66AC548-E2B9-74CD-293C-43526EE51DCE}.Release-DLL|x64.ActiveCfg = Release|x64 {A66AC548-E2B9-74CD-293C-43526EE51DCE}.Release-DLL|x64.Build.0 = Release|x64 + {4E856E4A-7497-1B1A-1AED-D4C01E5D873A}.Debug|Win32.ActiveCfg = Debug|Win32 + {4E856E4A-7497-1B1A-1AED-D4C01E5D873A}.Debug|x64.ActiveCfg = Debug|x64 + {4E856E4A-7497-1B1A-1AED-D4C01E5D873A}.Release|Win32.ActiveCfg = Release|Win32 + {4E856E4A-7497-1B1A-1AED-D4C01E5D873A}.Release|x64.ActiveCfg = Release|x64 + {4E856E4A-7497-1B1A-1AED-D4C01E5D873A}.Debug|Win32.Build.0 = Debug|Win32 + {4E856E4A-7497-1B1A-1AED-D4C01E5D873A}.Debug|x64.Build.0 = Debug|x64 + {4E856E4A-7497-1B1A-1AED-D4C01E5D873A}.Release|Win32.Build.0 = Release|Win32 + {4E856E4A-7497-1B1A-1AED-D4C01E5D873A}.Release|x64.Build.0 = Release|x64 + {4E856E4A-7497-1B1A-1AED-D4C01E5D873A}.Debug-DLL|Win32.ActiveCfg = Debug|Win32 + {4E856E4A-7497-1B1A-1AED-D4C01E5D873A}.Debug-DLL|Win32.Build.0 = Debug|Win32 + {4E856E4A-7497-1B1A-1AED-D4C01E5D873A}.Debug-DLL|x64.ActiveCfg = Debug|x64 + {4E856E4A-7497-1B1A-1AED-D4C01E5D873A}.Debug-DLL|x64.Build.0 = Debug|x64 + {4E856E4A-7497-1B1A-1AED-D4C01E5D873A}.Release-DLL|Win32.ActiveCfg = Release|Win32 + {4E856E4A-7497-1B1A-1AED-D4C01E5D873A}.Release-DLL|Win32.Build.0 = Release|Win32 + {4E856E4A-7497-1B1A-1AED-D4C01E5D873A}.Release-DLL|x64.ActiveCfg = Release|x64 + {4E856E4A-7497-1B1A-1AED-D4C01E5D873A}.Release-DLL|x64.Build.0 = Release|x64 {EDEA8257-AEA8-1B0A-F95B-8D6CD7286463}.Debug|Win32.ActiveCfg = Debug|Win32 {EDEA8257-AEA8-1B0A-F95B-8D6CD7286463}.Debug|x64.ActiveCfg = Debug|x64 {EDEA8257-AEA8-1B0A-F95B-8D6CD7286463}.Release|Win32.ActiveCfg = Release|Win32 diff --git a/vsprojects/vcxproj/test/num_external_connectivity_watchers_test/num_external_connectivity_watchers_test.vcxproj b/vsprojects/vcxproj/test/num_external_connectivity_watchers_test/num_external_connectivity_watchers_test.vcxproj new file mode 100644 index 00000000000..2b373e8a16d --- /dev/null +++ b/vsprojects/vcxproj/test/num_external_connectivity_watchers_test/num_external_connectivity_watchers_test.vcxproj @@ -0,0 +1,199 @@ + + + + + + Debug + Win32 + + + Debug + x64 + + + Release + Win32 + + + Release + x64 + + + + {4E856E4A-7497-1B1A-1AED-D4C01E5D873A} + true + $(SolutionDir)IntDir\$(MSBuildProjectName)\ + + + + v100 + + + v110 + + + v120 + + + v140 + + + Application + true + Unicode + + + Application + false + true + Unicode + + + + + + + + + + + + + + num_external_connectivity_watchers_test + static + Debug + static + Debug + + + num_external_connectivity_watchers_test + static + Release + static + Release + + + + NotUsing + Level3 + Disabled + WIN32;_DEBUG;_LIB;%(PreprocessorDefinitions) + true + MultiThreadedDebug + true + None + false + + + Console + true + false + + + + + + NotUsing + Level3 + Disabled + WIN32;_DEBUG;_LIB;%(PreprocessorDefinitions) + true + MultiThreadedDebug + true + None + false + + + Console + true + false + + + + + + NotUsing + Level3 + MaxSpeed + WIN32;NDEBUG;_LIB;%(PreprocessorDefinitions) + true + true + true + MultiThreaded + true + None + false + + + Console + true + false + true + true + + + + + + NotUsing + Level3 + MaxSpeed + WIN32;NDEBUG;_LIB;%(PreprocessorDefinitions) + true + true + true + MultiThreaded + true + None + false + + + Console + true + false + true + true + + + + + + + + + + {17BCAFC0-5FDC-4C94-AEB9-95F3E220614B} + + + {29D16885-7228-4C31-81ED-5F9187C7F2A9} + + + {EAB0A629-17A9-44DB-B5FF-E91A721FE037} + + + {B23D3D1A-9438-4EDA-BEB6-9A0A03D17792} + + + + + + + + + + + + + + + This project references NuGet package(s) that are missing on this computer. Enable NuGet Package Restore to download them. For more information, see http://go.microsoft.com/fwlink/?LinkID=322105. The missing file is {0}. + + + + + + + + + diff --git a/vsprojects/vcxproj/test/num_external_connectivity_watchers_test/num_external_connectivity_watchers_test.vcxproj.filters b/vsprojects/vcxproj/test/num_external_connectivity_watchers_test/num_external_connectivity_watchers_test.vcxproj.filters new file mode 100644 index 00000000000..92a4198e307 --- /dev/null +++ b/vsprojects/vcxproj/test/num_external_connectivity_watchers_test/num_external_connectivity_watchers_test.vcxproj.filters @@ -0,0 +1,21 @@ + + + + + test\core\surface + + + + + + {9557f01e-947a-775e-4540-bf9a1fd9b19a} + + + {2b3a6de2-5820-e21f-5b39-66012c94bfbb} + + + {e3f23659-fc16-a4cc-a9e2-c73b625c38f5} + + + + From c0ce2cdf0030dd5df342fda3c3e76afccacaa854 Mon Sep 17 00:00:00 2001 From: Ken Payson Date: Fri, 19 May 2017 17:47:49 -0700 Subject: [PATCH 19/45] Update version to 1.3.5 --- BUILD | 2 +- CMakeLists.txt | 2 +- Makefile | 4 ++-- build.yaml | 2 +- gRPC-Core.podspec | 2 +- gRPC-ProtoRPC.podspec | 2 +- gRPC-RxLibrary.podspec | 2 +- gRPC.podspec | 2 +- package.json | 2 +- package.xml | 4 ++-- src/cpp/common/version_cc.cc | 2 +- src/csharp/Grpc.Core/Version.csproj.include | 2 +- src/csharp/Grpc.Core/VersionInfo.cs | 4 ++-- src/csharp/build_packages_dotnetcli.bat | 2 +- src/csharp/build_packages_dotnetcli.sh | 4 ++-- src/node/health_check/package.json | 4 ++-- src/node/tools/package.json | 2 +- src/objective-c/!ProtoCompiler-gRPCPlugin.podspec | 2 +- src/objective-c/GRPCClient/private/version.h | 2 +- src/php/composer.json | 2 +- src/python/grpcio/grpc_version.py | 2 +- src/python/grpcio_health_checking/grpc_version.py | 2 +- src/python/grpcio_reflection/grpc_version.py | 2 +- src/python/grpcio_tests/grpc_version.py | 2 +- src/ruby/lib/grpc/version.rb | 2 +- src/ruby/tools/version.rb | 2 +- tools/distrib/python/grpcio_tools/grpc_version.py | 2 +- tools/doxygen/Doxyfile.c++ | 2 +- tools/doxygen/Doxyfile.c++.internal | 2 +- 29 files changed, 34 insertions(+), 34 deletions(-) diff --git a/BUILD b/BUILD index 51314f645c0..166e6ba7518 100644 --- a/BUILD +++ b/BUILD @@ -42,7 +42,7 @@ g_stands_for = "gentle" core_version = "3.0.0" -version = "1.3.4" +version = "1.3.5" grpc_cc_library( name = "gpr", diff --git a/CMakeLists.txt b/CMakeLists.txt index 48f9bb42a90..cff8f856e02 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -39,7 +39,7 @@ cmake_minimum_required(VERSION 2.8) set(PACKAGE_NAME "grpc") -set(PACKAGE_VERSION "1.3.4") +set(PACKAGE_VERSION "1.3.5") set(PACKAGE_STRING "${PACKAGE_NAME} ${PACKAGE_VERSION}") set(PACKAGE_TARNAME "${PACKAGE_NAME}-${PACKAGE_VERSION}") set(PACKAGE_BUGREPORT "https://github.com/grpc/grpc/issues/") diff --git a/Makefile b/Makefile index 8359ce2fc63..77206ba92bf 100644 --- a/Makefile +++ b/Makefile @@ -420,8 +420,8 @@ Q = @ endif CORE_VERSION = 3.0.0 -CPP_VERSION = 1.3.4 -CSHARP_VERSION = 1.3.4 +CPP_VERSION = 1.3.5 +CSHARP_VERSION = 1.3.5 CPPFLAGS_NO_ARCH += $(addprefix -I, $(INCLUDES)) $(addprefix -D, $(DEFINES)) CPPFLAGS += $(CPPFLAGS_NO_ARCH) $(ARCH_FLAGS) diff --git a/build.yaml b/build.yaml index 0629b459ac8..3af590609a1 100644 --- a/build.yaml +++ b/build.yaml @@ -14,7 +14,7 @@ settings: '#10': See the expand_version.py for all the quirks here core_version: 3.0.0 g_stands_for: gentle - version: 1.3.4 + version: 1.3.5 filegroups: - name: census public_headers: diff --git a/gRPC-Core.podspec b/gRPC-Core.podspec index c8e50b577ac..5d1ba611830 100644 --- a/gRPC-Core.podspec +++ b/gRPC-Core.podspec @@ -37,7 +37,7 @@ Pod::Spec.new do |s| s.name = 'gRPC-Core' - version = '1.3.4' + version = '1.3.5' s.version = version s.summary = 'Core cross-platform gRPC library, written in C' s.homepage = 'http://www.grpc.io' diff --git a/gRPC-ProtoRPC.podspec b/gRPC-ProtoRPC.podspec index 6737e0136a8..e60ea7c08ee 100644 --- a/gRPC-ProtoRPC.podspec +++ b/gRPC-ProtoRPC.podspec @@ -36,7 +36,7 @@ Pod::Spec.new do |s| s.name = 'gRPC-ProtoRPC' - version = '1.3.4' + version = '1.3.5' s.version = version s.summary = 'RPC library for Protocol Buffers, based on gRPC' s.homepage = 'http://www.grpc.io' diff --git a/gRPC-RxLibrary.podspec b/gRPC-RxLibrary.podspec index 0b338d44aaf..d82130ad4ae 100644 --- a/gRPC-RxLibrary.podspec +++ b/gRPC-RxLibrary.podspec @@ -36,7 +36,7 @@ Pod::Spec.new do |s| s.name = 'gRPC-RxLibrary' - version = '1.3.4' + version = '1.3.5' s.version = version s.summary = 'Reactive Extensions library for iOS/OSX.' s.homepage = 'http://www.grpc.io' diff --git a/gRPC.podspec b/gRPC.podspec index 1783df67ef5..5aa8a86a058 100644 --- a/gRPC.podspec +++ b/gRPC.podspec @@ -35,7 +35,7 @@ Pod::Spec.new do |s| s.name = 'gRPC' - version = '1.3.4' + version = '1.3.5' s.version = version s.summary = 'gRPC client library for iOS/OSX' s.homepage = 'http://www.grpc.io' diff --git a/package.json b/package.json index 11e34416520..c83f51c2212 100644 --- a/package.json +++ b/package.json @@ -1,6 +1,6 @@ { "name": "grpc", - "version": "1.3.4", + "version": "1.3.5", "author": "Google Inc.", "description": "gRPC Library for Node", "homepage": "http://www.grpc.io/", diff --git a/package.xml b/package.xml index 6b3eddadf6d..1c91f1c0c23 100644 --- a/package.xml +++ b/package.xml @@ -13,8 +13,8 @@ 2017-05-05 - 1.3.4 - 1.3.4 + 1.3.5 + 1.3.5 beta diff --git a/src/cpp/common/version_cc.cc b/src/cpp/common/version_cc.cc index 97437ba5308..0a1b72527b6 100644 --- a/src/cpp/common/version_cc.cc +++ b/src/cpp/common/version_cc.cc @@ -37,5 +37,5 @@ #include namespace grpc { -grpc::string Version() { return "1.3.4"; } +grpc::string Version() { return "1.3.5"; } } diff --git a/src/csharp/Grpc.Core/Version.csproj.include b/src/csharp/Grpc.Core/Version.csproj.include index 881c311b17e..63536ecc6b4 100755 --- a/src/csharp/Grpc.Core/Version.csproj.include +++ b/src/csharp/Grpc.Core/Version.csproj.include @@ -1,7 +1,7 @@ - 1.3.4 + 1.3.5 3.2.0 diff --git a/src/csharp/Grpc.Core/VersionInfo.cs b/src/csharp/Grpc.Core/VersionInfo.cs index bbe5a17d6b7..fed38292f04 100644 --- a/src/csharp/Grpc.Core/VersionInfo.cs +++ b/src/csharp/Grpc.Core/VersionInfo.cs @@ -48,11 +48,11 @@ namespace Grpc.Core /// /// Current AssemblyFileVersion of gRPC C# assemblies /// - public const string CurrentAssemblyFileVersion = "1.3.4.0"; + public const string CurrentAssemblyFileVersion = "1.3.5.0"; /// /// Current version of gRPC C# /// - public const string CurrentVersion = "1.3.4"; + public const string CurrentVersion = "1.3.5"; } } diff --git a/src/csharp/build_packages_dotnetcli.bat b/src/csharp/build_packages_dotnetcli.bat index a385ac74e3e..3aec7aacbeb 100755 --- a/src/csharp/build_packages_dotnetcli.bat +++ b/src/csharp/build_packages_dotnetcli.bat @@ -28,7 +28,7 @@ @rem OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. @rem Current package versions -set VERSION=1.3.4 +set VERSION=1.3.5 @rem Adjust the location of nuget.exe set NUGET=C:\nuget\nuget.exe diff --git a/src/csharp/build_packages_dotnetcli.sh b/src/csharp/build_packages_dotnetcli.sh index 66c41d4d940..da585cb663d 100755 --- a/src/csharp/build_packages_dotnetcli.sh +++ b/src/csharp/build_packages_dotnetcli.sh @@ -70,7 +70,7 @@ dotnet pack --configuration Release --include-symbols --include-source Grpc.Auth dotnet pack --configuration Release --include-symbols --include-source Grpc.HealthCheck --output ../../../artifacts dotnet pack --configuration Release --include-symbols --include-source Grpc.Reflection --output ../../../artifacts -nuget pack Grpc.nuspec -Version "1.3.4" -OutputDirectory ../../artifacts -nuget pack Grpc.Tools.nuspec -Version "1.3.4" -OutputDirectory ../../artifacts +nuget pack Grpc.nuspec -Version "1.3.5" -OutputDirectory ../../artifacts +nuget pack Grpc.Tools.nuspec -Version "1.3.5" -OutputDirectory ../../artifacts (cd ../../artifacts && zip csharp_nugets_dotnetcli.zip *.nupkg) diff --git a/src/node/health_check/package.json b/src/node/health_check/package.json index 6329cd9c377..2fdcb12777c 100644 --- a/src/node/health_check/package.json +++ b/src/node/health_check/package.json @@ -1,6 +1,6 @@ { "name": "grpc-health-check", - "version": "1.3.4", + "version": "1.3.5", "author": "Google Inc.", "description": "Health check service for use with gRPC", "repository": { @@ -15,7 +15,7 @@ } ], "dependencies": { - "grpc": "^1.3.4", + "grpc": "^1.3.5", "lodash": "^3.9.3", "google-protobuf": "^3.0.0" }, diff --git a/src/node/tools/package.json b/src/node/tools/package.json index 355ae2fdc1f..cabd4030dc9 100644 --- a/src/node/tools/package.json +++ b/src/node/tools/package.json @@ -1,6 +1,6 @@ { "name": "grpc-tools", - "version": "1.3.4", + "version": "1.3.5", "author": "Google Inc.", "description": "Tools for developing with gRPC on Node.js", "homepage": "http://www.grpc.io/", diff --git a/src/objective-c/!ProtoCompiler-gRPCPlugin.podspec b/src/objective-c/!ProtoCompiler-gRPCPlugin.podspec index b4fc9685049..23f91867c41 100644 --- a/src/objective-c/!ProtoCompiler-gRPCPlugin.podspec +++ b/src/objective-c/!ProtoCompiler-gRPCPlugin.podspec @@ -42,7 +42,7 @@ Pod::Spec.new do |s| # exclamation mark ensures that other "regular" pods will be able to find it as it'll be installed # before them. s.name = '!ProtoCompiler-gRPCPlugin' - v = '1.3.4' + v = '1.3.5' s.version = v s.summary = 'The gRPC ProtoC plugin generates Objective-C files from .proto services.' s.description = <<-DESC diff --git a/src/objective-c/GRPCClient/private/version.h b/src/objective-c/GRPCClient/private/version.h index ccf96230bc1..43ab9bd0641 100644 --- a/src/objective-c/GRPCClient/private/version.h +++ b/src/objective-c/GRPCClient/private/version.h @@ -38,4 +38,4 @@ // `tools/buildgen/generate_projects.sh`. -#define GRPC_OBJC_VERSION_STRING @"1.3.4" +#define GRPC_OBJC_VERSION_STRING @"1.3.5" diff --git a/src/php/composer.json b/src/php/composer.json index 562859e6b3d..08f2b9afabd 100644 --- a/src/php/composer.json +++ b/src/php/composer.json @@ -2,7 +2,7 @@ "name": "grpc/grpc-dev", "description": "gRPC library for PHP - for Developement use only", "license": "BSD-3-Clause", - "version": "1.3.4", + "version": "1.3.5", "require": { "php": ">=5.5.0", "google/protobuf": "^v3.1.0" diff --git a/src/python/grpcio/grpc_version.py b/src/python/grpcio/grpc_version.py index 29ffcab1065..52b1397468c 100644 --- a/src/python/grpcio/grpc_version.py +++ b/src/python/grpcio/grpc_version.py @@ -29,4 +29,4 @@ # AUTO-GENERATED FROM `$REPO_ROOT/templates/src/python/grpcio/grpc_version.py.template`!!! -VERSION='1.3.4' +VERSION='1.3.5' diff --git a/src/python/grpcio_health_checking/grpc_version.py b/src/python/grpcio_health_checking/grpc_version.py index 16e0dc13275..143c1ede368 100644 --- a/src/python/grpcio_health_checking/grpc_version.py +++ b/src/python/grpcio_health_checking/grpc_version.py @@ -29,4 +29,4 @@ # AUTO-GENERATED FROM `$REPO_ROOT/templates/src/python/grpcio_health_checking/grpc_version.py.template`!!! -VERSION='1.3.4' +VERSION='1.3.5' diff --git a/src/python/grpcio_reflection/grpc_version.py b/src/python/grpcio_reflection/grpc_version.py index 5ef0ed8045e..66f1ff968ae 100644 --- a/src/python/grpcio_reflection/grpc_version.py +++ b/src/python/grpcio_reflection/grpc_version.py @@ -29,4 +29,4 @@ # AUTO-GENERATED FROM `$REPO_ROOT/templates/src/python/grpcio_reflection/grpc_version.py.template`!!! -VERSION='1.3.4' +VERSION='1.3.5' diff --git a/src/python/grpcio_tests/grpc_version.py b/src/python/grpcio_tests/grpc_version.py index 7e4c57e6ec6..a6da39c8ebf 100644 --- a/src/python/grpcio_tests/grpc_version.py +++ b/src/python/grpcio_tests/grpc_version.py @@ -29,4 +29,4 @@ # AUTO-GENERATED FROM `$REPO_ROOT/templates/src/python/grpcio_tests/grpc_version.py.template`!!! -VERSION='1.3.4' +VERSION='1.3.5' diff --git a/src/ruby/lib/grpc/version.rb b/src/ruby/lib/grpc/version.rb index c03ec97196b..27595318d33 100644 --- a/src/ruby/lib/grpc/version.rb +++ b/src/ruby/lib/grpc/version.rb @@ -29,5 +29,5 @@ # GRPC contains the General RPC module. module GRPC - VERSION = '1.3.4' + VERSION = '1.3.5' end diff --git a/src/ruby/tools/version.rb b/src/ruby/tools/version.rb index fe0fb2cef21..f93c1f14af2 100644 --- a/src/ruby/tools/version.rb +++ b/src/ruby/tools/version.rb @@ -29,6 +29,6 @@ module GRPC module Tools - VERSION = '1.3.4' + VERSION = '1.3.5' end end diff --git a/tools/distrib/python/grpcio_tools/grpc_version.py b/tools/distrib/python/grpcio_tools/grpc_version.py index 020785aa730..71786813299 100644 --- a/tools/distrib/python/grpcio_tools/grpc_version.py +++ b/tools/distrib/python/grpcio_tools/grpc_version.py @@ -29,4 +29,4 @@ # AUTO-GENERATED FROM `$REPO_ROOT/templates/tools/distrib/python/grpcio_tools/grpc_version.py.template`!!! -VERSION='1.3.4' +VERSION='1.3.5' diff --git a/tools/doxygen/Doxyfile.c++ b/tools/doxygen/Doxyfile.c++ index 5021a1a153b..55980eadac5 100644 --- a/tools/doxygen/Doxyfile.c++ +++ b/tools/doxygen/Doxyfile.c++ @@ -40,7 +40,7 @@ PROJECT_NAME = "GRPC C++" # could be handy for archiving the generated documentation or if some version # control system is used. -PROJECT_NUMBER = 1.3.4 +PROJECT_NUMBER = 1.3.5 # Using the PROJECT_BRIEF tag one can provide an optional one line description # for a project that appears at the top of each page and should give viewer a diff --git a/tools/doxygen/Doxyfile.c++.internal b/tools/doxygen/Doxyfile.c++.internal index 1df6951aef2..7580617bf12 100644 --- a/tools/doxygen/Doxyfile.c++.internal +++ b/tools/doxygen/Doxyfile.c++.internal @@ -40,7 +40,7 @@ PROJECT_NAME = "GRPC C++" # could be handy for archiving the generated documentation or if some version # control system is used. -PROJECT_NUMBER = 1.3.4 +PROJECT_NUMBER = 1.3.5 # Using the PROJECT_BRIEF tag one can provide an optional one line description # for a project that appears at the top of each page and should give viewer a From 8f7bc54ff2256179ede6d4a6d1a8792b7820fc28 Mon Sep 17 00:00:00 2001 From: Ken Payson Date: Tue, 16 May 2017 10:30:59 -0700 Subject: [PATCH 20/45] Reconnect disconnected channels automatically --- src/python/grpcio/grpc/_channel.py | 7 +- src/python/grpcio_tests/tests/tests.json | 1 + .../tests/unit/_reconnect_test.py | 70 +++++++++++++++++++ 3 files changed, 77 insertions(+), 1 deletion(-) create mode 100644 src/python/grpcio_tests/tests/unit/_reconnect_test.py diff --git a/src/python/grpcio/grpc/_channel.py b/src/python/grpcio/grpc/_channel.py index 4316449ac65..012ed8ec812 100644 --- a/src/python/grpcio/grpc/_channel.py +++ b/src/python/grpcio/grpc/_channel.py @@ -786,7 +786,7 @@ def _channel_managed_call_management(state): class _ChannelConnectivityState(object): def __init__(self, channel): - self.lock = threading.Lock() + self.lock = threading.RLock() self.channel = channel self.polling = False self.connectivity = None @@ -926,6 +926,11 @@ class Channel(grpc.Channel): self._call_state = _ChannelCallState(self._channel) self._connectivity_state = _ChannelConnectivityState(self._channel) + # TODO(https://github.com/grpc/grpc/issues/9884) + # Temporary work around UNAVAILABLE issues + # Remove this once c-core has retry support + _subscribe(self._connectivity_state, lambda *args: None, None) + def subscribe(self, callback, try_to_connect=None): _subscribe(self._connectivity_state, callback, try_to_connect) diff --git a/src/python/grpcio_tests/tests/tests.json b/src/python/grpcio_tests/tests/tests.json index f750b051022..5f641d87010 100644 --- a/src/python/grpcio_tests/tests/tests.json +++ b/src/python/grpcio_tests/tests/tests.json @@ -31,6 +31,7 @@ "unit._invocation_defects_test.InvocationDefectsTest", "unit._metadata_code_details_test.MetadataCodeDetailsTest", "unit._metadata_test.MetadataTest", + "unit._reconnect_test.ReconnectTest", "unit._resource_exhausted_test.ResourceExhaustedTest", "unit._rpc_test.RPCTest", "unit._sanity._sanity_test.Sanity", diff --git a/src/python/grpcio_tests/tests/unit/_reconnect_test.py b/src/python/grpcio_tests/tests/unit/_reconnect_test.py new file mode 100644 index 00000000000..6c316476b3e --- /dev/null +++ b/src/python/grpcio_tests/tests/unit/_reconnect_test.py @@ -0,0 +1,70 @@ +# Copyright 2017, Google Inc. +# All rights reserved. +# +# Redistribution and use in source and binary forms, with or without +# modification, are permitted provided that the following conditions are +# met: +# +# * Redistributions of source code must retain the above copyright +# notice, this list of conditions and the following disclaimer. +# * Redistributions in binary form must reproduce the above +# copyright notice, this list of conditions and the following disclaimer +# in the documentation and/or other materials provided with the +# distribution. +# * Neither the name of Google Inc. nor the names of its +# contributors may be used to endorse or promote products derived from +# this software without specific prior written permission. +# +# THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS +# "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT +# LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR +# A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT +# OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, +# SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT +# LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, +# DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY +# THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +# (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE +# OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. +"""Tests that a channel will reconnect if a connection is dropped""" + +import unittest + +import grpc +from grpc.framework.foundation import logging_pool + +from tests.unit.framework.common import test_constants + +_REQUEST = b'\x00\x00\x00' +_RESPONSE = b'\x00\x00\x01' + +_UNARY_UNARY = '/test/UnaryUnary' + + +def _handle_unary_unary(unused_request, unused_servicer_context): + return _RESPONSE + + +class ReconnectTest(unittest.TestCase): + + def test_reconnect(self): + server_pool = logging_pool.pool(test_constants.THREAD_CONCURRENCY) + handler = grpc.method_handlers_generic_handler('test', { + 'UnaryUnary': + grpc.unary_unary_rpc_method_handler(_handle_unary_unary) + }) + server = grpc.server(server_pool, (handler,)) + port = server.add_insecure_port('[::]:0') + server.start() + channel = grpc.insecure_channel('localhost:%d' % port) + multi_callable = channel.unary_unary(_UNARY_UNARY) + self.assertEqual(_RESPONSE, multi_callable(_REQUEST)) + server.stop(None) + server = grpc.server(server_pool, (handler,)) + server.add_insecure_port('[::]:{}'.format(port)) + server.start() + self.assertEqual(_RESPONSE, multi_callable(_REQUEST)) + + +if __name__ == '__main__': + unittest.main(verbosity=2) From f8be2d65cc942e94c81d76e1fba5bb3aee538189 Mon Sep 17 00:00:00 2001 From: Jan Tattermusch Date: Tue, 23 May 2017 21:08:34 +0200 Subject: [PATCH 21/45] add privateassets none to C# nugets depending on Grpc.Core --- src/csharp/Grpc.Auth/Grpc.Auth.csproj | 4 +++- src/csharp/Grpc.Core.Testing/Grpc.Core.Testing.csproj | 6 ++++-- src/csharp/Grpc.HealthCheck/Grpc.HealthCheck.csproj | 4 +++- src/csharp/Grpc.Reflection/Grpc.Reflection.csproj | 4 +++- 4 files changed, 13 insertions(+), 5 deletions(-) diff --git a/src/csharp/Grpc.Auth/Grpc.Auth.csproj b/src/csharp/Grpc.Auth/Grpc.Auth.csproj index 6ac25aa1f02..c082e30c46c 100755 --- a/src/csharp/Grpc.Auth/Grpc.Auth.csproj +++ b/src/csharp/Grpc.Auth/Grpc.Auth.csproj @@ -23,7 +23,9 @@ - + + None + diff --git a/src/csharp/Grpc.Core.Testing/Grpc.Core.Testing.csproj b/src/csharp/Grpc.Core.Testing/Grpc.Core.Testing.csproj index f4dd5105fc7..1efda925bd7 100755 --- a/src/csharp/Grpc.Core.Testing/Grpc.Core.Testing.csproj +++ b/src/csharp/Grpc.Core.Testing/Grpc.Core.Testing.csproj @@ -1,4 +1,4 @@ - + @@ -23,7 +23,9 @@ - + + None + diff --git a/src/csharp/Grpc.HealthCheck/Grpc.HealthCheck.csproj b/src/csharp/Grpc.HealthCheck/Grpc.HealthCheck.csproj index eac6e1fc95f..80c7dfe48ca 100755 --- a/src/csharp/Grpc.HealthCheck/Grpc.HealthCheck.csproj +++ b/src/csharp/Grpc.HealthCheck/Grpc.HealthCheck.csproj @@ -22,7 +22,9 @@ - + + None + diff --git a/src/csharp/Grpc.Reflection/Grpc.Reflection.csproj b/src/csharp/Grpc.Reflection/Grpc.Reflection.csproj index 70bfcc89c5c..eafa0f4e108 100755 --- a/src/csharp/Grpc.Reflection/Grpc.Reflection.csproj +++ b/src/csharp/Grpc.Reflection/Grpc.Reflection.csproj @@ -22,7 +22,9 @@ - + + None + From be8522974d9a8237468193d680b20cb503793a57 Mon Sep 17 00:00:00 2001 From: Jan Tattermusch Date: Tue, 23 May 2017 22:17:22 +0200 Subject: [PATCH 22/45] include symbols and source in nugets --- src/csharp/Grpc.Auth/Grpc.Auth.csproj | 2 ++ src/csharp/Grpc.Core.Testing/Grpc.Core.Testing.csproj | 2 ++ src/csharp/Grpc.Core/Grpc.Core.csproj | 4 +++- src/csharp/Grpc.HealthCheck/Grpc.HealthCheck.csproj | 2 ++ src/csharp/Grpc.Reflection/Grpc.Reflection.csproj | 2 ++ 5 files changed, 11 insertions(+), 1 deletion(-) diff --git a/src/csharp/Grpc.Auth/Grpc.Auth.csproj b/src/csharp/Grpc.Auth/Grpc.Auth.csproj index c082e30c46c..188ddb95b99 100755 --- a/src/csharp/Grpc.Auth/Grpc.Auth.csproj +++ b/src/csharp/Grpc.Auth/Grpc.Auth.csproj @@ -16,6 +16,8 @@ https://github.com/grpc/grpc https://github.com/grpc/grpc/blob/master/LICENSE 1.6.0 + true + true diff --git a/src/csharp/Grpc.Core.Testing/Grpc.Core.Testing.csproj b/src/csharp/Grpc.Core.Testing/Grpc.Core.Testing.csproj index 1efda925bd7..45ec8743222 100755 --- a/src/csharp/Grpc.Core.Testing/Grpc.Core.Testing.csproj +++ b/src/csharp/Grpc.Core.Testing/Grpc.Core.Testing.csproj @@ -16,6 +16,8 @@ https://github.com/grpc/grpc https://github.com/grpc/grpc/blob/master/LICENSE 1.6.0 + true + true diff --git a/src/csharp/Grpc.Core/Grpc.Core.csproj b/src/csharp/Grpc.Core/Grpc.Core.csproj index 7e0f3f053d0..bcf0282b92e 100755 --- a/src/csharp/Grpc.Core/Grpc.Core.csproj +++ b/src/csharp/Grpc.Core/Grpc.Core.csproj @@ -1,4 +1,4 @@ - + @@ -15,6 +15,8 @@ https://github.com/grpc/grpc https://github.com/grpc/grpc/blob/master/LICENSE 1.6.0 + true + true diff --git a/src/csharp/Grpc.HealthCheck/Grpc.HealthCheck.csproj b/src/csharp/Grpc.HealthCheck/Grpc.HealthCheck.csproj index 80c7dfe48ca..c3791a4e6b2 100755 --- a/src/csharp/Grpc.HealthCheck/Grpc.HealthCheck.csproj +++ b/src/csharp/Grpc.HealthCheck/Grpc.HealthCheck.csproj @@ -15,6 +15,8 @@ https://github.com/grpc/grpc https://github.com/grpc/grpc/blob/master/LICENSE 1.6.0 + true + true diff --git a/src/csharp/Grpc.Reflection/Grpc.Reflection.csproj b/src/csharp/Grpc.Reflection/Grpc.Reflection.csproj index eafa0f4e108..3a075552483 100755 --- a/src/csharp/Grpc.Reflection/Grpc.Reflection.csproj +++ b/src/csharp/Grpc.Reflection/Grpc.Reflection.csproj @@ -15,6 +15,8 @@ https://github.com/grpc/grpc https://github.com/grpc/grpc/blob/master/LICENSE 1.6.0 + true + true From 905f41869bbf143ccf38f3aa4ed6980251ad7de3 Mon Sep 17 00:00:00 2001 From: Jan Tattermusch Date: Tue, 23 May 2017 22:34:14 +0200 Subject: [PATCH 23/45] remove now unnecessary extra args --- src/csharp/build_packages_dotnetcli.bat | 10 +++++----- src/csharp/build_packages_dotnetcli.sh | 10 +++++----- .../src/csharp/build_packages_dotnetcli.bat.template | 10 +++++----- .../src/csharp/build_packages_dotnetcli.sh.template | 10 +++++----- 4 files changed, 20 insertions(+), 20 deletions(-) diff --git a/src/csharp/build_packages_dotnetcli.bat b/src/csharp/build_packages_dotnetcli.bat index 3aec7aacbeb..eb3ba2a952e 100755 --- a/src/csharp/build_packages_dotnetcli.bat +++ b/src/csharp/build_packages_dotnetcli.bat @@ -60,11 +60,11 @@ xcopy /Y /I ..\..\architecture=x64,language=protoc,platform=macos\artifacts\* pr @rem To be able to build, we also need to put grpc_csharp_ext to its normal location xcopy /Y /I nativelibs\windows_x64\grpc_csharp_ext.dll ..\..\cmake\build\x64\Release\ -%DOTNET% pack --configuration Release --include-symbols --include-source Grpc.Core --output ..\..\..\artifacts || goto :error -%DOTNET% pack --configuration Release --include-symbols --include-source Grpc.Core.Testing --output ..\..\..\artifacts || goto :error -%DOTNET% pack --configuration Release --include-symbols --include-source Grpc.Auth --output ..\..\..\artifacts || goto :error -%DOTNET% pack --configuration Release --include-symbols --include-source Grpc.HealthCheck --output ..\..\..\artifacts || goto :error -%DOTNET% pack --configuration Release --include-symbols --include-source Grpc.Reflection --output ..\..\..\artifacts || goto :error +%DOTNET% pack --configuration Release Grpc.Core --output ..\..\..\artifacts || goto :error +%DOTNET% pack --configuration Release Grpc.Core.Testing --output ..\..\..\artifacts || goto :error +%DOTNET% pack --configuration Release Grpc.Auth --output ..\..\..\artifacts || goto :error +%DOTNET% pack --configuration Release Grpc.HealthCheck --output ..\..\..\artifacts || goto :error +%DOTNET% pack --configuration Release Grpc.Reflection --output ..\..\..\artifacts || goto :error %NUGET% pack Grpc.nuspec -Version %VERSION% -OutputDirectory ..\..\artifacts || goto :error %NUGET% pack Grpc.Tools.nuspec -Version %VERSION% -OutputDirectory ..\..\artifacts diff --git a/src/csharp/build_packages_dotnetcli.sh b/src/csharp/build_packages_dotnetcli.sh index da585cb663d..76ae99a2fb1 100755 --- a/src/csharp/build_packages_dotnetcli.sh +++ b/src/csharp/build_packages_dotnetcli.sh @@ -64,11 +64,11 @@ dotnet restore Grpc.sln mkdir -p ../../libs/opt cp nativelibs/linux_x64/libgrpc_csharp_ext.so ../../libs/opt -dotnet pack --configuration Release --include-symbols --include-source Grpc.Core --output ../../../artifacts -dotnet pack --configuration Release --include-symbols --include-source Grpc.Core.Testing --output ../../../artifacts -dotnet pack --configuration Release --include-symbols --include-source Grpc.Auth --output ../../../artifacts -dotnet pack --configuration Release --include-symbols --include-source Grpc.HealthCheck --output ../../../artifacts -dotnet pack --configuration Release --include-symbols --include-source Grpc.Reflection --output ../../../artifacts +dotnet pack --configuration Release Grpc.Core --output ../../../artifacts +dotnet pack --configuration Release Grpc.Core.Testing --output ../../../artifacts +dotnet pack --configuration Release Grpc.Auth --output ../../../artifacts +dotnet pack --configuration Release Grpc.HealthCheck --output ../../../artifacts +dotnet pack --configuration Release Grpc.Reflection --output ../../../artifacts nuget pack Grpc.nuspec -Version "1.3.5" -OutputDirectory ../../artifacts nuget pack Grpc.Tools.nuspec -Version "1.3.5" -OutputDirectory ../../artifacts diff --git a/templates/src/csharp/build_packages_dotnetcli.bat.template b/templates/src/csharp/build_packages_dotnetcli.bat.template index 5f6ffb97544..91808e0d266 100755 --- a/templates/src/csharp/build_packages_dotnetcli.bat.template +++ b/templates/src/csharp/build_packages_dotnetcli.bat.template @@ -62,11 +62,11 @@ @rem To be able to build, we also need to put grpc_csharp_ext to its normal location xcopy /Y /I nativelibs\windows_x64\grpc_csharp_ext.dll ..\..\cmake\build\x64\Release${"\\"} - %%DOTNET% pack --configuration Release --include-symbols --include-source Grpc.Core --output ..\..\..\artifacts || goto :error - %%DOTNET% pack --configuration Release --include-symbols --include-source Grpc.Core.Testing --output ..\..\..\artifacts || goto :error - %%DOTNET% pack --configuration Release --include-symbols --include-source Grpc.Auth --output ..\..\..\artifacts || goto :error - %%DOTNET% pack --configuration Release --include-symbols --include-source Grpc.HealthCheck --output ..\..\..\artifacts || goto :error - %%DOTNET% pack --configuration Release --include-symbols --include-source Grpc.Reflection --output ..\..\..\artifacts || goto :error + %%DOTNET% pack --configuration Release Grpc.Core --output ..\..\..\artifacts || goto :error + %%DOTNET% pack --configuration Release Grpc.Core.Testing --output ..\..\..\artifacts || goto :error + %%DOTNET% pack --configuration Release Grpc.Auth --output ..\..\..\artifacts || goto :error + %%DOTNET% pack --configuration Release Grpc.HealthCheck --output ..\..\..\artifacts || goto :error + %%DOTNET% pack --configuration Release Grpc.Reflection --output ..\..\..\artifacts || goto :error %%NUGET% pack Grpc.nuspec -Version %VERSION% -OutputDirectory ..\..\artifacts || goto :error %%NUGET% pack Grpc.Tools.nuspec -Version %VERSION% -OutputDirectory ..\..\artifacts diff --git a/templates/src/csharp/build_packages_dotnetcli.sh.template b/templates/src/csharp/build_packages_dotnetcli.sh.template index d37f4eb4f4e..374b236f93c 100755 --- a/templates/src/csharp/build_packages_dotnetcli.sh.template +++ b/templates/src/csharp/build_packages_dotnetcli.sh.template @@ -66,11 +66,11 @@ mkdir -p ../../libs/opt cp nativelibs/linux_x64/libgrpc_csharp_ext.so ../../libs/opt - dotnet pack --configuration Release --include-symbols --include-source Grpc.Core --output ../../../artifacts - dotnet pack --configuration Release --include-symbols --include-source Grpc.Core.Testing --output ../../../artifacts - dotnet pack --configuration Release --include-symbols --include-source Grpc.Auth --output ../../../artifacts - dotnet pack --configuration Release --include-symbols --include-source Grpc.HealthCheck --output ../../../artifacts - dotnet pack --configuration Release --include-symbols --include-source Grpc.Reflection --output ../../../artifacts + dotnet pack --configuration Release Grpc.Core --output ../../../artifacts + dotnet pack --configuration Release Grpc.Core.Testing --output ../../../artifacts + dotnet pack --configuration Release Grpc.Auth --output ../../../artifacts + dotnet pack --configuration Release Grpc.HealthCheck --output ../../../artifacts + dotnet pack --configuration Release Grpc.Reflection --output ../../../artifacts nuget pack Grpc.nuspec -Version "${settings.csharp_version}" -OutputDirectory ../../artifacts nuget pack Grpc.Tools.nuspec -Version "${settings.csharp_version}" -OutputDirectory ../../artifacts From bbfdbb19c002d23e2fd3d94d6a089cff5b03a390 Mon Sep 17 00:00:00 2001 From: Jan Tattermusch Date: Tue, 23 May 2017 22:48:45 +0200 Subject: [PATCH 24/45] bump version to 1.3.6 --- BUILD | 2 +- CMakeLists.txt | 2 +- Makefile | 4 ++-- build.yaml | 2 +- gRPC-Core.podspec | 2 +- gRPC-ProtoRPC.podspec | 2 +- gRPC-RxLibrary.podspec | 2 +- gRPC.podspec | 2 +- package.json | 2 +- package.xml | 4 ++-- src/cpp/common/version_cc.cc | 2 +- src/csharp/Grpc.Core/Version.csproj.include | 2 +- src/csharp/Grpc.Core/VersionInfo.cs | 4 ++-- src/csharp/build_packages_dotnetcli.bat | 2 +- src/csharp/build_packages_dotnetcli.sh | 4 ++-- src/node/health_check/package.json | 4 ++-- src/node/tools/package.json | 2 +- src/objective-c/!ProtoCompiler-gRPCPlugin.podspec | 2 +- src/objective-c/GRPCClient/private/version.h | 2 +- src/php/composer.json | 2 +- src/python/grpcio/grpc_version.py | 2 +- src/python/grpcio_health_checking/grpc_version.py | 2 +- src/python/grpcio_reflection/grpc_version.py | 2 +- src/python/grpcio_tests/grpc_version.py | 2 +- src/ruby/lib/grpc/version.rb | 2 +- src/ruby/tools/version.rb | 2 +- tools/distrib/python/grpcio_tools/grpc_version.py | 2 +- tools/doxygen/Doxyfile.c++ | 2 +- tools/doxygen/Doxyfile.c++.internal | 2 +- 29 files changed, 34 insertions(+), 34 deletions(-) diff --git a/BUILD b/BUILD index 166e6ba7518..cb8c08a6368 100644 --- a/BUILD +++ b/BUILD @@ -42,7 +42,7 @@ g_stands_for = "gentle" core_version = "3.0.0" -version = "1.3.5" +version = "1.3.6" grpc_cc_library( name = "gpr", diff --git a/CMakeLists.txt b/CMakeLists.txt index cff8f856e02..86416cc11e5 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -39,7 +39,7 @@ cmake_minimum_required(VERSION 2.8) set(PACKAGE_NAME "grpc") -set(PACKAGE_VERSION "1.3.5") +set(PACKAGE_VERSION "1.3.6") set(PACKAGE_STRING "${PACKAGE_NAME} ${PACKAGE_VERSION}") set(PACKAGE_TARNAME "${PACKAGE_NAME}-${PACKAGE_VERSION}") set(PACKAGE_BUGREPORT "https://github.com/grpc/grpc/issues/") diff --git a/Makefile b/Makefile index 77206ba92bf..b5bb74113b1 100644 --- a/Makefile +++ b/Makefile @@ -420,8 +420,8 @@ Q = @ endif CORE_VERSION = 3.0.0 -CPP_VERSION = 1.3.5 -CSHARP_VERSION = 1.3.5 +CPP_VERSION = 1.3.6 +CSHARP_VERSION = 1.3.6 CPPFLAGS_NO_ARCH += $(addprefix -I, $(INCLUDES)) $(addprefix -D, $(DEFINES)) CPPFLAGS += $(CPPFLAGS_NO_ARCH) $(ARCH_FLAGS) diff --git a/build.yaml b/build.yaml index 3af590609a1..4c01cf245d2 100644 --- a/build.yaml +++ b/build.yaml @@ -14,7 +14,7 @@ settings: '#10': See the expand_version.py for all the quirks here core_version: 3.0.0 g_stands_for: gentle - version: 1.3.5 + version: 1.3.6 filegroups: - name: census public_headers: diff --git a/gRPC-Core.podspec b/gRPC-Core.podspec index 5d1ba611830..515a8dad63d 100644 --- a/gRPC-Core.podspec +++ b/gRPC-Core.podspec @@ -37,7 +37,7 @@ Pod::Spec.new do |s| s.name = 'gRPC-Core' - version = '1.3.5' + version = '1.3.6' s.version = version s.summary = 'Core cross-platform gRPC library, written in C' s.homepage = 'http://www.grpc.io' diff --git a/gRPC-ProtoRPC.podspec b/gRPC-ProtoRPC.podspec index e60ea7c08ee..d4dd0b10445 100644 --- a/gRPC-ProtoRPC.podspec +++ b/gRPC-ProtoRPC.podspec @@ -36,7 +36,7 @@ Pod::Spec.new do |s| s.name = 'gRPC-ProtoRPC' - version = '1.3.5' + version = '1.3.6' s.version = version s.summary = 'RPC library for Protocol Buffers, based on gRPC' s.homepage = 'http://www.grpc.io' diff --git a/gRPC-RxLibrary.podspec b/gRPC-RxLibrary.podspec index d82130ad4ae..6ed1849f028 100644 --- a/gRPC-RxLibrary.podspec +++ b/gRPC-RxLibrary.podspec @@ -36,7 +36,7 @@ Pod::Spec.new do |s| s.name = 'gRPC-RxLibrary' - version = '1.3.5' + version = '1.3.6' s.version = version s.summary = 'Reactive Extensions library for iOS/OSX.' s.homepage = 'http://www.grpc.io' diff --git a/gRPC.podspec b/gRPC.podspec index 5aa8a86a058..808bbf92e87 100644 --- a/gRPC.podspec +++ b/gRPC.podspec @@ -35,7 +35,7 @@ Pod::Spec.new do |s| s.name = 'gRPC' - version = '1.3.5' + version = '1.3.6' s.version = version s.summary = 'gRPC client library for iOS/OSX' s.homepage = 'http://www.grpc.io' diff --git a/package.json b/package.json index c83f51c2212..b8ac31aa552 100644 --- a/package.json +++ b/package.json @@ -1,6 +1,6 @@ { "name": "grpc", - "version": "1.3.5", + "version": "1.3.6", "author": "Google Inc.", "description": "gRPC Library for Node", "homepage": "http://www.grpc.io/", diff --git a/package.xml b/package.xml index 1c91f1c0c23..66e313b1a41 100644 --- a/package.xml +++ b/package.xml @@ -13,8 +13,8 @@ 2017-05-05 - 1.3.5 - 1.3.5 + 1.3.6 + 1.3.6 beta diff --git a/src/cpp/common/version_cc.cc b/src/cpp/common/version_cc.cc index 0a1b72527b6..71018423469 100644 --- a/src/cpp/common/version_cc.cc +++ b/src/cpp/common/version_cc.cc @@ -37,5 +37,5 @@ #include namespace grpc { -grpc::string Version() { return "1.3.5"; } +grpc::string Version() { return "1.3.6"; } } diff --git a/src/csharp/Grpc.Core/Version.csproj.include b/src/csharp/Grpc.Core/Version.csproj.include index 63536ecc6b4..22d7b92ae31 100755 --- a/src/csharp/Grpc.Core/Version.csproj.include +++ b/src/csharp/Grpc.Core/Version.csproj.include @@ -1,7 +1,7 @@ - 1.3.5 + 1.3.6 3.2.0 diff --git a/src/csharp/Grpc.Core/VersionInfo.cs b/src/csharp/Grpc.Core/VersionInfo.cs index fed38292f04..fb6a4b41972 100644 --- a/src/csharp/Grpc.Core/VersionInfo.cs +++ b/src/csharp/Grpc.Core/VersionInfo.cs @@ -48,11 +48,11 @@ namespace Grpc.Core /// /// Current AssemblyFileVersion of gRPC C# assemblies /// - public const string CurrentAssemblyFileVersion = "1.3.5.0"; + public const string CurrentAssemblyFileVersion = "1.3.6.0"; /// /// Current version of gRPC C# /// - public const string CurrentVersion = "1.3.5"; + public const string CurrentVersion = "1.3.6"; } } diff --git a/src/csharp/build_packages_dotnetcli.bat b/src/csharp/build_packages_dotnetcli.bat index 3aec7aacbeb..1f93ff694f3 100755 --- a/src/csharp/build_packages_dotnetcli.bat +++ b/src/csharp/build_packages_dotnetcli.bat @@ -28,7 +28,7 @@ @rem OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. @rem Current package versions -set VERSION=1.3.5 +set VERSION=1.3.6 @rem Adjust the location of nuget.exe set NUGET=C:\nuget\nuget.exe diff --git a/src/csharp/build_packages_dotnetcli.sh b/src/csharp/build_packages_dotnetcli.sh index da585cb663d..9f467fcbe61 100755 --- a/src/csharp/build_packages_dotnetcli.sh +++ b/src/csharp/build_packages_dotnetcli.sh @@ -70,7 +70,7 @@ dotnet pack --configuration Release --include-symbols --include-source Grpc.Auth dotnet pack --configuration Release --include-symbols --include-source Grpc.HealthCheck --output ../../../artifacts dotnet pack --configuration Release --include-symbols --include-source Grpc.Reflection --output ../../../artifacts -nuget pack Grpc.nuspec -Version "1.3.5" -OutputDirectory ../../artifacts -nuget pack Grpc.Tools.nuspec -Version "1.3.5" -OutputDirectory ../../artifacts +nuget pack Grpc.nuspec -Version "1.3.6" -OutputDirectory ../../artifacts +nuget pack Grpc.Tools.nuspec -Version "1.3.6" -OutputDirectory ../../artifacts (cd ../../artifacts && zip csharp_nugets_dotnetcli.zip *.nupkg) diff --git a/src/node/health_check/package.json b/src/node/health_check/package.json index 2fdcb12777c..f5700206fde 100644 --- a/src/node/health_check/package.json +++ b/src/node/health_check/package.json @@ -1,6 +1,6 @@ { "name": "grpc-health-check", - "version": "1.3.5", + "version": "1.3.6", "author": "Google Inc.", "description": "Health check service for use with gRPC", "repository": { @@ -15,7 +15,7 @@ } ], "dependencies": { - "grpc": "^1.3.5", + "grpc": "^1.3.6", "lodash": "^3.9.3", "google-protobuf": "^3.0.0" }, diff --git a/src/node/tools/package.json b/src/node/tools/package.json index cabd4030dc9..59397a5c24f 100644 --- a/src/node/tools/package.json +++ b/src/node/tools/package.json @@ -1,6 +1,6 @@ { "name": "grpc-tools", - "version": "1.3.5", + "version": "1.3.6", "author": "Google Inc.", "description": "Tools for developing with gRPC on Node.js", "homepage": "http://www.grpc.io/", diff --git a/src/objective-c/!ProtoCompiler-gRPCPlugin.podspec b/src/objective-c/!ProtoCompiler-gRPCPlugin.podspec index 23f91867c41..0d14df62df7 100644 --- a/src/objective-c/!ProtoCompiler-gRPCPlugin.podspec +++ b/src/objective-c/!ProtoCompiler-gRPCPlugin.podspec @@ -42,7 +42,7 @@ Pod::Spec.new do |s| # exclamation mark ensures that other "regular" pods will be able to find it as it'll be installed # before them. s.name = '!ProtoCompiler-gRPCPlugin' - v = '1.3.5' + v = '1.3.6' s.version = v s.summary = 'The gRPC ProtoC plugin generates Objective-C files from .proto services.' s.description = <<-DESC diff --git a/src/objective-c/GRPCClient/private/version.h b/src/objective-c/GRPCClient/private/version.h index 43ab9bd0641..578d31c9ed6 100644 --- a/src/objective-c/GRPCClient/private/version.h +++ b/src/objective-c/GRPCClient/private/version.h @@ -38,4 +38,4 @@ // `tools/buildgen/generate_projects.sh`. -#define GRPC_OBJC_VERSION_STRING @"1.3.5" +#define GRPC_OBJC_VERSION_STRING @"1.3.6" diff --git a/src/php/composer.json b/src/php/composer.json index 08f2b9afabd..45be98eba3a 100644 --- a/src/php/composer.json +++ b/src/php/composer.json @@ -2,7 +2,7 @@ "name": "grpc/grpc-dev", "description": "gRPC library for PHP - for Developement use only", "license": "BSD-3-Clause", - "version": "1.3.5", + "version": "1.3.6", "require": { "php": ">=5.5.0", "google/protobuf": "^v3.1.0" diff --git a/src/python/grpcio/grpc_version.py b/src/python/grpcio/grpc_version.py index 52b1397468c..1997ce98fad 100644 --- a/src/python/grpcio/grpc_version.py +++ b/src/python/grpcio/grpc_version.py @@ -29,4 +29,4 @@ # AUTO-GENERATED FROM `$REPO_ROOT/templates/src/python/grpcio/grpc_version.py.template`!!! -VERSION='1.3.5' +VERSION='1.3.6' diff --git a/src/python/grpcio_health_checking/grpc_version.py b/src/python/grpcio_health_checking/grpc_version.py index 143c1ede368..4e4ddd5e2d8 100644 --- a/src/python/grpcio_health_checking/grpc_version.py +++ b/src/python/grpcio_health_checking/grpc_version.py @@ -29,4 +29,4 @@ # AUTO-GENERATED FROM `$REPO_ROOT/templates/src/python/grpcio_health_checking/grpc_version.py.template`!!! -VERSION='1.3.5' +VERSION='1.3.6' diff --git a/src/python/grpcio_reflection/grpc_version.py b/src/python/grpcio_reflection/grpc_version.py index 66f1ff968ae..de61ce0ab27 100644 --- a/src/python/grpcio_reflection/grpc_version.py +++ b/src/python/grpcio_reflection/grpc_version.py @@ -29,4 +29,4 @@ # AUTO-GENERATED FROM `$REPO_ROOT/templates/src/python/grpcio_reflection/grpc_version.py.template`!!! -VERSION='1.3.5' +VERSION='1.3.6' diff --git a/src/python/grpcio_tests/grpc_version.py b/src/python/grpcio_tests/grpc_version.py index a6da39c8ebf..b07ec7946da 100644 --- a/src/python/grpcio_tests/grpc_version.py +++ b/src/python/grpcio_tests/grpc_version.py @@ -29,4 +29,4 @@ # AUTO-GENERATED FROM `$REPO_ROOT/templates/src/python/grpcio_tests/grpc_version.py.template`!!! -VERSION='1.3.5' +VERSION='1.3.6' diff --git a/src/ruby/lib/grpc/version.rb b/src/ruby/lib/grpc/version.rb index 27595318d33..3973654d5fb 100644 --- a/src/ruby/lib/grpc/version.rb +++ b/src/ruby/lib/grpc/version.rb @@ -29,5 +29,5 @@ # GRPC contains the General RPC module. module GRPC - VERSION = '1.3.5' + VERSION = '1.3.6' end diff --git a/src/ruby/tools/version.rb b/src/ruby/tools/version.rb index f93c1f14af2..1650938cda0 100644 --- a/src/ruby/tools/version.rb +++ b/src/ruby/tools/version.rb @@ -29,6 +29,6 @@ module GRPC module Tools - VERSION = '1.3.5' + VERSION = '1.3.6' end end diff --git a/tools/distrib/python/grpcio_tools/grpc_version.py b/tools/distrib/python/grpcio_tools/grpc_version.py index 71786813299..3e94e82a6dd 100644 --- a/tools/distrib/python/grpcio_tools/grpc_version.py +++ b/tools/distrib/python/grpcio_tools/grpc_version.py @@ -29,4 +29,4 @@ # AUTO-GENERATED FROM `$REPO_ROOT/templates/tools/distrib/python/grpcio_tools/grpc_version.py.template`!!! -VERSION='1.3.5' +VERSION='1.3.6' diff --git a/tools/doxygen/Doxyfile.c++ b/tools/doxygen/Doxyfile.c++ index 55980eadac5..c8a2a9f01c4 100644 --- a/tools/doxygen/Doxyfile.c++ +++ b/tools/doxygen/Doxyfile.c++ @@ -40,7 +40,7 @@ PROJECT_NAME = "GRPC C++" # could be handy for archiving the generated documentation or if some version # control system is used. -PROJECT_NUMBER = 1.3.5 +PROJECT_NUMBER = 1.3.6 # Using the PROJECT_BRIEF tag one can provide an optional one line description # for a project that appears at the top of each page and should give viewer a diff --git a/tools/doxygen/Doxyfile.c++.internal b/tools/doxygen/Doxyfile.c++.internal index 7580617bf12..d09757c2b1a 100644 --- a/tools/doxygen/Doxyfile.c++.internal +++ b/tools/doxygen/Doxyfile.c++.internal @@ -40,7 +40,7 @@ PROJECT_NAME = "GRPC C++" # could be handy for archiving the generated documentation or if some version # control system is used. -PROJECT_NUMBER = 1.3.5 +PROJECT_NUMBER = 1.3.6 # Using the PROJECT_BRIEF tag one can provide an optional one line description # for a project that appears at the top of each page and should give viewer a From 648832fd281e42d63263b27c147e0fcb88a0597c Mon Sep 17 00:00:00 2001 From: murgatroid99 Date: Tue, 23 May 2017 17:20:38 -0700 Subject: [PATCH 25/45] Enable more Node performance tests, fix streaming test implementation --- src/node/performance/benchmark_client.js | 42 +++++----------- .../run_tests/performance/scenario_config.py | 48 +++++++++---------- 2 files changed, 34 insertions(+), 56 deletions(-) diff --git a/src/node/performance/benchmark_client.js b/src/node/performance/benchmark_client.js index e7c426b2ff5..e0e68ffdef6 100644 --- a/src/node/performance/benchmark_client.js +++ b/src/node/performance/benchmark_client.js @@ -227,18 +227,22 @@ BenchmarkClient.prototype.startClosedLoop = function( makeCall = function(client) { if (self.running) { self.pending_calls++; - var start_time = process.hrtime(); var call = client.streamingCall(); + var start_time = process.hrtime(); call.write(argument); call.on('data', function() { - }); - call.on('end', function() { var time_diff = process.hrtime(start_time); self.histogram.add(timeDiffToNanos(time_diff)); - makeCall(client); self.pending_calls--; - if ((!self.running) && self.pending_calls == 0) { - self.emit('finished'); + if (self.running) { + self.pending_calls++; + start_time = process.hrtime(); + call.write(argument); + } else { + call.end(); + if (self.pending_calls == 0) { + self.emit('finished'); + } } }); call.on('error', function(error) { @@ -317,30 +321,8 @@ BenchmarkClient.prototype.startPoisson = function( } }; } else { - makeCall = function(client, poisson) { - if (self.running) { - self.pending_calls++; - var start_time = process.hrtime(); - var call = client.streamingCall(); - call.write(argument); - call.on('data', function() { - }); - call.on('end', function() { - var time_diff = process.hrtime(start_time); - self.histogram.add(timeDiffToNanos(time_diff)); - self.pending_calls--; - if ((!self.running) && self.pending_calls == 0) { - self.emit('finished'); - } - }); - call.on('error', function(error) { - self.emit('error', new Error('Client error: ' + error.message)); - self.running = false; - }); - } else { - poisson.stop(); - } - }; + self.emit('error', new Error('Streaming Poisson benchmarks not supported')); + return; } var averageIntervalMs = (1 / offered_load) * 1000; diff --git a/tools/run_tests/performance/scenario_config.py b/tools/run_tests/performance/scenario_config.py index c2ffd67dbf4..d28be006298 100644 --- a/tools/run_tests/performance/scenario_config.py +++ b/tools/run_tests/performance/scenario_config.py @@ -523,15 +523,14 @@ class NodeLanguage: def scenarios(self): # TODO(jtattermusch): make this scenario work - #yield _ping_pong_scenario( - # 'node_generic_async_streaming_ping_pong', rpc_type='STREAMING', - # client_type='ASYNC_CLIENT', server_type='ASYNC_GENERIC_SERVER', - # use_generic_payload=True) + yield _ping_pong_scenario( + 'node_generic_streaming_ping_pong', rpc_type='STREAMING', + client_type='ASYNC_CLIENT', server_type='ASYNC_GENERIC_SERVER', + use_generic_payload=True) - # TODO(jtattermusch): make this scenario work - #yield _ping_pong_scenario( - # 'node_protobuf_async_streaming_ping_pong', rpc_type='STREAMING', - # client_type='ASYNC_CLIENT', server_type='ASYNC_SERVER') + yield _ping_pong_scenario( + 'node_protobuf_streaming_ping_pong', rpc_type='STREAMING', + client_type='ASYNC_CLIENT', server_type='ASYNC_SERVER') yield _ping_pong_scenario( 'node_protobuf_unary_ping_pong', rpc_type='UNARY', @@ -564,29 +563,26 @@ class NodeLanguage: secure=secure, categories=[SCALABLE]) - # TODO(murgatroid99): fix bugs with this scenario and re-enable it - # yield _ping_pong_scenario( - # 'node_protobuf_async_unary_qps_unconstrained', rpc_type='UNARY', - # client_type='ASYNC_CLIENT', server_type='ASYNC_SERVER', - # unconstrained_client='async', - # categories=[SCALABLE, SMOKETEST]) - - # TODO(jtattermusch): make this scenario work - #yield _ping_pong_scenario( - # 'node_protobuf_async_streaming_qps_unconstrained', rpc_type='STREAMING', - # client_type='ASYNC_CLIENT', server_type='ASYNC_SERVER', - # unconstrained_client='async') + yield _ping_pong_scenario( + 'node_protobuf_unary_qps_unconstrained', rpc_type='UNARY', + client_type='ASYNC_CLIENT', server_type='ASYNC_SERVER', + unconstrained_client='async', + categories=[SCALABLE, SMOKETEST]) yield _ping_pong_scenario( - 'node_to_cpp_protobuf_async_unary_ping_pong', rpc_type='UNARY', + 'node_protobuf_streaming_qps_unconstrained', rpc_type='STREAMING', client_type='ASYNC_CLIENT', server_type='ASYNC_SERVER', + unconstrained_client='async') + + yield _ping_pong_scenario( + 'node_to_cpp_protobuf_sync_unary_ping_pong', rpc_type='UNARY', + client_type='SYNC_CLIENT', server_type='SYNC_SERVER', server_language='c++', async_server_threads=1) - # TODO(jtattermusch): make this scenario work - #yield _ping_pong_scenario( - # 'node_to_cpp_protobuf_async_streaming_ping_pong', rpc_type='STREAMING', - # client_type='ASYNC_CLIENT', server_type='ASYNC_SERVER', - # server_language='c++', async_server_threads=1) + yield _ping_pong_scenario( + 'node_to_cpp_protobuf_async_streaming_ping_pong', rpc_type='STREAMING', + client_type='ASYNC_CLIENT', server_type='ASYNC_SERVER', + server_language='c++', async_server_threads=1) def __str__(self): return 'node' From 30f2b7ece1d04502ef9a4345b88a76844ced9f2c Mon Sep 17 00:00:00 2001 From: murgatroid99 Date: Thu, 25 May 2017 10:55:53 -0700 Subject: [PATCH 26/45] Add more null checks to call methods --- src/node/ext/call.cc | 20 +++++++++++++++++--- src/node/ext/call.h | 1 + src/node/test/common_test.js | 1 - src/node/test/surface_test.js | 25 +++++++++++++++++++++++++ 4 files changed, 43 insertions(+), 4 deletions(-) diff --git a/src/node/ext/call.cc b/src/node/ext/call.cc index 2cc9f63b659..e2185da1c54 100644 --- a/src/node/ext/call.cc +++ b/src/node/ext/call.cc @@ -562,10 +562,12 @@ void Call::DestroyCall() { Call::Call(grpc_call *call) : wrapped_call(call), pending_batches(0), has_final_op_completed(false) { + peer = grpc_call_get_peer(call); } Call::~Call() { DestroyCall(); + gpr_free(peer); } void Call::Init(Local exports) { @@ -794,6 +796,11 @@ NAN_METHOD(Call::Cancel) { return Nan::ThrowTypeError("cancel can only be called on Call objects"); } Call *call = ObjectWrap::Unwrap(info.This()); + if (call->wrapped_call == NULL) { + /* Cancel is supposed to be idempotent. If the call has already finished, + * cancel should just complete silently */ + return; + } grpc_call_error error = grpc_call_cancel(call->wrapped_call, NULL); if (error != GRPC_CALL_OK) { return Nan::ThrowError(nanErrorWithCode("cancel failed", error)); @@ -814,6 +821,11 @@ NAN_METHOD(Call::CancelWithStatus) { "cancelWithStatus's second argument must be a string"); } Call *call = ObjectWrap::Unwrap(info.This()); + if (call->wrapped_call == NULL) { + /* Cancel is supposed to be idempotent. If the call has already finished, + * cancel should just complete silently */ + return; + } grpc_status_code code = static_cast( Nan::To(info[0]).FromJust()); if (code == GRPC_STATUS_OK) { @@ -830,9 +842,7 @@ NAN_METHOD(Call::GetPeer) { return Nan::ThrowTypeError("getPeer can only be called on Call objects"); } Call *call = ObjectWrap::Unwrap(info.This()); - char *peer = grpc_call_get_peer(call->wrapped_call); - Local peer_value = Nan::New(peer).ToLocalChecked(); - gpr_free(peer); + Local peer_value = Nan::New(call->peer).ToLocalChecked(); info.GetReturnValue().Set(peer_value); } @@ -847,6 +857,10 @@ NAN_METHOD(Call::SetCredentials) { "setCredentials' first argument must be a CallCredentials"); } Call *call = ObjectWrap::Unwrap(info.This()); + if (call->wrapped_call == NULL) { + return Nan::ThrowError( + "Cannot set credentials on a call that has already started"); + } CallCredentials *creds_object = ObjectWrap::Unwrap( Nan::To(info[0]).ToLocalChecked()); grpc_call_credentials *creds = creds_object->GetWrappedCredentials(); diff --git a/src/node/ext/call.h b/src/node/ext/call.h index 340e32682b9..45b448e0b1b 100644 --- a/src/node/ext/call.h +++ b/src/node/ext/call.h @@ -97,6 +97,7 @@ class Call : public Nan::ObjectWrap { call, this is GRPC_OP_RECV_STATUS_ON_CLIENT and for a server call, this is GRPC_OP_SEND_STATUS_FROM_SERVER */ bool has_final_op_completed; + char *peer; }; class Op { diff --git a/src/node/test/common_test.js b/src/node/test/common_test.js index b7c2c6a8d66..db80207e223 100644 --- a/src/node/test/common_test.js +++ b/src/node/test/common_test.js @@ -100,7 +100,6 @@ describe('Proto message long int serialize and deserialize', function() { var longNumDeserialize = deserializeCls(messages_proto.LongValues, num_options); var serialized = longSerialize({int_64: pos_value}); - console.log(longDeserialize(serialized)); assert.strictEqual(typeof longDeserialize(serialized).int_64, 'string'); /* With the longsAsStrings option disabled, long values are represented as * objects with 3 keys: low, high, and unsigned */ diff --git a/src/node/test/surface_test.js b/src/node/test/surface_test.js index d2f0511af2d..0696e7ae195 100644 --- a/src/node/test/surface_test.js +++ b/src/node/test/surface_test.js @@ -1110,6 +1110,18 @@ describe('Other conditions', function() { done(); }); }); + it('after the call has fully completed', function(done) { + var peer; + var call = client.unary({error: false}, function(err, data) { + assert.ifError(err); + setImmediate(function() { + assert.strictEqual(peer, call.getPeer()); + done(); + }); + }); + peer = call.getPeer(); + assert.strictEqual(typeof peer, 'string'); + }); }); }); describe('Call propagation', function() { @@ -1352,4 +1364,17 @@ describe('Cancelling surface client', function() { }); call.cancel(); }); + it('Should be idempotent', function(done) { + var call = client.div({'divisor': 0, 'dividend': 0}, function(err, resp) { + assert.strictEqual(err.code, surface_client.status.CANCELLED); + // Call asynchronously to try cancelling after call is fully completed + setImmediate(function() { + assert.doesNotThrow(function() { + call.cancel(); + }); + done(); + }); + }); + call.cancel(); + }); }); From cd6ab2212252db6543291121699451a9285a0c9a Mon Sep 17 00:00:00 2001 From: murgatroid99 Date: Thu, 25 May 2017 15:45:32 -0700 Subject: [PATCH 27/45] Fix concurrent_connectivity_test --- test/core/surface/concurrent_connectivity_test.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/test/core/surface/concurrent_connectivity_test.c b/test/core/surface/concurrent_connectivity_test.c index 1f09311b1fa..7614696caed 100644 --- a/test/core/surface/concurrent_connectivity_test.c +++ b/test/core/surface/concurrent_connectivity_test.c @@ -254,7 +254,7 @@ int run_concurrent_connectivity_test() { void watches_with_short_timeouts(void *addr) { for (int i = 0; i < NUM_OUTER_LOOPS_SHORT_TIMEOUTS; ++i) { - grpc_completion_queue *cq = grpc_completion_queue_create(NULL); + grpc_completion_queue *cq = grpc_completion_queue_create_for_next(NULL); grpc_channel *chan = grpc_insecure_channel_create((char *)addr, NULL, NULL); for (int j = 0; j < NUM_INNER_LOOPS_SHORT_TIMEOUTS; ++j) { From 7563641414f490f0f66a6991fc3901319ddb172c Mon Sep 17 00:00:00 2001 From: murgatroid99 Date: Thu, 25 May 2017 16:36:01 -0700 Subject: [PATCH 28/45] Fix node cancellation tests --- src/node/test/surface_test.js | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/src/node/test/surface_test.js b/src/node/test/surface_test.js index 0696e7ae195..f8eaf62aaff 100644 --- a/src/node/test/surface_test.js +++ b/src/node/test/surface_test.js @@ -1334,14 +1334,14 @@ describe('Cancelling surface client', function() { }); it('Should correctly cancel a unary call', function(done) { var call = client.div({'divisor': 0, 'dividend': 0}, function(err, resp) { - assert.strictEqual(err.code, surface_client.status.CANCELLED); + assert.strictEqual(err.code, grpc.status.CANCELLED); done(); }); call.cancel(); }); it('Should correctly cancel a client stream call', function(done) { var call = client.sum(function(err, resp) { - assert.strictEqual(err.code, surface_client.status.CANCELLED); + assert.strictEqual(err.code, grpc.status.CANCELLED); done(); }); call.cancel(); @@ -1350,7 +1350,7 @@ describe('Cancelling surface client', function() { var call = client.fib({'limit': 5}); call.on('data', function() {}); call.on('error', function(error) { - assert.strictEqual(error.code, surface_client.status.CANCELLED); + assert.strictEqual(error.code, grpc.status.CANCELLED); done(); }); call.cancel(); @@ -1359,14 +1359,14 @@ describe('Cancelling surface client', function() { var call = client.divMany(); call.on('data', function() {}); call.on('error', function(error) { - assert.strictEqual(error.code, surface_client.status.CANCELLED); + assert.strictEqual(error.code, grpc.status.CANCELLED); done(); }); call.cancel(); }); it('Should be idempotent', function(done) { var call = client.div({'divisor': 0, 'dividend': 0}, function(err, resp) { - assert.strictEqual(err.code, surface_client.status.CANCELLED); + assert.strictEqual(err.code, grpc.status.CANCELLED); // Call asynchronously to try cancelling after call is fully completed setImmediate(function() { assert.doesNotThrow(function() { From 28b082824353eab3912b9c4f949f0c426ea9f702 Mon Sep 17 00:00:00 2001 From: ncteisen Date: Mon, 22 May 2017 10:04:01 -0700 Subject: [PATCH 29/45] bm trickly bugfix --- test/cpp/microbenchmarks/bm_fullstack_trickle.cc | 16 ++++++++-------- tools/profiling/microbenchmarks/bm_json.py | 2 +- 2 files changed, 9 insertions(+), 9 deletions(-) diff --git a/test/cpp/microbenchmarks/bm_fullstack_trickle.cc b/test/cpp/microbenchmarks/bm_fullstack_trickle.cc index d7e3a9cf47d..a087bfe8996 100644 --- a/test/cpp/microbenchmarks/bm_fullstack_trickle.cc +++ b/test/cpp/microbenchmarks/bm_fullstack_trickle.cc @@ -320,8 +320,8 @@ static void BM_PumpStreamServerToClient_Trickle(benchmark::State& state) { } static void StreamingTrickleArgs(benchmark::internal::Benchmark* b) { - for (int i = 1; i <= 128 * 1024 * 1024; i *= 8) { - for (int j = 64; j <= 128 * 1024 * 1024; j *= 8) { + for (int i = 1; i <= 128 * 1024 * 1024; i *= 16) { + for (int j = 64; j <= 128 * 1024 * 1024; j *= 16) { double expected_time = static_cast(14 + i) / (125.0 * static_cast(j)); if (expected_time > 2.0) continue; @@ -425,12 +425,12 @@ static void UnaryTrickleArgs(benchmark::internal::Benchmark* b) { const int svr_4M = 4 * 1024 * 1024; const int svr_64M = 64 * 1024 * 1024; for (int bw = 64; bw <= 128 * 1024 * 1024; bw *= 16) { - b->Args({bw, cli_1024k, svr_256k}); - b->Args({bw, cli_1024k, svr_4M}); - b->Args({bw, cli_1024k, svr_64M}); - b->Args({bw, cli_32M, svr_256k}); - b->Args({bw, cli_32M, svr_4M}); - b->Args({bw, cli_32M, svr_64M}); + b->Args({cli_1024k, svr_256k, bw}); + b->Args({cli_1024k, svr_4M, bw}); + b->Args({cli_1024k, svr_64M, bw}); + b->Args({cli_32M, svr_256k, bw}); + b->Args({cli_32M, svr_4M, bw}); + b->Args({cli_32M, svr_64M, bw}); } } BENCHMARK(BM_PumpUnbalancedUnary_Trickle)->Apply(UnaryTrickleArgs); diff --git a/tools/profiling/microbenchmarks/bm_json.py b/tools/profiling/microbenchmarks/bm_json.py index f4d628e11f0..49a37072208 100644 --- a/tools/profiling/microbenchmarks/bm_json.py +++ b/tools/profiling/microbenchmarks/bm_json.py @@ -56,7 +56,7 @@ _BM_SPECS = { }, 'BM_PumpUnbalancedUnary_Trickle': { 'tpl': [], - 'dyn': ['request_size', 'bandwidth_kilobits'], + 'dyn': ['cli_req_size', 'svr_req_size', 'bandwidth_kilobits'], }, 'BM_ErrorStringOnNewError': { 'tpl': ['fixture'], From a4cd06fc212d218255bd083b47d733eebd0b1c77 Mon Sep 17 00:00:00 2001 From: ncteisen Date: Fri, 26 May 2017 11:06:10 -0400 Subject: [PATCH 30/45] Fixes --- test/cpp/microbenchmarks/bm_fullstack_trickle.cc | 16 ++++++++-------- 1 file changed, 8 insertions(+), 8 deletions(-) diff --git a/test/cpp/microbenchmarks/bm_fullstack_trickle.cc b/test/cpp/microbenchmarks/bm_fullstack_trickle.cc index a087bfe8996..702a14d14ea 100644 --- a/test/cpp/microbenchmarks/bm_fullstack_trickle.cc +++ b/test/cpp/microbenchmarks/bm_fullstack_trickle.cc @@ -320,8 +320,8 @@ static void BM_PumpStreamServerToClient_Trickle(benchmark::State& state) { } static void StreamingTrickleArgs(benchmark::internal::Benchmark* b) { - for (int i = 1; i <= 128 * 1024 * 1024; i *= 16) { - for (int j = 64; j <= 128 * 1024 * 1024; j *= 16) { + for (int i = 1; i <= 128 * 1024 * 1024; i *= 8) { + for (int j = 64; j <= 128 * 1024 * 1024; j *= 8) { double expected_time = static_cast(14 + i) / (125.0 * static_cast(j)); if (expected_time > 2.0) continue; @@ -419,18 +419,18 @@ static void BM_PumpUnbalancedUnary_Trickle(benchmark::State& state) { } static void UnaryTrickleArgs(benchmark::internal::Benchmark* b) { + // A selection of interesting numbers const int cli_1024k = 1024 * 1024; const int cli_32M = 32 * 1024 * 1024; const int svr_256k = 256 * 1024; const int svr_4M = 4 * 1024 * 1024; const int svr_64M = 64 * 1024 * 1024; for (int bw = 64; bw <= 128 * 1024 * 1024; bw *= 16) { - b->Args({cli_1024k, svr_256k, bw}); - b->Args({cli_1024k, svr_4M, bw}); - b->Args({cli_1024k, svr_64M, bw}); - b->Args({cli_32M, svr_256k, bw}); - b->Args({cli_32M, svr_4M, bw}); - b->Args({cli_32M, svr_64M, bw}); + for (auto svr : {svr_256k, svr_4M, svr_64M}) { + for (auto cli: {cli_1024k, cli_32M}) { + b->Args({cli, svr, bw}); + } + } } } BENCHMARK(BM_PumpUnbalancedUnary_Trickle)->Apply(UnaryTrickleArgs); From cce3ccc29ede38276628060ab9b819dbeaafe23f Mon Sep 17 00:00:00 2001 From: Alexander Polcyn Date: Fri, 26 May 2017 14:10:13 -0700 Subject: [PATCH 31/45] get rid of flakey asserts in num_watchers test --- .../core/surface/num_external_connectivity_watchers_test.c | 7 ------- 1 file changed, 7 deletions(-) diff --git a/test/core/surface/num_external_connectivity_watchers_test.c b/test/core/surface/num_external_connectivity_watchers_test.c index 96288ab60db..93944c9ad5b 100644 --- a/test/core/surface/num_external_connectivity_watchers_test.c +++ b/test/core/surface/num_external_connectivity_watchers_test.c @@ -92,15 +92,12 @@ static void run_timeouts_test(const test_fixture *fixture) { /* start 1 watcher and then let it time out */ channel_idle_start_watch(channel, cq); - GPR_ASSERT(grpc_channel_num_external_connectivity_watchers(channel) == 1); channel_idle_poll_for_timeout(channel, cq); GPR_ASSERT(grpc_channel_num_external_connectivity_watchers(channel) == 0); /* start 3 watchers and then let them all time out */ for (size_t i = 1; i <= 3; i++) { channel_idle_start_watch(channel, cq); - GPR_ASSERT(grpc_channel_num_external_connectivity_watchers(channel) == - (int)i); } for (size_t i = 1; i <= 3; i++) { channel_idle_poll_for_timeout(channel, cq); @@ -111,14 +108,11 @@ static void run_timeouts_test(const test_fixture *fixture) { * time out */ for (size_t i = 1; i <= 3; i++) { channel_idle_start_watch(channel, cq); - GPR_ASSERT(grpc_channel_num_external_connectivity_watchers(channel) == - (int)i); } channel_idle_poll_for_timeout(channel, cq); for (size_t i = 3; i <= 5; i++) { channel_idle_start_watch(channel, cq); } - GPR_ASSERT(grpc_channel_num_external_connectivity_watchers(channel) >= 3); for (size_t i = 1; i <= 5; i++) { channel_idle_poll_for_timeout(channel, cq); } @@ -160,7 +154,6 @@ static void run_channel_shutdown_before_timeout_test( grpc_channel_watch_connectivity_state(channel, GRPC_CHANNEL_IDLE, connect_deadline, cq, (void *)1); - GPR_ASSERT(grpc_channel_num_external_connectivity_watchers(channel) == 1); grpc_channel_destroy(channel); grpc_event ev = From 93fdf611a571450964ad4512ff2ed33d7c39c47c Mon Sep 17 00:00:00 2001 From: Makarand Dharmapurikar Date: Tue, 30 May 2017 14:03:01 -0700 Subject: [PATCH 32/45] s/inline/__inline/. Visual studio incompatiblity. MS Visual studio '13 and before don't understand inline and throw Error C2054. Reference: https://msdn.microsoft.com/en-us/library/bw1hbe6y.aspx --- src/core/ext/census/intrusive_hash_map.c | 10 +++++----- src/core/ext/census/intrusive_hash_map.h | 2 +- 2 files changed, 6 insertions(+), 6 deletions(-) diff --git a/src/core/ext/census/intrusive_hash_map.c b/src/core/ext/census/intrusive_hash_map.c index 77512a3aac8..d147f23364d 100644 --- a/src/core/ext/census/intrusive_hash_map.c +++ b/src/core/ext/census/intrusive_hash_map.c @@ -37,7 +37,7 @@ extern bool hm_index_compare(const hm_index *A, const hm_index *B); /* Simple hashing function that takes lower 32 bits. */ -static inline uint32_t chunked_vector_hasher(uint64_t key) { +static __inline uint32_t chunked_vector_hasher(uint64_t key) { return (uint32_t)key; } @@ -45,7 +45,7 @@ static inline uint32_t chunked_vector_hasher(uint64_t key) { static const size_t VECTOR_CHUNK_SIZE = (1 << 20) / sizeof(void *); /* Helper functions which return buckets from the chunked vector. */ -static inline void **get_mutable_bucket(const chunked_vector *buckets, +static __inline void **get_mutable_bucket(const chunked_vector *buckets, uint32_t index) { if (index < VECTOR_CHUNK_SIZE) { return &buckets->first_[index]; @@ -54,7 +54,7 @@ static inline void **get_mutable_bucket(const chunked_vector *buckets, return &buckets->rest_[rest_index][index % VECTOR_CHUNK_SIZE]; } -static inline void *get_bucket(const chunked_vector *buckets, uint32_t index) { +static __inline void *get_bucket(const chunked_vector *buckets, uint32_t index) { if (index < VECTOR_CHUNK_SIZE) { return buckets->first_[index]; } @@ -63,7 +63,7 @@ static inline void *get_bucket(const chunked_vector *buckets, uint32_t index) { } /* Helper function. */ -static inline size_t RestSize(const chunked_vector *vec) { +static __inline size_t RestSize(const chunked_vector *vec) { return (vec->size_ <= VECTOR_CHUNK_SIZE) ? 0 : (vec->size_ - VECTOR_CHUNK_SIZE - 1) / VECTOR_CHUNK_SIZE + 1; @@ -222,7 +222,7 @@ hm_item *intrusive_hash_map_erase(intrusive_hash_map *hash_map, uint64_t key) { * array_size-1. Returns true if it is a new hm_item and false if the hm_item * already existed. */ -static inline bool intrusive_hash_map_internal_insert(chunked_vector *buckets, +static __inline bool intrusive_hash_map_internal_insert(chunked_vector *buckets, uint32_t hash_mask, hm_item *item) { const uint64_t key = item->key; diff --git a/src/core/ext/census/intrusive_hash_map.h b/src/core/ext/census/intrusive_hash_map.h index a8405517b89..e316bf4b161 100644 --- a/src/core/ext/census/intrusive_hash_map.h +++ b/src/core/ext/census/intrusive_hash_map.h @@ -101,7 +101,7 @@ typedef struct hm_index { /* Returns true if two hm_indices point to the same object within the hash map * and false otherwise. */ -inline bool hm_index_compare(const hm_index *A, const hm_index *B) { +__inline bool hm_index_compare(const hm_index *A, const hm_index *B) { return (A->item == B->item && A->bucket_index == B->bucket_index); } From aebcdbd732e9294c8a424d3167c028f02af5ef1c Mon Sep 17 00:00:00 2001 From: David Garcia Quintas Date: Tue, 30 May 2017 14:14:27 -0700 Subject: [PATCH 33/45] master bumped to 1.5.x --- BUILD | 4 ++-- CMakeLists.txt | 2 +- Makefile | 4 ++-- build.yaml | 2 +- gRPC-Core.podspec | 2 +- gRPC-ProtoRPC.podspec | 2 +- gRPC-RxLibrary.podspec | 2 +- gRPC.podspec | 2 +- package.json | 2 +- package.xml | 4 ++-- src/cpp/common/version_cc.cc | 2 +- src/csharp/Grpc.Core/Version.csproj.include | 2 +- src/csharp/Grpc.Core/VersionInfo.cs | 4 ++-- src/csharp/build_packages_dotnetcli.bat | 2 +- src/csharp/build_packages_dotnetcli.sh | 4 ++-- src/node/health_check/package.json | 4 ++-- src/node/tools/package.json | 2 +- src/objective-c/!ProtoCompiler-gRPCPlugin.podspec | 2 +- src/objective-c/GRPCClient/private/version.h | 2 +- src/php/composer.json | 2 +- src/php/ext/grpc/version.h | 2 +- src/python/grpcio/grpc/_grpcio_metadata.py | 2 +- src/python/grpcio/grpc_version.py | 2 +- src/python/grpcio_health_checking/grpc_version.py | 2 +- src/python/grpcio_reflection/grpc_version.py | 2 +- src/python/grpcio_tests/grpc_version.py | 2 +- src/ruby/lib/grpc/version.rb | 2 +- src/ruby/tools/version.rb | 2 +- tools/distrib/python/grpcio_tools/grpc_version.py | 2 +- tools/doxygen/Doxyfile.c++ | 2 +- tools/doxygen/Doxyfile.c++.internal | 2 +- 31 files changed, 37 insertions(+), 37 deletions(-) diff --git a/BUILD b/BUILD index bdea522ad15..d3a77808ea1 100644 --- a/BUILD +++ b/BUILD @@ -51,9 +51,9 @@ load( # This should be updated along with build.yaml g_stands_for = "gregarious" -core_version = "3.0.0-dev" +core_version = "4.0.0-dev" -version = "1.4.0-dev" +version = "1.5.0-dev" grpc_cc_library( name = "gpr", diff --git a/CMakeLists.txt b/CMakeLists.txt index fd53f621a65..11c6b047888 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -39,7 +39,7 @@ cmake_minimum_required(VERSION 2.8) set(PACKAGE_NAME "grpc") -set(PACKAGE_VERSION "1.4.0-dev") +set(PACKAGE_VERSION "1.5.0-dev") set(PACKAGE_STRING "${PACKAGE_NAME} ${PACKAGE_VERSION}") set(PACKAGE_TARNAME "${PACKAGE_NAME}-${PACKAGE_VERSION}") set(PACKAGE_BUGREPORT "https://github.com/grpc/grpc/issues/") diff --git a/Makefile b/Makefile index 82b2104b4a7..5e29711fb18 100644 --- a/Makefile +++ b/Makefile @@ -423,8 +423,8 @@ Q = @ endif CORE_VERSION = 4.0.0-dev -CPP_VERSION = 1.4.0-dev -CSHARP_VERSION = 1.4.0-dev +CPP_VERSION = 1.5.0-dev +CSHARP_VERSION = 1.5.0-dev CPPFLAGS_NO_ARCH += $(addprefix -I, $(INCLUDES)) $(addprefix -D, $(DEFINES)) CPPFLAGS += $(CPPFLAGS_NO_ARCH) $(ARCH_FLAGS) diff --git a/build.yaml b/build.yaml index 26144e33def..d1e61256e6e 100644 --- a/build.yaml +++ b/build.yaml @@ -14,7 +14,7 @@ settings: '#10': See the expand_version.py for all the quirks here core_version: 4.0.0-dev g_stands_for: gregarious - version: 1.4.0-dev + version: 1.5.0-dev filegroups: - name: census public_headers: diff --git a/gRPC-Core.podspec b/gRPC-Core.podspec index d9de2d78a05..e5e61df477f 100644 --- a/gRPC-Core.podspec +++ b/gRPC-Core.podspec @@ -37,7 +37,7 @@ Pod::Spec.new do |s| s.name = 'gRPC-Core' - version = '1.4.0-dev' + version = '1.5.0-dev' s.version = version s.summary = 'Core cross-platform gRPC library, written in C' s.homepage = 'http://www.grpc.io' diff --git a/gRPC-ProtoRPC.podspec b/gRPC-ProtoRPC.podspec index 62cb0d11a1c..6baef288855 100644 --- a/gRPC-ProtoRPC.podspec +++ b/gRPC-ProtoRPC.podspec @@ -36,7 +36,7 @@ Pod::Spec.new do |s| s.name = 'gRPC-ProtoRPC' - version = '1.4.0-dev' + version = '1.5.0-dev' s.version = version s.summary = 'RPC library for Protocol Buffers, based on gRPC' s.homepage = 'http://www.grpc.io' diff --git a/gRPC-RxLibrary.podspec b/gRPC-RxLibrary.podspec index 77ceb22123c..dfccc5d16c4 100644 --- a/gRPC-RxLibrary.podspec +++ b/gRPC-RxLibrary.podspec @@ -36,7 +36,7 @@ Pod::Spec.new do |s| s.name = 'gRPC-RxLibrary' - version = '1.4.0-dev' + version = '1.5.0-dev' s.version = version s.summary = 'Reactive Extensions library for iOS/OSX.' s.homepage = 'http://www.grpc.io' diff --git a/gRPC.podspec b/gRPC.podspec index 10520bd3880..7f4886ab656 100644 --- a/gRPC.podspec +++ b/gRPC.podspec @@ -35,7 +35,7 @@ Pod::Spec.new do |s| s.name = 'gRPC' - version = '1.4.0-dev' + version = '1.5.0-dev' s.version = version s.summary = 'gRPC client library for iOS/OSX' s.homepage = 'http://www.grpc.io' diff --git a/package.json b/package.json index 1ed182ced93..a0d76c435b6 100644 --- a/package.json +++ b/package.json @@ -1,6 +1,6 @@ { "name": "grpc", - "version": "1.4.0-dev", + "version": "1.5.0-dev", "author": "Google Inc.", "description": "gRPC Library for Node", "homepage": "http://www.grpc.io/", diff --git a/package.xml b/package.xml index 9179ef238c9..817a0345d60 100644 --- a/package.xml +++ b/package.xml @@ -13,8 +13,8 @@ 2017-05-22 - 1.4.0dev - 1.4.0dev + 1.5.0dev + 1.5.0dev beta diff --git a/src/cpp/common/version_cc.cc b/src/cpp/common/version_cc.cc index 72a4c4cf94a..e4f5cb8422e 100644 --- a/src/cpp/common/version_cc.cc +++ b/src/cpp/common/version_cc.cc @@ -37,5 +37,5 @@ #include namespace grpc { -grpc::string Version() { return "1.4.0-dev"; } +grpc::string Version() { return "1.5.0-dev"; } } diff --git a/src/csharp/Grpc.Core/Version.csproj.include b/src/csharp/Grpc.Core/Version.csproj.include index 8388bfd9cca..81156452f3e 100755 --- a/src/csharp/Grpc.Core/Version.csproj.include +++ b/src/csharp/Grpc.Core/Version.csproj.include @@ -1,7 +1,7 @@ - 1.4.0-dev + 1.5.0-dev 3.3.0 diff --git a/src/csharp/Grpc.Core/VersionInfo.cs b/src/csharp/Grpc.Core/VersionInfo.cs index 2e55d9d80eb..d507878c2df 100644 --- a/src/csharp/Grpc.Core/VersionInfo.cs +++ b/src/csharp/Grpc.Core/VersionInfo.cs @@ -48,11 +48,11 @@ namespace Grpc.Core /// /// Current AssemblyFileVersion of gRPC C# assemblies /// - public const string CurrentAssemblyFileVersion = "1.4.0.0"; + public const string CurrentAssemblyFileVersion = "1.5.0.0"; /// /// Current version of gRPC C# /// - public const string CurrentVersion = "1.4.0-dev"; + public const string CurrentVersion = "1.5.0-dev"; } } diff --git a/src/csharp/build_packages_dotnetcli.bat b/src/csharp/build_packages_dotnetcli.bat index aa8a8d3b17b..35664cc762d 100755 --- a/src/csharp/build_packages_dotnetcli.bat +++ b/src/csharp/build_packages_dotnetcli.bat @@ -28,7 +28,7 @@ @rem OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. @rem Current package versions -set VERSION=1.4.0-dev +set VERSION=1.5.0-dev @rem Adjust the location of nuget.exe set NUGET=C:\nuget\nuget.exe diff --git a/src/csharp/build_packages_dotnetcli.sh b/src/csharp/build_packages_dotnetcli.sh index d33923845c1..7dc07a220df 100755 --- a/src/csharp/build_packages_dotnetcli.sh +++ b/src/csharp/build_packages_dotnetcli.sh @@ -54,7 +54,7 @@ dotnet pack --configuration Release Grpc.Auth --output ../../../artifacts dotnet pack --configuration Release Grpc.HealthCheck --output ../../../artifacts dotnet pack --configuration Release Grpc.Reflection --output ../../../artifacts -nuget pack Grpc.nuspec -Version "1.4.0-dev" -OutputDirectory ../../artifacts -nuget pack Grpc.Tools.nuspec -Version "1.4.0-dev" -OutputDirectory ../../artifacts +nuget pack Grpc.nuspec -Version "1.5.0-dev" -OutputDirectory ../../artifacts +nuget pack Grpc.Tools.nuspec -Version "1.5.0-dev" -OutputDirectory ../../artifacts (cd ../../artifacts && zip csharp_nugets_dotnetcli.zip *.nupkg) diff --git a/src/node/health_check/package.json b/src/node/health_check/package.json index 37c9b7a54f5..0922f54a394 100644 --- a/src/node/health_check/package.json +++ b/src/node/health_check/package.json @@ -1,6 +1,6 @@ { "name": "grpc-health-check", - "version": "1.4.0-dev", + "version": "1.5.0-dev", "author": "Google Inc.", "description": "Health check service for use with gRPC", "repository": { @@ -15,7 +15,7 @@ } ], "dependencies": { - "grpc": "^1.4.0-dev", + "grpc": "^1.5.0-dev", "lodash": "^3.9.3", "google-protobuf": "^3.0.0" }, diff --git a/src/node/tools/package.json b/src/node/tools/package.json index a81aa87f4bb..542d52d48bc 100644 --- a/src/node/tools/package.json +++ b/src/node/tools/package.json @@ -1,6 +1,6 @@ { "name": "grpc-tools", - "version": "1.4.0-dev", + "version": "1.5.0-dev", "author": "Google Inc.", "description": "Tools for developing with gRPC on Node.js", "homepage": "http://www.grpc.io/", diff --git a/src/objective-c/!ProtoCompiler-gRPCPlugin.podspec b/src/objective-c/!ProtoCompiler-gRPCPlugin.podspec index 2f29058b59d..711814e7fa9 100644 --- a/src/objective-c/!ProtoCompiler-gRPCPlugin.podspec +++ b/src/objective-c/!ProtoCompiler-gRPCPlugin.podspec @@ -42,7 +42,7 @@ Pod::Spec.new do |s| # exclamation mark ensures that other "regular" pods will be able to find it as it'll be installed # before them. s.name = '!ProtoCompiler-gRPCPlugin' - v = '1.4.0-dev' + v = '1.5.0-dev' s.version = v s.summary = 'The gRPC ProtoC plugin generates Objective-C files from .proto services.' s.description = <<-DESC diff --git a/src/objective-c/GRPCClient/private/version.h b/src/objective-c/GRPCClient/private/version.h index c846f4214c9..cacbce46448 100644 --- a/src/objective-c/GRPCClient/private/version.h +++ b/src/objective-c/GRPCClient/private/version.h @@ -38,4 +38,4 @@ // `tools/buildgen/generate_projects.sh`. -#define GRPC_OBJC_VERSION_STRING @"1.4.0-dev" +#define GRPC_OBJC_VERSION_STRING @"1.5.0-dev" diff --git a/src/php/composer.json b/src/php/composer.json index a4fba7e4f6a..3a97e5fb414 100644 --- a/src/php/composer.json +++ b/src/php/composer.json @@ -2,7 +2,7 @@ "name": "grpc/grpc-dev", "description": "gRPC library for PHP - for Developement use only", "license": "BSD-3-Clause", - "version": "1.4.0", + "version": "1.5.0", "require": { "php": ">=5.5.0", "google/protobuf": "^v3.3.0" diff --git a/src/php/ext/grpc/version.h b/src/php/ext/grpc/version.h index 993ef2de274..303a63ec364 100644 --- a/src/php/ext/grpc/version.h +++ b/src/php/ext/grpc/version.h @@ -35,6 +35,6 @@ #ifndef VERSION_H #define VERSION_H -#define PHP_GRPC_VERSION "1.4.0" +#define PHP_GRPC_VERSION "1.5.0" #endif /* VERSION_H */ diff --git a/src/python/grpcio/grpc/_grpcio_metadata.py b/src/python/grpcio/grpc/_grpcio_metadata.py index a0cb0dd067f..3ae2602d20c 100644 --- a/src/python/grpcio/grpc/_grpcio_metadata.py +++ b/src/python/grpcio/grpc/_grpcio_metadata.py @@ -29,4 +29,4 @@ # AUTO-GENERATED FROM `$REPO_ROOT/templates/src/python/grpcio/grpc/_grpcio_metadata.py.template`!!! -__version__ = """1.4.0.dev0""" +__version__ = """1.5.0.dev0""" diff --git a/src/python/grpcio/grpc_version.py b/src/python/grpcio/grpc_version.py index ea4bc7ba207..f5bd29ff85c 100644 --- a/src/python/grpcio/grpc_version.py +++ b/src/python/grpcio/grpc_version.py @@ -29,4 +29,4 @@ # AUTO-GENERATED FROM `$REPO_ROOT/templates/src/python/grpcio/grpc_version.py.template`!!! -VERSION='1.4.0.dev0' +VERSION='1.5.0.dev0' diff --git a/src/python/grpcio_health_checking/grpc_version.py b/src/python/grpcio_health_checking/grpc_version.py index 26aa555e14c..26a83018839 100644 --- a/src/python/grpcio_health_checking/grpc_version.py +++ b/src/python/grpcio_health_checking/grpc_version.py @@ -29,4 +29,4 @@ # AUTO-GENERATED FROM `$REPO_ROOT/templates/src/python/grpcio_health_checking/grpc_version.py.template`!!! -VERSION='1.4.0.dev0' +VERSION='1.5.0.dev0' diff --git a/src/python/grpcio_reflection/grpc_version.py b/src/python/grpcio_reflection/grpc_version.py index 978d6b4011f..f16737df80a 100644 --- a/src/python/grpcio_reflection/grpc_version.py +++ b/src/python/grpcio_reflection/grpc_version.py @@ -29,4 +29,4 @@ # AUTO-GENERATED FROM `$REPO_ROOT/templates/src/python/grpcio_reflection/grpc_version.py.template`!!! -VERSION='1.4.0.dev0' +VERSION='1.5.0.dev0' diff --git a/src/python/grpcio_tests/grpc_version.py b/src/python/grpcio_tests/grpc_version.py index 5f0b0848846..28cf8a8a628 100644 --- a/src/python/grpcio_tests/grpc_version.py +++ b/src/python/grpcio_tests/grpc_version.py @@ -29,4 +29,4 @@ # AUTO-GENERATED FROM `$REPO_ROOT/templates/src/python/grpcio_tests/grpc_version.py.template`!!! -VERSION='1.4.0.dev0' +VERSION='1.5.0.dev0' diff --git a/src/ruby/lib/grpc/version.rb b/src/ruby/lib/grpc/version.rb index f30dff335f1..e2e784d19f2 100644 --- a/src/ruby/lib/grpc/version.rb +++ b/src/ruby/lib/grpc/version.rb @@ -29,5 +29,5 @@ # GRPC contains the General RPC module. module GRPC - VERSION = '1.4.0.dev' + VERSION = '1.5.0.dev' end diff --git a/src/ruby/tools/version.rb b/src/ruby/tools/version.rb index 1f8d4afb95f..4f74238df79 100644 --- a/src/ruby/tools/version.rb +++ b/src/ruby/tools/version.rb @@ -29,6 +29,6 @@ module GRPC module Tools - VERSION = '1.4.0.dev' + VERSION = '1.5.0.dev' end end diff --git a/tools/distrib/python/grpcio_tools/grpc_version.py b/tools/distrib/python/grpcio_tools/grpc_version.py index 1f2aa81c850..417722a4d24 100644 --- a/tools/distrib/python/grpcio_tools/grpc_version.py +++ b/tools/distrib/python/grpcio_tools/grpc_version.py @@ -29,4 +29,4 @@ # AUTO-GENERATED FROM `$REPO_ROOT/templates/tools/distrib/python/grpcio_tools/grpc_version.py.template`!!! -VERSION='1.4.0.dev0' +VERSION='1.5.0.dev0' diff --git a/tools/doxygen/Doxyfile.c++ b/tools/doxygen/Doxyfile.c++ index 3861bdb85af..23746de1aa5 100644 --- a/tools/doxygen/Doxyfile.c++ +++ b/tools/doxygen/Doxyfile.c++ @@ -40,7 +40,7 @@ PROJECT_NAME = "GRPC C++" # could be handy for archiving the generated documentation or if some version # control system is used. -PROJECT_NUMBER = 1.4.0-dev +PROJECT_NUMBER = 1.5.0-dev # Using the PROJECT_BRIEF tag one can provide an optional one line description # for a project that appears at the top of each page and should give viewer a diff --git a/tools/doxygen/Doxyfile.c++.internal b/tools/doxygen/Doxyfile.c++.internal index 5bab66c7d6a..52e722f56c9 100644 --- a/tools/doxygen/Doxyfile.c++.internal +++ b/tools/doxygen/Doxyfile.c++.internal @@ -40,7 +40,7 @@ PROJECT_NAME = "GRPC C++" # could be handy for archiving the generated documentation or if some version # control system is used. -PROJECT_NUMBER = 1.4.0-dev +PROJECT_NUMBER = 1.5.0-dev # Using the PROJECT_BRIEF tag one can provide an optional one line description # for a project that appears at the top of each page and should give viewer a From a9f94e9882e5c9978fb6376d94a7144f53ab1c4b Mon Sep 17 00:00:00 2001 From: Makarand Dharmapurikar Date: Tue, 30 May 2017 15:21:46 -0700 Subject: [PATCH 34/45] s/inline/__inline/ --- test/core/census/intrusive_hash_map_test.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/test/core/census/intrusive_hash_map_test.c b/test/core/census/intrusive_hash_map_test.c index fe8d3a1675a..552546f9a31 100644 --- a/test/core/census/intrusive_hash_map_test.c +++ b/test/core/census/intrusive_hash_map_test.c @@ -49,7 +49,7 @@ static const uint32_t kInitialLog2Size = 4; typedef struct object { uint64_t val; } object; /* Helper function to allocate and initialize object. */ -static inline object *make_new_object(uint64_t val) { +static __inline object *make_new_object(uint64_t val) { object *obj = (object *)gpr_malloc(sizeof(object)); obj->val = val; return obj; @@ -63,7 +63,7 @@ typedef struct ptr_item { /* Helper function that creates a new hash map item. It is up to the user to * free the item that was allocated. */ -static inline ptr_item *make_ptr_item(uint64_t key, uint64_t value) { +static __inline ptr_item *make_ptr_item(uint64_t key, uint64_t value) { ptr_item *new_item = (ptr_item *)gpr_malloc(sizeof(ptr_item)); new_item->IHM_key = key; new_item->IHM_hash_link = NULL; From 7ed4a63512ca58ee608ed3f7fd6c2a6bbd1c2ffc Mon Sep 17 00:00:00 2001 From: Mak Dharma Date: Tue, 30 May 2017 20:04:36 -0700 Subject: [PATCH 35/45] clang-format --- src/core/ext/census/intrusive_hash_map.c | 9 +++++---- 1 file changed, 5 insertions(+), 4 deletions(-) diff --git a/src/core/ext/census/intrusive_hash_map.c b/src/core/ext/census/intrusive_hash_map.c index d147f23364d..9f56b765e12 100644 --- a/src/core/ext/census/intrusive_hash_map.c +++ b/src/core/ext/census/intrusive_hash_map.c @@ -46,7 +46,7 @@ static const size_t VECTOR_CHUNK_SIZE = (1 << 20) / sizeof(void *); /* Helper functions which return buckets from the chunked vector. */ static __inline void **get_mutable_bucket(const chunked_vector *buckets, - uint32_t index) { + uint32_t index) { if (index < VECTOR_CHUNK_SIZE) { return &buckets->first_[index]; } @@ -54,7 +54,8 @@ static __inline void **get_mutable_bucket(const chunked_vector *buckets, return &buckets->rest_[rest_index][index % VECTOR_CHUNK_SIZE]; } -static __inline void *get_bucket(const chunked_vector *buckets, uint32_t index) { +static __inline void *get_bucket(const chunked_vector *buckets, + uint32_t index) { if (index < VECTOR_CHUNK_SIZE) { return buckets->first_[index]; } @@ -223,8 +224,8 @@ hm_item *intrusive_hash_map_erase(intrusive_hash_map *hash_map, uint64_t key) { * already existed. */ static __inline bool intrusive_hash_map_internal_insert(chunked_vector *buckets, - uint32_t hash_mask, - hm_item *item) { + uint32_t hash_mask, + hm_item *item) { const uint64_t key = item->key; uint32_t index = chunked_vector_hasher(key) & hash_mask; hm_item **slot = (hm_item **)get_mutable_bucket(buckets, index); From d8543c4e0f4ff827337654e198d41ff5539a2b9e Mon Sep 17 00:00:00 2001 From: Matt Kwong Date: Wed, 17 May 2017 18:04:58 -0700 Subject: [PATCH 36/45] Fix --measure_cpu_costs flag in run_tests.py on Windows --- tools/run_tests/python_utils/jobset.py | 7 ++++++- 1 file changed, 6 insertions(+), 1 deletion(-) diff --git a/tools/run_tests/python_utils/jobset.py b/tools/run_tests/python_utils/jobset.py index 37540353088..b4f7557a35f 100755 --- a/tools/run_tests/python_utils/jobset.py +++ b/tools/run_tests/python_utils/jobset.py @@ -270,8 +270,13 @@ class Job(object): env = sanitized_environment(env) self._start = time.time() cmdline = self._spec.cmdline - if measure_cpu_costs: + # The Unix time command is finicky when used with MSBuild, so we don't use it + # with jobs that run MSBuild. + global measure_cpu_costs + if measure_cpu_costs and not 'vsprojects\\build' in cmdline[0]: cmdline = ['time', '-p'] + cmdline + else: + measure_cpu_costs = False try_start = lambda: subprocess.Popen(args=cmdline, stderr=subprocess.STDOUT, stdout=self._tempfile, From 0315de23cc14072b2c202129892f8b13a12355e0 Mon Sep 17 00:00:00 2001 From: Jan Tattermusch Date: Wed, 31 May 2017 17:58:49 -0700 Subject: [PATCH 37/45] add sanity to internal_ci --- tools/internal_ci/linux/grpc_sanity.cfg | 39 +++++++++++++++++++++++++ tools/internal_ci/linux/grpc_sanity.sh | 2 +- 2 files changed, 40 insertions(+), 1 deletion(-) create mode 100644 tools/internal_ci/linux/grpc_sanity.cfg diff --git a/tools/internal_ci/linux/grpc_sanity.cfg b/tools/internal_ci/linux/grpc_sanity.cfg new file mode 100644 index 00000000000..e2f320494b4 --- /dev/null +++ b/tools/internal_ci/linux/grpc_sanity.cfg @@ -0,0 +1,39 @@ +# Copyright 2017, Google Inc. +# All rights reserved. +# +# Redistribution and use in source and binary forms, with or without +# modification, are permitted provided that the following conditions are +# met: +# +# * Redistributions of source code must retain the above copyright +# notice, this list of conditions and the following disclaimer. +# * Redistributions in binary form must reproduce the above +# copyright notice, this list of conditions and the following disclaimer +# in the documentation and/or other materials provided with the +# distribution. +# * Neither the name of Google Inc. nor the names of its +# contributors may be used to endorse or promote products derived from +# this software without specific prior written permission. +# +# THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS +# "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT +# LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR +# A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT +# OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, +# SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT +# LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, +# DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY +# THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +# (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE +# OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + +# Config file for the internal CI (in protobuf text format) + +# Location of the continuous shell script in repository. +build_file: "grpc/tools/internal_ci/linux/grpc_sanity.sh" +timeout_mins: 20 +action { + define_artifacts { + regex: "**/*sponge_log.xml" + } +} diff --git a/tools/internal_ci/linux/grpc_sanity.sh b/tools/internal_ci/linux/grpc_sanity.sh index 7166ce7d248..432a42c4493 100755 --- a/tools/internal_ci/linux/grpc_sanity.sh +++ b/tools/internal_ci/linux/grpc_sanity.sh @@ -35,4 +35,4 @@ cd $(dirname $0)/../../.. source tools/internal_ci/helper_scripts/prepare_build_linux_rc -tools/run_tests/run_tests.py -l sanity -c opt -t -x sponge_log.xml --use_docker --report_suite_name sanity_linux_opt +tools/run_tests/run_tests_matrix.py -f basictests linux sanity opt --inner_jobs 16 -j 1 --internal_ci From 3972fad38cbe06aef040f6d2c010397c0e950813 Mon Sep 17 00:00:00 2001 From: ncteisen Date: Wed, 31 May 2017 18:47:49 -0700 Subject: [PATCH 38/45] clang format --- test/cpp/microbenchmarks/bm_fullstack_trickle.cc | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/test/cpp/microbenchmarks/bm_fullstack_trickle.cc b/test/cpp/microbenchmarks/bm_fullstack_trickle.cc index 702a14d14ea..9f616fe152f 100644 --- a/test/cpp/microbenchmarks/bm_fullstack_trickle.cc +++ b/test/cpp/microbenchmarks/bm_fullstack_trickle.cc @@ -427,7 +427,7 @@ static void UnaryTrickleArgs(benchmark::internal::Benchmark* b) { const int svr_64M = 64 * 1024 * 1024; for (int bw = 64; bw <= 128 * 1024 * 1024; bw *= 16) { for (auto svr : {svr_256k, svr_4M, svr_64M}) { - for (auto cli: {cli_1024k, cli_32M}) { + for (auto cli : {cli_1024k, cli_32M}) { b->Args({cli, svr, bw}); } } From df8b5eacf091e77d6396b6ee93bbbd443db8ea05 Mon Sep 17 00:00:00 2001 From: Eric Gribkoff Date: Wed, 31 May 2017 16:11:20 -0700 Subject: [PATCH 39/45] Update comment formatting --- include/grpc++/grpc++.h | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/include/grpc++/grpc++.h b/include/grpc++/grpc++.h index d6c3e2e7683..a4f512dbee9 100644 --- a/include/grpc++/grpc++.h +++ b/include/grpc++/grpc++.h @@ -34,18 +34,18 @@ /// \mainpage gRPC C++ API /// /// The gRPC C++ API mainly consists of the following classes: -// +///
/// - grpc::Channel, which represents the connection to an endpoint. See [the /// gRPC Concepts page](http://www.grpc.io/docs/guides/concepts.html) for more /// details. Channels are created by the factory function grpc::CreateChannel. -// +/// /// - grpc::CompletionQueue, the producer-consumer queue used for all /// asynchronous communication with the gRPC runtime. -// +/// /// - grpc::ClientContext and grpc::ServerContext, where optional configuration /// for an RPC can be set, such as setting custom metadata to be conveyed to the /// peer, compression settings, authentication, etc. -// +/// /// - grpc::Server, representing a gRPC server, created by grpc::ServerBuilder. /// /// Streaming calls are handled with the streaming classes in From ed32b787781d0a7381803212c4ab512e0729a92a Mon Sep 17 00:00:00 2001 From: murgatroid99 Date: Thu, 1 Jun 2017 10:44:39 -0700 Subject: [PATCH 40/45] Switch node_to_cpp unary benchmark to async --- tools/run_tests/performance/scenario_config.py | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/tools/run_tests/performance/scenario_config.py b/tools/run_tests/performance/scenario_config.py index d28be006298..e18fd69cc4e 100644 --- a/tools/run_tests/performance/scenario_config.py +++ b/tools/run_tests/performance/scenario_config.py @@ -575,8 +575,8 @@ class NodeLanguage: unconstrained_client='async') yield _ping_pong_scenario( - 'node_to_cpp_protobuf_sync_unary_ping_pong', rpc_type='UNARY', - client_type='SYNC_CLIENT', server_type='SYNC_SERVER', + 'node_to_cpp_protobuf_async_unary_ping_pong', rpc_type='UNARY', + client_type='ASYNC_CLIENT', server_type='ASYNC_SERVER', server_language='c++', async_server_threads=1) yield _ping_pong_scenario( From dd1143dab060c7a4775429569075876dcf6f4503 Mon Sep 17 00:00:00 2001 From: Jan Tattermusch Date: Thu, 1 Jun 2017 20:58:36 +0200 Subject: [PATCH 41/45] install ruby on internal_ci linux --- tools/internal_ci/linux/grpc_build_artifacts.sh | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/tools/internal_ci/linux/grpc_build_artifacts.sh b/tools/internal_ci/linux/grpc_build_artifacts.sh index 1b12be143e9..16c2a748a60 100755 --- a/tools/internal_ci/linux/grpc_build_artifacts.sh +++ b/tools/internal_ci/linux/grpc_build_artifacts.sh @@ -35,4 +35,8 @@ cd $(dirname $0)/../../.. source tools/internal_ci/helper_scripts/prepare_build_linux_rc +# TODO(jtattermusch): install ruby on the internal_ci worker +gpg --keyserver hkp://keys.gnupg.net --recv-keys 409B6B1796C275462A1703113804BB82D39DC0E3 +curl -sSL https://get.rvm.io | bash -s stable --ruby + tools/run_tests/task_runner.py -f artifact linux From 5bc11d55d44a58e0139b62a3110bdf43ef7e4f95 Mon Sep 17 00:00:00 2001 From: Mehrdad Afshari Date: Thu, 1 Jun 2017 11:23:21 -0700 Subject: [PATCH 42/45] Expand pylint to grpc_health and grpc_reflection --- .../grpc_reflection/v1alpha/reflection.py | 5 ++--- tools/distrib/pylint_code.sh | 14 +++++++++----- 2 files changed, 11 insertions(+), 8 deletions(-) diff --git a/src/python/grpcio_reflection/grpc_reflection/v1alpha/reflection.py b/src/python/grpcio_reflection/grpc_reflection/v1alpha/reflection.py index 0f399f8f8d9..1a7d3259df0 100644 --- a/src/python/grpcio_reflection/grpc_reflection/v1alpha/reflection.py +++ b/src/python/grpcio_reflection/grpc_reflection/v1alpha/reflection.py @@ -28,8 +28,6 @@ # OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. """Reference implementation for reflection in gRPC Python.""" -import threading - import grpc from google.protobuf import descriptor_pb2 from google.protobuf import descriptor_pool @@ -120,6 +118,7 @@ class ReflectionServicer(reflection_pb2_grpc.ServerReflectionServicer): ])) def ServerReflectionInfo(self, request_iterator, context): + # pylint: disable=unused-argument for request in request_iterator: if request.HasField('file_by_filename'): yield self._file_by_filename(request.file_by_filename) @@ -152,4 +151,4 @@ def enable_server_reflection(service_names, server, pool=None): pool: DescriptorPool object to use (descriptor_pool.Default() if None). """ reflection_pb2_grpc.add_ServerReflectionServicer_to_server( - ReflectionServicer(service_names, pool), server) + ReflectionServicer(service_names, pool=pool), server) diff --git a/tools/distrib/pylint_code.sh b/tools/distrib/pylint_code.sh index 6369e605d53..b1e305c56d0 100755 --- a/tools/distrib/pylint_code.sh +++ b/tools/distrib/pylint_code.sh @@ -31,18 +31,22 @@ set -ex # change to root directory -cd $(dirname $0)/../.. +cd "$(dirname "$0")/../.." -DIRS=src/python/grpcio/grpc +DIRS=( + 'src/python/grpcio/grpc' + 'src/python/grpcio_reflection/grpc_reflection' + 'src/python/grpcio_health_checking/grpc_health' +) VIRTUALENV=python_pylint_venv virtualenv $VIRTUALENV -PYTHON=`realpath $VIRTUALENV/bin/python` +PYTHON=$(realpath $VIRTUALENV/bin/python) $PYTHON -m pip install pylint==1.6.5 -for dir in $DIRS; do - $PYTHON -m pylint --rcfile=.pylintrc -rn $dir || exit $? +for dir in "${DIRS[@]}"; do + $PYTHON -m pylint --rcfile=.pylintrc -rn "$dir" || exit $? done exit 0 From 631862f42100520b0d5d4602aeb4e547581eef72 Mon Sep 17 00:00:00 2001 From: Ken Payson Date: Thu, 1 Jun 2017 14:27:52 -0700 Subject: [PATCH 43/45] Change Python Windows tests to 3.5 --- tools/dockerfile/test/python_jessie_x64/Dockerfile | 3 ++- tools/run_tests/helper_scripts/build_python.sh | 1 + tools/run_tests/run_tests.py | 2 +- 3 files changed, 4 insertions(+), 2 deletions(-) diff --git a/tools/dockerfile/test/python_jessie_x64/Dockerfile b/tools/dockerfile/test/python_jessie_x64/Dockerfile index cc69f4b5cd5..f470bc24872 100644 --- a/tools/dockerfile/test/python_jessie_x64/Dockerfile +++ b/tools/dockerfile/test/python_jessie_x64/Dockerfile @@ -75,7 +75,8 @@ RUN pip install --upgrade google-api-python-client RUN apt-get update && apt-get install -y \ python-all-dev \ python3-all-dev \ - python-pip + python-pip \ + python3-pip # Install Python packages from PyPI RUN pip install pip --upgrade diff --git a/tools/run_tests/helper_scripts/build_python.sh b/tools/run_tests/helper_scripts/build_python.sh index 6ad285cdb97..bd4b40b508b 100755 --- a/tools/run_tests/helper_scripts/build_python.sh +++ b/tools/run_tests/helper_scripts/build_python.sh @@ -146,6 +146,7 @@ fi ############################ # Perform build operations # ############################ +$PYTHON -m pip install virtualenv # Instnatiate the virtualenv, preferring to do so from the relevant python # version. Even if these commands fail (e.g. on Windows due to name conflicts) diff --git a/tools/run_tests/run_tests.py b/tools/run_tests/run_tests.py index 568774cecea..204ed5c3975 100755 --- a/tools/run_tests/run_tests.py +++ b/tools/run_tests/run_tests.py @@ -672,7 +672,7 @@ class PythonLanguage(object): if args.compiler == 'default': if os.name == 'nt': - return (python27_config,) + return (python35_config,) else: return (python27_config, python34_config,) elif args.compiler == 'python2.7': From 697d68681df55c6256fe27cded33b07b50e9f187 Mon Sep 17 00:00:00 2001 From: Jan Tattermusch Date: Fri, 2 Jun 2017 11:55:08 -0700 Subject: [PATCH 44/45] adhoc install of macOS dependencies --- .../helper_scripts/prepare_build_macos_rc | 67 +++++++++++++++++++ tools/internal_ci/macos/grpc_master.sh | 2 +- 2 files changed, 68 insertions(+), 1 deletion(-) create mode 100644 tools/internal_ci/helper_scripts/prepare_build_macos_rc diff --git a/tools/internal_ci/helper_scripts/prepare_build_macos_rc b/tools/internal_ci/helper_scripts/prepare_build_macos_rc new file mode 100644 index 00000000000..2f97b0f705b --- /dev/null +++ b/tools/internal_ci/helper_scripts/prepare_build_macos_rc @@ -0,0 +1,67 @@ +#!/bin/bash +# Copyright 2017, Google Inc. +# All rights reserved. +# +# Redistribution and use in source and binary forms, with or without +# modification, are permitted provided that the following conditions are +# met: +# +# * Redistributions of source code must retain the above copyright +# notice, this list of conditions and the following disclaimer. +# * Redistributions in binary form must reproduce the above +# copyright notice, this list of conditions and the following disclaimer +# in the documentation and/or other materials provided with the +# distribution. +# * Neither the name of Google Inc. nor the names of its +# contributors may be used to endorse or promote products derived from +# this software without specific prior written permission. +# +# THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS +# "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT +# LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR +# A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT +# OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, +# SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT +# LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, +# DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY +# THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +# (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE +# OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + +# Source this rc script to prepare the environment for macos builds + +# TODO(jtattermusch): remove all deps once installed on MacOS workers + +# brew and C++ deps +yes | ruby -e "$(curl -fsSL https://raw.githubusercontent.com/Homebrew/install/master/install)" +brew install autoconf automake libtool ccache cmake gflags gpg wget + +# TODO(jtattermusch): install rvm & ruby +# TODO(jtattermusch): install cocoapods + +# python +wget https://bootstrap.pypa.io/get-pip.py +sudo python get-pip.py +sudo pip install virtualenv + +# TODO(jtattermusch): install python3 + +# mono +wget https://download.mono-project.com/archive/5.0.1/macos-10-universal/MonoFramework-MDK-5.0.1.1.macos10.xamarin.universal.pkg +sudo installer -pkg MonoFramework-MDK-5.0.1.1.macos10.xamarin.universal.pkg -target / + +# dotnet SDK +wget https://go.microsoft.com/fwlink/?linkid=843444 -O dotnet-dev-osx-x64.1.0.1.pkg +sudo installer -pkg dotnet-dev-osx-x64.1.0.1.pkg -target / +ln -s /usr/local/share/dotnet/dotnet /usr/local/bin/dotnet +dotnet --version # bootstrap dotnet SDK + +# Node +wget -qO- https://raw.githubusercontent.com/creationix/nvm/v0.30.2/install.sh | bash +. ~/.nvm/nvm.sh +nvm install 4 +nvm alias default 4 +npm update npm -g +npm install -g node-pre-gyp + +git submodule update --init diff --git a/tools/internal_ci/macos/grpc_master.sh b/tools/internal_ci/macos/grpc_master.sh index 4ce1af73a54..4eeac4e1e64 100755 --- a/tools/internal_ci/macos/grpc_master.sh +++ b/tools/internal_ci/macos/grpc_master.sh @@ -33,7 +33,7 @@ set -ex # change to grpc repo root cd $(dirname $0)/../../.. -git submodule update --init +source tools/internal_ci/helper_scripts/prepare_build_macos_rc tools/run_tests/run_tests_matrix.py -f basictests macos --internal_ci || FAILED="true" From e53730c3dccc218a889efb95b1326960fec5707f Mon Sep 17 00:00:00 2001 From: Jan Tattermusch Date: Fri, 2 Jun 2017 12:53:16 -0700 Subject: [PATCH 45/45] fix macos installation script --- tools/internal_ci/helper_scripts/prepare_build_macos_rc | 9 +++++++-- 1 file changed, 7 insertions(+), 2 deletions(-) diff --git a/tools/internal_ci/helper_scripts/prepare_build_macos_rc b/tools/internal_ci/helper_scripts/prepare_build_macos_rc index 2f97b0f705b..3eccff80b48 100644 --- a/tools/internal_ci/helper_scripts/prepare_build_macos_rc +++ b/tools/internal_ci/helper_scripts/prepare_build_macos_rc @@ -56,9 +56,14 @@ sudo installer -pkg dotnet-dev-osx-x64.1.0.1.pkg -target / ln -s /usr/local/share/dotnet/dotnet /usr/local/bin/dotnet dotnet --version # bootstrap dotnet SDK -# Node +# nvm wget -qO- https://raw.githubusercontent.com/creationix/nvm/v0.30.2/install.sh | bash -. ~/.nvm/nvm.sh +# bootstrap nvm silently & without terminating this script +set +ex +source ~/.nvm/nvm.sh +set -ex + +# node nvm install 4 nvm alias default 4 npm update npm -g