From b4b6a0e5e1a6077e69dcf51f1d7e42cf6d1be8bd Mon Sep 17 00:00:00 2001 From: Yuchen Zeng Date: Tue, 28 Feb 2017 22:06:52 -0800 Subject: [PATCH 01/11] Retry sending pings if they are delayed --- .../chttp2/transport/chttp2_transport.c | 14 +++++++++++--- .../ext/transport/chttp2/transport/internal.h | 2 ++ .../ext/transport/chttp2/transport/writing.c | 6 ++++++ test/core/end2end/tests/ping.c | 18 +++++++++++++----- 4 files changed, 32 insertions(+), 8 deletions(-) diff --git a/src/core/ext/transport/chttp2/transport/chttp2_transport.c b/src/core/ext/transport/chttp2/transport/chttp2_transport.c index da4c7dc7b23..96e46c29ca7 100644 --- a/src/core/ext/transport/chttp2/transport/chttp2_transport.c +++ b/src/core/ext/transport/chttp2/transport/chttp2_transport.c @@ -142,6 +142,8 @@ static void send_ping_locked(grpc_exec_ctx *exec_ctx, grpc_chttp2_transport *t, grpc_chttp2_ping_type ping_type, grpc_closure *on_initiate, grpc_closure *on_complete); +static void retry_initiate_ping_locked(grpc_exec_ctx *exec_ctx, void *tp, + grpc_error *error); #define DEFAULT_MIN_TIME_BETWEEN_PINGS_MS 0 #define DEFAULT_MAX_PINGS_BETWEEN_DATA 3 @@ -266,6 +268,8 @@ static void init_transport(grpc_exec_ctx *exec_ctx, grpc_chttp2_transport *t, grpc_closure_init(&t->destructive_reclaimer_locked, destructive_reclaimer_locked, t, grpc_combiner_scheduler(t->combiner, false)); + grpc_closure_init(&t->retry_initiate_ping_locked, retry_initiate_ping_locked, + t, grpc_combiner_scheduler(t->combiner, false)); grpc_closure_init(&t->start_bdp_ping_locked, start_bdp_ping_locked, t, grpc_combiner_scheduler(t->combiner, false)); grpc_closure_init(&t->finish_bdp_ping_locked, finish_bdp_ping_locked, t, @@ -1388,6 +1392,12 @@ static void send_ping_locked(grpc_exec_ctx *exec_ctx, grpc_chttp2_transport *t, } } +static void retry_initiate_ping_locked(grpc_exec_ctx *exec_ctx, void *tp, + grpc_error *error) { + grpc_chttp2_transport *t = tp; + grpc_chttp2_initiate_write(exec_ctx, t, false, "retry_send_ping"); +} + void grpc_chttp2_ack_ping(grpc_exec_ctx *exec_ctx, grpc_chttp2_transport *t, uint64_t id) { grpc_chttp2_ping_queue *pq = @@ -2114,9 +2124,7 @@ static void finish_keepalive_ping_locked(grpc_exec_ctx *exec_ctx, void *arg, grpc_timer_init( exec_ctx, &t->keepalive_ping_timer, gpr_time_add(gpr_now(GPR_CLOCK_MONOTONIC), t->keepalive_time), - grpc_closure_create(init_keepalive_ping_locked, t, - grpc_combiner_scheduler(t->combiner, false)), - gpr_now(GPR_CLOCK_MONOTONIC)); + &t->init_keepalive_ping_locked, gpr_now(GPR_CLOCK_MONOTONIC)); } } GRPC_CHTTP2_UNREF_TRANSPORT(exec_ctx, t, "keepalive ping end"); diff --git a/src/core/ext/transport/chttp2/transport/internal.h b/src/core/ext/transport/chttp2/transport/internal.h index d26812ad6be..a23aa60dbdb 100644 --- a/src/core/ext/transport/chttp2/transport/internal.h +++ b/src/core/ext/transport/chttp2/transport/internal.h @@ -102,6 +102,7 @@ typedef struct { typedef struct { gpr_timespec last_ping_sent_time; int pings_before_data_required; + grpc_timer delayed_ping_timer; } grpc_chttp2_repeated_ping_state; /* deframer state for the overall http2 stream of bytes */ @@ -308,6 +309,7 @@ struct grpc_chttp2_transport { grpc_chttp2_repeated_ping_policy ping_policy; grpc_chttp2_repeated_ping_state ping_state; uint64_t ping_ctr; /* unique id for pings */ + grpc_closure retry_initiate_ping_locked; /** ping acks */ size_t ping_ack_count; diff --git a/src/core/ext/transport/chttp2/transport/writing.c b/src/core/ext/transport/chttp2/transport/writing.c index 2b9d93cae7c..b9c2f15face 100644 --- a/src/core/ext/transport/chttp2/transport/writing.c +++ b/src/core/ext/transport/chttp2/transport/writing.c @@ -101,6 +101,12 @@ static void maybe_initiate_ping(grpc_exec_ctx *exec_ctx, "Ping delayed [%p]: not enough time elapsed since last ping", t->peer_string); } + + grpc_timer_init(exec_ctx, &t->ping_state.delayed_ping_timer, + gpr_time_add(t->ping_state.last_ping_sent_time, + t->ping_policy.min_time_between_pings), + &t->retry_initiate_ping_locked, + gpr_now(GPR_CLOCK_MONOTONIC)); return; } /* coalesce equivalent pings into this one */ diff --git a/test/core/end2end/tests/ping.c b/test/core/end2end/tests/ping.c index f5bfac2255c..082ac641f0b 100644 --- a/test/core/end2end/tests/ping.c +++ b/test/core/end2end/tests/ping.c @@ -41,9 +41,12 @@ #include "test/core/end2end/cq_verifier.h" +#define PING_NUM 5 + static void *tag(intptr_t t) { return (void *)t; } -static void test_ping(grpc_end2end_test_config config) { +static void test_ping(grpc_end2end_test_config config, + int min_time_between_pings_ms) { grpc_end2end_test_fixture f = config.create_fixture(NULL, NULL); cq_verifier *cqv = cq_verifier_create(f.cq); grpc_connectivity_state state = GRPC_CHANNEL_IDLE; @@ -51,7 +54,7 @@ static void test_ping(grpc_end2end_test_config config) { grpc_arg a[] = {{.type = GRPC_ARG_INTEGER, .key = GRPC_ARG_HTTP2_MIN_TIME_BETWEEN_PINGS_MS, - .value.integer = 0}, + .value.integer = min_time_between_pings_ms}, {.type = GRPC_ARG_INTEGER, .key = GRPC_ARG_HTTP2_MAX_PINGS_WITHOUT_DATA, .value.integer = 20}}; @@ -70,7 +73,11 @@ static void test_ping(grpc_end2end_test_config config) { READY is reached */ while (state != GRPC_CHANNEL_READY) { grpc_channel_watch_connectivity_state( - f.client, state, grpc_timeout_seconds_to_deadline(3), f.cq, tag(99)); + f.client, state, + gpr_time_add(grpc_timeout_seconds_to_deadline(3), + gpr_time_from_millis(min_time_between_pings_ms * PING_NUM, + GPR_TIMESPAN)), + f.cq, tag(99)); CQ_EXPECT_COMPLETION(cqv, tag(99), 1); cq_verify(cqv); state = grpc_channel_check_connectivity_state(f.client, 0); @@ -79,7 +86,7 @@ static void test_ping(grpc_end2end_test_config config) { state == GRPC_CHANNEL_TRANSIENT_FAILURE); } - for (i = 1; i <= 5; i++) { + for (i = 1; i <= PING_NUM; i++) { grpc_channel_ping(f.client, f.cq, tag(i), NULL); CQ_EXPECT_COMPLETION(cqv, tag(i), 1); cq_verify(cqv); @@ -102,7 +109,8 @@ static void test_ping(grpc_end2end_test_config config) { void ping(grpc_end2end_test_config config) { GPR_ASSERT(config.feature_mask & FEATURE_MASK_SUPPORTS_DELAYED_CONNECTION); - test_ping(config); + test_ping(config, 0); + test_ping(config, 100); } void ping_pre_init(void) {} From cbcdb4023f8e2fecaae3ec4abb21974fbe75024e Mon Sep 17 00:00:00 2001 From: Yuchen Zeng Date: Wed, 1 Mar 2017 01:42:18 -0800 Subject: [PATCH 02/11] Fix mac windows failures --- .../transport/chttp2/transport/chttp2_transport.c | 2 ++ src/core/ext/transport/chttp2/transport/internal.h | 1 + src/core/ext/transport/chttp2/transport/writing.c | 14 ++++++++------ 3 files changed, 11 insertions(+), 6 deletions(-) diff --git a/src/core/ext/transport/chttp2/transport/chttp2_transport.c b/src/core/ext/transport/chttp2/transport/chttp2_transport.c index 96e46c29ca7..024d9d649f8 100644 --- a/src/core/ext/transport/chttp2/transport/chttp2_transport.c +++ b/src/core/ext/transport/chttp2/transport/chttp2_transport.c @@ -477,6 +477,7 @@ static void init_transport(grpc_exec_ctx *exec_ctx, grpc_chttp2_transport *t, t->ping_state.pings_before_data_required = t->ping_policy.max_pings_without_data; + t->ping_state.is_delayed_ping_timer_set = false; /** Start client-side keepalive pings */ if (t->is_client) { @@ -1395,6 +1396,7 @@ static void send_ping_locked(grpc_exec_ctx *exec_ctx, grpc_chttp2_transport *t, static void retry_initiate_ping_locked(grpc_exec_ctx *exec_ctx, void *tp, grpc_error *error) { grpc_chttp2_transport *t = tp; + t->ping_state.is_delayed_ping_timer_set = false; grpc_chttp2_initiate_write(exec_ctx, t, false, "retry_send_ping"); } diff --git a/src/core/ext/transport/chttp2/transport/internal.h b/src/core/ext/transport/chttp2/transport/internal.h index a23aa60dbdb..bfbfd5fd97c 100644 --- a/src/core/ext/transport/chttp2/transport/internal.h +++ b/src/core/ext/transport/chttp2/transport/internal.h @@ -103,6 +103,7 @@ typedef struct { gpr_timespec last_ping_sent_time; int pings_before_data_required; grpc_timer delayed_ping_timer; + bool is_delayed_ping_timer_set; } grpc_chttp2_repeated_ping_state; /* deframer state for the overall http2 stream of bytes */ diff --git a/src/core/ext/transport/chttp2/transport/writing.c b/src/core/ext/transport/chttp2/transport/writing.c index b9c2f15face..0869056f56d 100644 --- a/src/core/ext/transport/chttp2/transport/writing.c +++ b/src/core/ext/transport/chttp2/transport/writing.c @@ -101,12 +101,14 @@ static void maybe_initiate_ping(grpc_exec_ctx *exec_ctx, "Ping delayed [%p]: not enough time elapsed since last ping", t->peer_string); } - - grpc_timer_init(exec_ctx, &t->ping_state.delayed_ping_timer, - gpr_time_add(t->ping_state.last_ping_sent_time, - t->ping_policy.min_time_between_pings), - &t->retry_initiate_ping_locked, - gpr_now(GPR_CLOCK_MONOTONIC)); + if (!t->ping_state.is_delayed_ping_timer_set) { + t->ping_state.is_delayed_ping_timer_set = true; + grpc_timer_init(exec_ctx, &t->ping_state.delayed_ping_timer, + gpr_time_add(t->ping_state.last_ping_sent_time, + t->ping_policy.min_time_between_pings), + &t->retry_initiate_ping_locked, + gpr_now(GPR_CLOCK_MONOTONIC)); + } return; } /* coalesce equivalent pings into this one */ From 9f00073f3cf61b5d12814d2290da7a344b6e0068 Mon Sep 17 00:00:00 2001 From: thinkerou Date: Sun, 26 Mar 2017 00:52:56 +0800 Subject: [PATCH 03/11] fix markdown render error --- src/compiler/README.md | 2 +- src/core/README.md | 2 +- src/core/ext/census/gen/README.md | 2 +- src/cpp/README.md | 16 ++++++++-------- src/php/README.md | 2 +- 5 files changed, 12 insertions(+), 12 deletions(-) diff --git a/src/compiler/README.md b/src/compiler/README.md index a2f49b3cd53..d5684af7ff2 100644 --- a/src/compiler/README.md +++ b/src/compiler/README.md @@ -1,4 +1,4 @@ -#Overview +# Overview This directory contains source code for gRPC protocol buffer compiler (*protoc*) plugins. Along with `protoc`, these plugins are used to generate gRPC client and server stubs from `.proto` files. diff --git a/src/core/README.md b/src/core/README.md index 44c6f247725..130d2652b39 100644 --- a/src/core/README.md +++ b/src/core/README.md @@ -1,4 +1,4 @@ -#Overview +# Overview This directory contains source code for C library (a.k.a the *gRPC C core*) that provides all gRPC's core functionality through a low level API. Libraries in other languages in this repository (C++, Ruby, Python, PHP, NodeJS, Objective-C) are layered on top of this library. diff --git a/src/core/ext/census/gen/README.md b/src/core/ext/census/gen/README.md index fdbac1084cd..d4612bc7c85 100644 --- a/src/core/ext/census/gen/README.md +++ b/src/core/ext/census/gen/README.md @@ -1,6 +1,6 @@ Files generated for use by Census stats and trace recording subsystem. -#Files +# Files * census.pb.{h,c} - Generated from src/core/ext/census/census.proto, using the script `tools/codegen/core/gen_nano_proto.sh src/proto/census/census.proto $PWD/src/core/ext/census/gen src/core/ext/census/gen` diff --git a/src/cpp/README.md b/src/cpp/README.md index d9b521317a6..e9ef489a7ca 100644 --- a/src/cpp/README.md +++ b/src/cpp/README.md @@ -1,17 +1,17 @@ -#Overview +# Overview This directory contains source code for C++ implementation of gRPC. -#Pre-requisites +# Pre-requisites -##Linux +## Linux ```sh $ [sudo] apt-get install build-essential autoconf libtool ``` -##Mac OSX +## Mac OSX For a Mac system, git is not available by default. You will first need to install Xcode from the Mac AppStore and then run the following command from a @@ -21,7 +21,7 @@ terminal: $ [sudo] xcode-select --install ``` -##Protoc +## Protoc By default gRPC uses [protocol buffers](https://github.com/google/protobuf), you will need the `protoc` compiler to generate stub server and client code. @@ -39,12 +39,12 @@ $ sudo make install # 'make' should have been run by core grpc Alternatively, you can download `protoc` binaries from [the protocol buffers Github repository](https://github.com/google/protobuf/releases). -#Installation +# Installation Currently to install gRPC for C++, you need to build from source as described below. -#Build from Source +# Build from Source ```sh $ git clone -b $(curl -L http://grpc.io/release) https://github.com/grpc/grpc @@ -54,7 +54,7 @@ below. $ [sudo] make install ``` -#Documentation +# Documentation You can find out how to build and run our simplest gRPC C++ example in our [C++ quick start](../../examples/cpp). diff --git a/src/php/README.md b/src/php/README.md index f08541f16cf..f9f93ba8159 100644 --- a/src/php/README.md +++ b/src/php/README.md @@ -1,5 +1,5 @@ -#Overview +# Overview This directory contains source code for PHP implementation of gRPC layered on shared C library. From 34d21ceadcc7e83f15f3bdcfa6955940c6e4d30a Mon Sep 17 00:00:00 2001 From: thinkerou Date: Sun, 26 Mar 2017 01:07:27 +0800 Subject: [PATCH 04/11] fix php style --- src/php/lib/Grpc/AbstractCall.php | 2 +- src/php/tests/unit_tests/ServerTest.php | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/src/php/lib/Grpc/AbstractCall.php b/src/php/lib/Grpc/AbstractCall.php index 4833fdc7b6f..a59bfa3ba38 100644 --- a/src/php/lib/Grpc/AbstractCall.php +++ b/src/php/lib/Grpc/AbstractCall.php @@ -131,7 +131,7 @@ abstract class AbstractCall // Proto3 implementation if (method_exists($data, 'encode')) { return $data->encode(); - } else if (method_exists($data, 'serializeToString')) { + } elseif (method_exists($data, 'serializeToString')) { return $data->serializeToString(); } diff --git a/src/php/tests/unit_tests/ServerTest.php b/src/php/tests/unit_tests/ServerTest.php index 5f40202f182..3e7c01f20e2 100644 --- a/src/php/tests/unit_tests/ServerTest.php +++ b/src/php/tests/unit_tests/ServerTest.php @@ -69,7 +69,7 @@ class ServerTest extends PHPUnit_Framework_TestCase $this->server = new Grpc\Server(); $port = $this->server->addHttp2Port('0.0.0.0:0'); $this->server->start(); - $channel = new Grpc\Channel('localhost:' . $port, + $channel = new Grpc\Channel('localhost:'.$port, ['credentials' => Grpc\ChannelCredentials::createInsecure()]); $deadline = Grpc\Timeval::infFuture(); From 3d43da7b4b8118d52feae7bea217da1a77c77416 Mon Sep 17 00:00:00 2001 From: Yuchen Zeng Date: Mon, 27 Mar 2017 11:33:21 -0700 Subject: [PATCH 05/11] Change keepalive arguments, add grpc_set_disable_ping_ack --- include/grpc/impl/codegen/grpc_types.h | 8 +-- .../chttp2/transport/chttp2_transport.c | 58 ++++++++++++++----- .../transport/chttp2/transport/frame_ping.c | 10 +++- .../transport/chttp2/transport/frame_ping.h | 3 + .../ext/transport/chttp2/transport/internal.h | 4 ++ test/core/end2end/tests/keepalive_timeout.c | 20 ++++--- 6 files changed, 76 insertions(+), 27 deletions(-) diff --git a/include/grpc/impl/codegen/grpc_types.h b/include/grpc/impl/codegen/grpc_types.h index 887c176f1a4..7e0fcdc6213 100644 --- a/include/grpc/impl/codegen/grpc_types.h +++ b/include/grpc/impl/codegen/grpc_types.h @@ -198,14 +198,14 @@ typedef struct { #define GRPC_ARG_HTTP2_WRITE_BUFFER_SIZE "grpc.http2.write_buffer_size" /** After a duration of this time the client pings the server to see if the transport is still alive. Int valued, seconds. */ -#define GRPC_ARG_HTTP2_KEEPALIVE_TIME "grpc.http2.keepalive_time" +#define GRPC_ARG_KEEPALIVE_TIME_S "grpc.keepalive_time" /** After waiting for a duration of this time, if the client does not receive the ping ack, it will close the transport. Int valued, seconds. */ -#define GRPC_ARG_HTTP2_KEEPALIVE_TIMEOUT "grpc.http2.keepalive_timeout" +#define GRPC_ARG_KEEPALIVE_TIMEOUT_S "grpc.keepalive_timeout" /** Is it permissible to send keepalive pings without any outstanding streams. Int valued, 0(false)/1(true). */ -#define GRPC_ARG_HTTP2_KEEPALIVE_PERMIT_WITHOUT_CALLS \ - "grpc.http2.keepalive_permit_without_calls" +#define GRPC_ARG_KEEPALIVE_PERMIT_WITHOUT_CALLS \ + "grpc.keepalive_permit_without_calls" /** Default authority to pass if none specified on call construction. A string. * */ #define GRPC_ARG_DEFAULT_AUTHORITY "grpc.default_authority" diff --git a/src/core/ext/transport/chttp2/transport/chttp2_transport.c b/src/core/ext/transport/chttp2/transport/chttp2_transport.c index 8676a3752e8..bd8edb82f4f 100644 --- a/src/core/ext/transport/chttp2/transport/chttp2_transport.c +++ b/src/core/ext/transport/chttp2/transport/chttp2_transport.c @@ -69,10 +69,15 @@ #define MAX_WRITE_BUFFER_SIZE (64 * 1024 * 1024) #define DEFAULT_MAX_HEADER_LIST_SIZE (16 * 1024) -#define DEFAULT_KEEPALIVE_TIME_SECOND INT_MAX -#define DEFAULT_KEEPALIVE_TIMEOUT_SECOND 20 +#define DEFAULT_KEEPALIVE_TIME_S INT_MAX +#define DEFAULT_KEEPALIVE_TIMEOUT_S 20 #define DEFAULT_KEEPALIVE_PERMIT_WITHOUT_CALLS false +static int g_default_keepalive_time_s = DEFAULT_KEEPALIVE_TIME_S; +static int g_default_keepalive_timeout_s = DEFAULT_KEEPALIVE_TIMEOUT_S; +static bool g_default_keepalive_permit_without_calls = + DEFAULT_KEEPALIVE_PERMIT_WITHOUT_CALLS; + #define MAX_CLIENT_STREAM_ID 0x7fffffffu int grpc_http_trace = 0; int grpc_flowctl_trace = 0; @@ -345,15 +350,14 @@ static void init_transport(grpc_exec_ctx *exec_ctx, grpc_chttp2_transport *t, /* client-side keepalive setting */ t->keepalive_time = - DEFAULT_KEEPALIVE_TIME_SECOND == INT_MAX + g_default_keepalive_time_s == INT_MAX ? gpr_inf_future(GPR_TIMESPAN) - : gpr_time_from_seconds(DEFAULT_KEEPALIVE_TIME_SECOND, GPR_TIMESPAN); + : gpr_time_from_seconds(g_default_keepalive_time_s, GPR_TIMESPAN); t->keepalive_timeout = - DEFAULT_KEEPALIVE_TIMEOUT_SECOND == INT_MAX + g_default_keepalive_timeout_s == INT_MAX ? gpr_inf_future(GPR_TIMESPAN) - : gpr_time_from_seconds(DEFAULT_KEEPALIVE_TIMEOUT_SECOND, - GPR_TIMESPAN); - t->keepalive_permit_without_calls = DEFAULT_KEEPALIVE_PERMIT_WITHOUT_CALLS; + : gpr_time_from_seconds(g_default_keepalive_timeout_s, GPR_TIMESPAN); + t->keepalive_permit_without_calls = g_default_keepalive_permit_without_calls; if (channel_args) { for (i = 0; i < channel_args->num_args; i++) { @@ -402,25 +406,24 @@ static void init_transport(grpc_exec_ctx *exec_ctx, grpc_chttp2_transport *t, strcmp(channel_args->args[i].key, GRPC_ARG_HTTP2_BDP_PROBE)) { t->enable_bdp_probe = grpc_channel_arg_get_integer( &channel_args->args[i], (grpc_integer_options){1, 0, 1}); - } else if (0 == strcmp(channel_args->args[i].key, - GRPC_ARG_HTTP2_KEEPALIVE_TIME)) { + } else if (0 == + strcmp(channel_args->args[i].key, GRPC_ARG_KEEPALIVE_TIME_S)) { const int value = grpc_channel_arg_get_integer( &channel_args->args[i], - (grpc_integer_options){DEFAULT_KEEPALIVE_TIME_SECOND, 1, INT_MAX}); + (grpc_integer_options){g_default_keepalive_time_s, 1, INT_MAX}); t->keepalive_time = value == INT_MAX ? gpr_inf_future(GPR_TIMESPAN) : gpr_time_from_seconds(value, GPR_TIMESPAN); } else if (0 == strcmp(channel_args->args[i].key, - GRPC_ARG_HTTP2_KEEPALIVE_TIMEOUT)) { + GRPC_ARG_KEEPALIVE_TIMEOUT_S)) { const int value = grpc_channel_arg_get_integer( &channel_args->args[i], - (grpc_integer_options){DEFAULT_KEEPALIVE_TIMEOUT_SECOND, 0, - INT_MAX}); + (grpc_integer_options){g_default_keepalive_timeout_s, 0, INT_MAX}); t->keepalive_timeout = value == INT_MAX ? gpr_inf_future(GPR_TIMESPAN) : gpr_time_from_seconds(value, GPR_TIMESPAN); } else if (0 == strcmp(channel_args->args[i].key, - GRPC_ARG_HTTP2_KEEPALIVE_PERMIT_WITHOUT_CALLS)) { + GRPC_ARG_KEEPALIVE_PERMIT_WITHOUT_CALLS)) { t->keepalive_permit_without_calls = (uint32_t)grpc_channel_arg_get_integer( &channel_args->args[i], (grpc_integer_options){0, 0, 1}); @@ -2103,6 +2106,31 @@ static void finish_bdp_ping_locked(grpc_exec_ctx *exec_ctx, void *tp, GRPC_CHTTP2_UNREF_TRANSPORT(exec_ctx, t, "bdp_ping"); } +void grpc_chttp2_config_default_keepalive_args(grpc_channel_args *args) { + size_t i; + if (args) { + for (i = 0; i < args->num_args; i++) { + if (0 == strcmp(args->args[i].key, GRPC_ARG_KEEPALIVE_TIME_S)) { + g_default_keepalive_time_s = grpc_channel_arg_get_integer( + &args->args[i], + (grpc_integer_options){g_default_keepalive_time_s, 1, INT_MAX}); + } else if (0 == strcmp(args->args[i].key, GRPC_ARG_KEEPALIVE_TIMEOUT_S)) { + g_default_keepalive_timeout_s = grpc_channel_arg_get_integer( + &args->args[i], + (grpc_integer_options){g_default_keepalive_timeout_s, 0, INT_MAX}); + ; + } else if (0 == strcmp(args->args[i].key, + GRPC_ARG_KEEPALIVE_PERMIT_WITHOUT_CALLS)) { + g_default_keepalive_permit_without_calls = + (uint32_t)grpc_channel_arg_get_integer( + &args->args[i], + (grpc_integer_options){g_default_keepalive_permit_without_calls, + 0, 1}); + } + } + } +} + static void init_keepalive_ping_locked(grpc_exec_ctx *exec_ctx, void *arg, grpc_error *error) { grpc_chttp2_transport *t = arg; diff --git a/src/core/ext/transport/chttp2/transport/frame_ping.c b/src/core/ext/transport/chttp2/transport/frame_ping.c index de8462a17ea..ca175ea4d7c 100644 --- a/src/core/ext/transport/chttp2/transport/frame_ping.c +++ b/src/core/ext/transport/chttp2/transport/frame_ping.c @@ -40,6 +40,8 @@ #include #include +static bool g_disable_ping_ack = false; + grpc_slice grpc_chttp2_ping_create(uint8_t ack, uint64_t opaque_8bytes) { grpc_slice slice = grpc_slice_malloc(9 + 8); uint8_t *p = GRPC_SLICE_START_PTR(slice); @@ -99,7 +101,9 @@ grpc_error *grpc_chttp2_ping_parser_parse(grpc_exec_ctx *exec_ctx, void *parser, if (p->byte == 8) { GPR_ASSERT(is_last); if (p->is_ack) { - grpc_chttp2_ack_ping(exec_ctx, t, p->opaque_8bytes); + if (!g_disable_ping_ack) { + grpc_chttp2_ack_ping(exec_ctx, t, p->opaque_8bytes); + } } else { if (t->ping_ack_count == t->ping_ack_capacity) { t->ping_ack_capacity = GPR_MAX(t->ping_ack_capacity * 3 / 2, 3); @@ -113,3 +117,7 @@ grpc_error *grpc_chttp2_ping_parser_parse(grpc_exec_ctx *exec_ctx, void *parser, return GRPC_ERROR_NONE; } + +void grpc_set_disable_ping_ack(bool disable_ping_ack) { + g_disable_ping_ack = disable_ping_ack; +} diff --git a/src/core/ext/transport/chttp2/transport/frame_ping.h b/src/core/ext/transport/chttp2/transport/frame_ping.h index ef642465d7e..01983d2b127 100644 --- a/src/core/ext/transport/chttp2/transport/frame_ping.h +++ b/src/core/ext/transport/chttp2/transport/frame_ping.h @@ -53,4 +53,7 @@ grpc_error *grpc_chttp2_ping_parser_parse(grpc_exec_ctx *exec_ctx, void *parser, grpc_chttp2_stream *s, grpc_slice slice, int is_last); +/* Test-only function for disabling ping ack */ +void grpc_set_disable_ping_ack(bool disable_ping_ack); + #endif /* GRPC_CORE_EXT_TRANSPORT_CHTTP2_TRANSPORT_FRAME_PING_H */ diff --git a/src/core/ext/transport/chttp2/transport/internal.h b/src/core/ext/transport/chttp2/transport/internal.h index 3c56c215991..891ae2f2812 100644 --- a/src/core/ext/transport/chttp2/transport/internal.h +++ b/src/core/ext/transport/chttp2/transport/internal.h @@ -827,4 +827,8 @@ void grpc_chttp2_fail_pending_writes(grpc_exec_ctx *exec_ctx, uint32_t grpc_chttp2_target_incoming_window(grpc_chttp2_transport *t); +/** Set the default keepalive configurations, must only be called at + initialization */ +void grpc_chttp2_config_default_keepalive_args(grpc_channel_args *args); + #endif /* GRPC_CORE_EXT_TRANSPORT_CHTTP2_TRANSPORT_INTERNAL_H */ diff --git a/test/core/end2end/tests/keepalive_timeout.c b/test/core/end2end/tests/keepalive_timeout.c index 4296be36190..9e6682ed052 100644 --- a/test/core/end2end/tests/keepalive_timeout.c +++ b/test/core/end2end/tests/keepalive_timeout.c @@ -41,6 +41,7 @@ #include #include #include +#include "src/core/ext/transport/chttp2/transport/frame_ping.h" #include "src/core/lib/channel/channel_args.h" #include "src/core/lib/iomgr/exec_ctx.h" #include "src/core/lib/support/env.h" @@ -109,13 +110,15 @@ static void test_keepalive_timeout(grpc_end2end_test_config config) { grpc_raw_byte_buffer_create(&response_payload_slice, 1); gpr_timespec deadline = five_seconds_time(); - grpc_arg keepalive_args[2]; - keepalive_args[0].type = GRPC_ARG_INTEGER; - keepalive_args[0].key = GRPC_ARG_HTTP2_KEEPALIVE_TIME; - keepalive_args[0].value.integer = 2; - keepalive_args[1].type = GRPC_ARG_INTEGER; - keepalive_args[1].key = GRPC_ARG_HTTP2_KEEPALIVE_TIMEOUT; - keepalive_args[1].value.integer = 0; + grpc_arg keepalive_args[] = {{.type = GRPC_ARG_INTEGER, + .key = GRPC_ARG_KEEPALIVE_TIME_S, + .value.integer = 2}, + {.type = GRPC_ARG_INTEGER, + .key = GRPC_ARG_KEEPALIVE_TIMEOUT_S, + .value.integer = 0}, + {.type = GRPC_ARG_INTEGER, + .key = GRPC_ARG_HTTP2_BDP_PROBE, + .value.integer = 1}}; grpc_channel_args *client_args = NULL; client_args = grpc_channel_args_copy_and_add(client_args, keepalive_args, 2); @@ -134,6 +137,9 @@ static void test_keepalive_timeout(grpc_end2end_test_config config) { grpc_call_error error; grpc_slice details; + /* Disable ping ack to trigger the keepalive timeout */ + grpc_set_disable_ping_ack(true); + c = grpc_channel_create_call( f.client, NULL, GRPC_PROPAGATE_DEFAULTS, f.cq, grpc_slice_from_static_string("/foo"), From 44264d59730d3b7f575e6c98c97cdf6e3fdea9fd Mon Sep 17 00:00:00 2001 From: Yuchen Zeng Date: Mon, 27 Mar 2017 16:32:15 -0700 Subject: [PATCH 06/11] Add client_ prefix for keepalive args --- include/grpc/impl/codegen/grpc_types.h | 4 +- .../chttp2/transport/chttp2_transport.c | 47 +++++++++++-------- test/core/end2end/tests/keepalive_timeout.c | 4 +- 3 files changed, 31 insertions(+), 24 deletions(-) diff --git a/include/grpc/impl/codegen/grpc_types.h b/include/grpc/impl/codegen/grpc_types.h index 7e0fcdc6213..f4c6f7d211b 100644 --- a/include/grpc/impl/codegen/grpc_types.h +++ b/include/grpc/impl/codegen/grpc_types.h @@ -198,10 +198,10 @@ typedef struct { #define GRPC_ARG_HTTP2_WRITE_BUFFER_SIZE "grpc.http2.write_buffer_size" /** After a duration of this time the client pings the server to see if the transport is still alive. Int valued, seconds. */ -#define GRPC_ARG_KEEPALIVE_TIME_S "grpc.keepalive_time" +#define GRPC_ARG_CLIENT_KEEPALIVE_TIME_S "grpc.client_keepalive_time" /** After waiting for a duration of this time, if the client does not receive the ping ack, it will close the transport. Int valued, seconds. */ -#define GRPC_ARG_KEEPALIVE_TIMEOUT_S "grpc.keepalive_timeout" +#define GRPC_ARG_CLIENT_KEEPALIVE_TIMEOUT_S "grpc.client_keepalive_timeout" /** Is it permissible to send keepalive pings without any outstanding streams. Int valued, 0(false)/1(true). */ #define GRPC_ARG_KEEPALIVE_PERMIT_WITHOUT_CALLS \ diff --git a/src/core/ext/transport/chttp2/transport/chttp2_transport.c b/src/core/ext/transport/chttp2/transport/chttp2_transport.c index bd8edb82f4f..7a68e6f163e 100644 --- a/src/core/ext/transport/chttp2/transport/chttp2_transport.c +++ b/src/core/ext/transport/chttp2/transport/chttp2_transport.c @@ -69,12 +69,13 @@ #define MAX_WRITE_BUFFER_SIZE (64 * 1024 * 1024) #define DEFAULT_MAX_HEADER_LIST_SIZE (16 * 1024) -#define DEFAULT_KEEPALIVE_TIME_S INT_MAX -#define DEFAULT_KEEPALIVE_TIMEOUT_S 20 +#define DEFAULT_CLIENT_KEEPALIVE_TIME_S INT_MAX +#define DEFAULT_CLIENT_KEEPALIVE_TIMEOUT_S 20 #define DEFAULT_KEEPALIVE_PERMIT_WITHOUT_CALLS false -static int g_default_keepalive_time_s = DEFAULT_KEEPALIVE_TIME_S; -static int g_default_keepalive_timeout_s = DEFAULT_KEEPALIVE_TIMEOUT_S; +static int g_default_client_keepalive_time_s = DEFAULT_CLIENT_KEEPALIVE_TIME_S; +static int g_default_client_keepalive_timeout_s = + DEFAULT_CLIENT_KEEPALIVE_TIMEOUT_S; static bool g_default_keepalive_permit_without_calls = DEFAULT_KEEPALIVE_PERMIT_WITHOUT_CALLS; @@ -350,13 +351,15 @@ static void init_transport(grpc_exec_ctx *exec_ctx, grpc_chttp2_transport *t, /* client-side keepalive setting */ t->keepalive_time = - g_default_keepalive_time_s == INT_MAX + g_default_client_keepalive_time_s == INT_MAX ? gpr_inf_future(GPR_TIMESPAN) - : gpr_time_from_seconds(g_default_keepalive_time_s, GPR_TIMESPAN); + : gpr_time_from_seconds(g_default_client_keepalive_time_s, + GPR_TIMESPAN); t->keepalive_timeout = - g_default_keepalive_timeout_s == INT_MAX + g_default_client_keepalive_timeout_s == INT_MAX ? gpr_inf_future(GPR_TIMESPAN) - : gpr_time_from_seconds(g_default_keepalive_timeout_s, GPR_TIMESPAN); + : gpr_time_from_seconds(g_default_client_keepalive_timeout_s, + GPR_TIMESPAN); t->keepalive_permit_without_calls = g_default_keepalive_permit_without_calls; if (channel_args) { @@ -406,19 +409,21 @@ static void init_transport(grpc_exec_ctx *exec_ctx, grpc_chttp2_transport *t, strcmp(channel_args->args[i].key, GRPC_ARG_HTTP2_BDP_PROBE)) { t->enable_bdp_probe = grpc_channel_arg_get_integer( &channel_args->args[i], (grpc_integer_options){1, 0, 1}); - } else if (0 == - strcmp(channel_args->args[i].key, GRPC_ARG_KEEPALIVE_TIME_S)) { + } else if (0 == strcmp(channel_args->args[i].key, + GRPC_ARG_CLIENT_KEEPALIVE_TIME_S)) { const int value = grpc_channel_arg_get_integer( &channel_args->args[i], - (grpc_integer_options){g_default_keepalive_time_s, 1, INT_MAX}); + (grpc_integer_options){g_default_client_keepalive_time_s, 1, + INT_MAX}); t->keepalive_time = value == INT_MAX ? gpr_inf_future(GPR_TIMESPAN) : gpr_time_from_seconds(value, GPR_TIMESPAN); } else if (0 == strcmp(channel_args->args[i].key, - GRPC_ARG_KEEPALIVE_TIMEOUT_S)) { + GRPC_ARG_CLIENT_KEEPALIVE_TIMEOUT_S)) { const int value = grpc_channel_arg_get_integer( &channel_args->args[i], - (grpc_integer_options){g_default_keepalive_timeout_s, 0, INT_MAX}); + (grpc_integer_options){g_default_client_keepalive_timeout_s, 0, + INT_MAX}); t->keepalive_timeout = value == INT_MAX ? gpr_inf_future(GPR_TIMESPAN) : gpr_time_from_seconds(value, GPR_TIMESPAN); @@ -2110,14 +2115,16 @@ void grpc_chttp2_config_default_keepalive_args(grpc_channel_args *args) { size_t i; if (args) { for (i = 0; i < args->num_args; i++) { - if (0 == strcmp(args->args[i].key, GRPC_ARG_KEEPALIVE_TIME_S)) { - g_default_keepalive_time_s = grpc_channel_arg_get_integer( - &args->args[i], - (grpc_integer_options){g_default_keepalive_time_s, 1, INT_MAX}); - } else if (0 == strcmp(args->args[i].key, GRPC_ARG_KEEPALIVE_TIMEOUT_S)) { - g_default_keepalive_timeout_s = grpc_channel_arg_get_integer( + if (0 == strcmp(args->args[i].key, GRPC_ARG_CLIENT_KEEPALIVE_TIME_S)) { + g_default_client_keepalive_time_s = grpc_channel_arg_get_integer( + &args->args[i], (grpc_integer_options){ + g_default_client_keepalive_time_s, 1, INT_MAX}); + } else if (0 == strcmp(args->args[i].key, + GRPC_ARG_CLIENT_KEEPALIVE_TIMEOUT_S)) { + g_default_client_keepalive_timeout_s = grpc_channel_arg_get_integer( &args->args[i], - (grpc_integer_options){g_default_keepalive_timeout_s, 0, INT_MAX}); + (grpc_integer_options){g_default_client_keepalive_timeout_s, 0, + INT_MAX}); ; } else if (0 == strcmp(args->args[i].key, GRPC_ARG_KEEPALIVE_PERMIT_WITHOUT_CALLS)) { diff --git a/test/core/end2end/tests/keepalive_timeout.c b/test/core/end2end/tests/keepalive_timeout.c index 9e6682ed052..44b6e12abc7 100644 --- a/test/core/end2end/tests/keepalive_timeout.c +++ b/test/core/end2end/tests/keepalive_timeout.c @@ -111,10 +111,10 @@ static void test_keepalive_timeout(grpc_end2end_test_config config) { gpr_timespec deadline = five_seconds_time(); grpc_arg keepalive_args[] = {{.type = GRPC_ARG_INTEGER, - .key = GRPC_ARG_KEEPALIVE_TIME_S, + .key = GRPC_ARG_CLIENT_KEEPALIVE_TIME_S, .value.integer = 2}, {.type = GRPC_ARG_INTEGER, - .key = GRPC_ARG_KEEPALIVE_TIMEOUT_S, + .key = GRPC_ARG_CLIENT_KEEPALIVE_TIMEOUT_S, .value.integer = 0}, {.type = GRPC_ARG_INTEGER, .key = GRPC_ARG_HTTP2_BDP_PROBE, From 7cd4f6890bec05ec3233724a10a5bab29c14e6ad Mon Sep 17 00:00:00 2001 From: ncteisen Date: Mon, 27 Mar 2017 19:15:47 -0700 Subject: [PATCH 07/11] Add fuzzer bug --- ...h-59a56fa18034a104fb9f16cd58071b6ff93b8756 | Bin 0 -> 268 bytes tools/run_tests/generated/tests.json | 23 ++++++++++++++++++ 2 files changed, 23 insertions(+) create mode 100644 test/core/end2end/fuzzers/api_fuzzer_corpus/crash-59a56fa18034a104fb9f16cd58071b6ff93b8756 diff --git a/test/core/end2end/fuzzers/api_fuzzer_corpus/crash-59a56fa18034a104fb9f16cd58071b6ff93b8756 b/test/core/end2end/fuzzers/api_fuzzer_corpus/crash-59a56fa18034a104fb9f16cd58071b6ff93b8756 new file mode 100644 index 0000000000000000000000000000000000000000..1460bc9fbf7e1b8599f2bceb0de058c9c5a36789 GIT binary patch literal 268 zcmWekEXZVFVqz=j(@f>)C}Jv3Ehe7o9OeOqlQR Date: Mon, 27 Mar 2017 18:56:12 -0700 Subject: [PATCH 08/11] Fix formatting issues, move g_disable_ping_ack check to the PING responder --- .../chttp2/transport/chttp2_transport.c | 1 - .../transport/chttp2/transport/frame_ping.c | 18 +++++++++--------- 2 files changed, 9 insertions(+), 10 deletions(-) diff --git a/src/core/ext/transport/chttp2/transport/chttp2_transport.c b/src/core/ext/transport/chttp2/transport/chttp2_transport.c index 7a68e6f163e..6830e59f007 100644 --- a/src/core/ext/transport/chttp2/transport/chttp2_transport.c +++ b/src/core/ext/transport/chttp2/transport/chttp2_transport.c @@ -2125,7 +2125,6 @@ void grpc_chttp2_config_default_keepalive_args(grpc_channel_args *args) { &args->args[i], (grpc_integer_options){g_default_client_keepalive_timeout_s, 0, INT_MAX}); - ; } else if (0 == strcmp(args->args[i].key, GRPC_ARG_KEEPALIVE_PERMIT_WITHOUT_CALLS)) { g_default_keepalive_permit_without_calls = diff --git a/src/core/ext/transport/chttp2/transport/frame_ping.c b/src/core/ext/transport/chttp2/transport/frame_ping.c index ca175ea4d7c..46dafdb62f6 100644 --- a/src/core/ext/transport/chttp2/transport/frame_ping.c +++ b/src/core/ext/transport/chttp2/transport/frame_ping.c @@ -101,17 +101,17 @@ grpc_error *grpc_chttp2_ping_parser_parse(grpc_exec_ctx *exec_ctx, void *parser, if (p->byte == 8) { GPR_ASSERT(is_last); if (p->is_ack) { - if (!g_disable_ping_ack) { - grpc_chttp2_ack_ping(exec_ctx, t, p->opaque_8bytes); - } + grpc_chttp2_ack_ping(exec_ctx, t, p->opaque_8bytes); } else { - if (t->ping_ack_count == t->ping_ack_capacity) { - t->ping_ack_capacity = GPR_MAX(t->ping_ack_capacity * 3 / 2, 3); - t->ping_acks = gpr_realloc( - t->ping_acks, t->ping_ack_capacity * sizeof(*t->ping_acks)); + if (!g_disable_ping_ack) { + if (t->ping_ack_count == t->ping_ack_capacity) { + t->ping_ack_capacity = GPR_MAX(t->ping_ack_capacity * 3 / 2, 3); + t->ping_acks = gpr_realloc( + t->ping_acks, t->ping_ack_capacity * sizeof(*t->ping_acks)); + } + t->ping_acks[t->ping_ack_count++] = p->opaque_8bytes; + grpc_chttp2_initiate_write(exec_ctx, t, false, "ping response"); } - t->ping_acks[t->ping_ack_count++] = p->opaque_8bytes; - grpc_chttp2_initiate_write(exec_ctx, t, false, "ping response"); } } From fdd908b01a35346cf252c43a1281a42b8d7c241c Mon Sep 17 00:00:00 2001 From: yang-g Date: Tue, 28 Mar 2017 09:49:54 -0700 Subject: [PATCH 09/11] Clamp memory usage estimate --- src/core/lib/iomgr/resource_quota.c | 14 +++-- ...9fd9efe2844ee61555ac08e4f88afd8901cc2dd53a | Bin 0 -> 229 bytes test/core/iomgr/resource_quota_test.c | 52 ++++++++++++++++++ tools/run_tests/generated/tests.json | 23 ++++++++ 4 files changed, 85 insertions(+), 4 deletions(-) create mode 100644 test/core/end2end/fuzzers/api_fuzzer_corpus/poc-c726ee220e980ed6ad17809fd9efe2844ee61555ac08e4f88afd8901cc2dd53a diff --git a/src/core/lib/iomgr/resource_quota.c b/src/core/lib/iomgr/resource_quota.c index 511ffdcdf13..8dcd80d0011 100644 --- a/src/core/lib/iomgr/resource_quota.c +++ b/src/core/lib/iomgr/resource_quota.c @@ -279,11 +279,17 @@ static void rq_step_sched(grpc_exec_ctx *exec_ctx, /* update the atomically available resource estimate - use no barriers since timeliness of delivery really doesn't matter much */ static void rq_update_estimate(grpc_resource_quota *resource_quota) { + gpr_atm memory_usage_estimation = MEMORY_USAGE_ESTIMATION_MAX; + if (resource_quota->size != 0) { + memory_usage_estimation = + GPR_CLAMP((gpr_atm)((1.0 - + ((double)resource_quota->free_pool) / + ((double)resource_quota->size)) * + MEMORY_USAGE_ESTIMATION_MAX), + 0, MEMORY_USAGE_ESTIMATION_MAX); + } gpr_atm_no_barrier_store(&resource_quota->memory_usage_estimation, - (gpr_atm)((1.0 - - ((double)resource_quota->free_pool) / - ((double)resource_quota->size)) * - MEMORY_USAGE_ESTIMATION_MAX)); + memory_usage_estimation); } /* returns true if all allocations are completed */ diff --git a/test/core/end2end/fuzzers/api_fuzzer_corpus/poc-c726ee220e980ed6ad17809fd9efe2844ee61555ac08e4f88afd8901cc2dd53a b/test/core/end2end/fuzzers/api_fuzzer_corpus/poc-c726ee220e980ed6ad17809fd9efe2844ee61555ac08e4f88afd8901cc2dd53a new file mode 100644 index 0000000000000000000000000000000000000000..01428693cf218bfa2fdffe03e7cf0ee1217d5ca3 GIT binary patch literal 229 zcmZQ7PAvi=1_l-eE(ZOy{QP3oqO#PYw4D6% 1 - eps); + + { + grpc_exec_ctx exec_ctx = GRPC_EXEC_CTX_INIT; + grpc_resource_user_unref(&exec_ctx, usr); + grpc_exec_ctx_finish(&exec_ctx); + } + + grpc_resource_quota_unref(q); + { + grpc_exec_ctx exec_ctx = GRPC_EXEC_CTX_INIT; + grpc_slice_buffer_destroy_internal(&exec_ctx, &buffer); + grpc_exec_ctx_finish(&exec_ctx); + } +} + int main(int argc, char **argv) { grpc_test_init(argc, argv); grpc_init(); @@ -705,6 +755,8 @@ int main(int argc, char **argv) { test_reclaimers_can_be_posted_repeatedly(); test_one_slice(); test_one_slice_deleted_late(); + test_resize_to_zero(); + test_negative_rq_free_pool(); grpc_shutdown(); return 0; } diff --git a/tools/run_tests/generated/tests.json b/tools/run_tests/generated/tests.json index 6202346fc2f..9400dbcc39c 100644 --- a/tools/run_tests/generated/tests.json +++ b/tools/run_tests/generated/tests.json @@ -94209,6 +94209,29 @@ ], "uses_polling": false }, + { + "args": [ + "test/core/end2end/fuzzers/api_fuzzer_corpus/poc-c726ee220e980ed6ad17809fd9efe2844ee61555ac08e4f88afd8901cc2dd53a" + ], + "ci_platforms": [ + "linux" + ], + "cpu_cost": 0.1, + "exclude_configs": [ + "tsan" + ], + "exclude_iomgrs": [ + "uv" + ], + "flaky": false, + "language": "c", + "name": "api_fuzzer_one_entry", + "platforms": [ + "mac", + "linux" + ], + "uses_polling": false + }, { "args": [ "test/core/end2end/fuzzers/api_fuzzer_corpus/timeout-0fa0559576ad2a45b06d0bfb84115963d7d48206" From b98b3c260e33a6d4b645bc554a77882ab206a75b Mon Sep 17 00:00:00 2001 From: Alexander Polcyn Date: Tue, 28 Mar 2017 12:26:49 -0700 Subject: [PATCH 10/11] add examples for ruby error throwing and handling --- .../ruby/errors_and_cancellation/README.md | 25 ++++ .../error_examples_client.rb | 117 ++++++++++++++++++ .../error_examples_server.rb | 76 ++++++++++++ 3 files changed, 218 insertions(+) create mode 100644 examples/ruby/errors_and_cancellation/README.md create mode 100755 examples/ruby/errors_and_cancellation/error_examples_client.rb create mode 100755 examples/ruby/errors_and_cancellation/error_examples_server.rb diff --git a/examples/ruby/errors_and_cancellation/README.md b/examples/ruby/errors_and_cancellation/README.md new file mode 100644 index 00000000000..126518c4aab --- /dev/null +++ b/examples/ruby/errors_and_cancellation/README.md @@ -0,0 +1,25 @@ +#Errors and Cancelletion code samples for grpc-ruby + +The examples in this directory show use of grpc errors. + +On the server side, errors are returned from service +implementations by raising a certain `GRPC::BadStatus` exception. + +On the client side, GRPC errors get raised when either: + * the call completes (unary and client-streaming call types) + * the response `Enumerable` is iterated through (server-streaming and + bidi call types). + +## To run the examples here: + +Start the server: + +``` +> ruby error_examples_server.rb +``` + +Then run the client: + +``` +> ruby error_examples_client.rb +``` diff --git a/examples/ruby/errors_and_cancellation/error_examples_client.rb b/examples/ruby/errors_and_cancellation/error_examples_client.rb new file mode 100755 index 00000000000..90456d066d7 --- /dev/null +++ b/examples/ruby/errors_and_cancellation/error_examples_client.rb @@ -0,0 +1,117 @@ +#!/usr/bin/env ruby + +# Copyright 2015, 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. + +# Sample app that connects to an error-throwing implementation of +# Route Guide service. +# +# Usage: $ path/to/route_guide_client.rb + +this_dir = File.expand_path(File.dirname(__FILE__)) +lib_dir = File.join(File.dirname(this_dir), 'lib') +$LOAD_PATH.unshift(lib_dir) unless $LOAD_PATH.include?(lib_dir) + +require 'grpc' +require 'route_guide_services_pb' + +include Routeguide + +def run_get_feature_expect_error(stub) + resp = stub.get_feature(Point.new) +end + +def run_list_features_expect_error(stub) + resps = stub.list_features(Rectangle.new) + + # NOOP iteration to pick up error + resps.each { } +end + +def run_record_route_expect_error(stub) + stub.record_route([]) +end + +def run_route_chat_expect_error(stub) + resps = stub.route_chat([]) + + # NOOP iteration to pick up error + resps.each { } +end + +def main + stub = RouteGuide::Stub.new('localhost:50051', :this_channel_is_insecure) + + begin + run_get_feature_expect_error(stub) + rescue GRPC::BadStatus => e + puts "===== GetFeature exception: =====" + puts e.inspect + puts "e.code: #{e.code}" + puts "e.details: #{e.details}" + puts "e.metadata: #{e.metadata}" + puts "=================================" + end + + begin + run_list_features_expect_error(stub) + rescue GRPC::BadStatus => e + error = true + puts "===== ListFeatures exception: =====" + puts e.inspect + puts "e.code: #{e.code}" + puts "e.details: #{e.details}" + puts "e.metadata: #{e.metadata}" + puts "=================================" + end + + begin + run_route_chat_expect_error(stub) + rescue GRPC::BadStatus => e + puts "==== RouteChat exception: ====" + puts e.inspect + puts "e.code: #{e.code}" + puts "e.details: #{e.details}" + puts "e.metadata: #{e.metadata}" + puts "=================================" + end + + begin + run_record_route_expect_error(stub) + rescue GRPC::BadStatus => e + puts "==== RecordRoute exception: ====" + puts e.inspect + puts "e.code: #{e.code}" + puts "e.details: #{e.details}" + puts "e.metadata: #{e.metadata}" + puts "=================================" + end +end + +main diff --git a/examples/ruby/errors_and_cancellation/error_examples_server.rb b/examples/ruby/errors_and_cancellation/error_examples_server.rb new file mode 100755 index 00000000000..66751882d91 --- /dev/null +++ b/examples/ruby/errors_and_cancellation/error_examples_server.rb @@ -0,0 +1,76 @@ +#!/usr/bin/env ruby +# -*- coding: utf-8 -*- + +# Copyright 2015, 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. + +# Error-throwing implementation of Route Guide service. +# +# Usage: $ path/to/route_guide_server.rb + +this_dir = File.expand_path(File.dirname(__FILE__)) +lib_dir = File.join(File.dirname(this_dir), 'lib') +$LOAD_PATH.unshift(lib_dir) unless $LOAD_PATH.include?(lib_dir) + +require 'grpc' +require 'route_guide_services_pb' + +include Routeguide + +include GRPC::Core::StatusCodes + +# CanellingandErrorReturningServiceImpl provides an implementation of the RouteGuide service. +class CancellingAndErrorReturningServerImpl < RouteGuide::Service + # def get_feature + # Note get_feature isn't implemented in this subclass, so the server + # will get a gRPC UNIMPLEMENTED error when it's called. + + def list_features(rectangle, _call) + raise "string appears on the client in the 'details' field of a 'GRPC::Unknown' exception" + end + + def record_route(call) + raise GRPC::BadStatus.new_status_exception(CANCELLED) + end + + def route_chat(notes) + raise GRPC::BadStatus.new_status_exception(ABORTED, details = 'arbitrary', metadata = {somekey: 'val'}) + end +end + +def main + port = '0.0.0.0:50051' + s = GRPC::RpcServer.new + s.add_http2_port(port, :this_port_is_insecure) + GRPC.logger.info("... running insecurely on #{port}") + s.handle(CancellingAndErrorReturningServerImpl.new) + s.run_till_terminated +end + +main From eb2b11534233aa439c743142a47f683a05a42878 Mon Sep 17 00:00:00 2001 From: ncteisen Date: Tue, 28 Mar 2017 15:27:27 -0700 Subject: [PATCH 11/11] Fix error slice bug --- src/core/lib/surface/call.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/core/lib/surface/call.c b/src/core/lib/surface/call.c index 895a8a3b060..9342c5f8e95 100644 --- a/src/core/lib/surface/call.c +++ b/src/core/lib/surface/call.c @@ -625,7 +625,7 @@ static bool get_final_status_from( void (*set_value)(grpc_status_code code, void *user_data), void *set_value_user_data, grpc_slice *details) { grpc_status_code code; - grpc_slice slice; + grpc_slice slice = grpc_empty_slice(); grpc_error_get_status(error, call->send_deadline, &code, &slice, NULL); if (code == GRPC_STATUS_OK && !allow_ok_status) { return false;