Merge pull request #10325 from y-zeng/keepalive_fixes

Client-side keepalive fixes
pull/10344/head
Yuchen Zeng 8 years ago committed by GitHub
commit 6b8e844e5e
  1. 8
      include/grpc/impl/codegen/grpc_types.h
  2. 58
      src/core/ext/transport/chttp2/transport/chttp2_transport.c
  3. 20
      src/core/ext/transport/chttp2/transport/frame_ping.c
  4. 3
      src/core/ext/transport/chttp2/transport/frame_ping.h
  5. 4
      src/core/ext/transport/chttp2/transport/internal.h
  6. 20
      test/core/end2end/tests/keepalive_timeout.c

@ -198,14 +198,14 @@ typedef struct {
#define GRPC_ARG_HTTP2_WRITE_BUFFER_SIZE "grpc.http2.write_buffer_size" #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 /** After a duration of this time the client pings the server to see if the
transport is still alive. Int valued, seconds. */ transport is still alive. Int valued, seconds. */
#define GRPC_ARG_HTTP2_KEEPALIVE_TIME "grpc.http2.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 /** 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. */ the ping ack, it will close the transport. Int valued, seconds. */
#define GRPC_ARG_HTTP2_KEEPALIVE_TIMEOUT "grpc.http2.keepalive_timeout" #define GRPC_ARG_CLIENT_KEEPALIVE_TIMEOUT_S "grpc.client_keepalive_timeout"
/** Is it permissible to send keepalive pings without any outstanding streams. /** Is it permissible to send keepalive pings without any outstanding streams.
Int valued, 0(false)/1(true). */ Int valued, 0(false)/1(true). */
#define GRPC_ARG_HTTP2_KEEPALIVE_PERMIT_WITHOUT_CALLS \ #define GRPC_ARG_KEEPALIVE_PERMIT_WITHOUT_CALLS \
"grpc.http2.keepalive_permit_without_calls" "grpc.keepalive_permit_without_calls"
/** Default authority to pass if none specified on call construction. A string. /** Default authority to pass if none specified on call construction. A string.
* */ * */
#define GRPC_ARG_DEFAULT_AUTHORITY "grpc.default_authority" #define GRPC_ARG_DEFAULT_AUTHORITY "grpc.default_authority"

@ -69,10 +69,16 @@
#define MAX_WRITE_BUFFER_SIZE (64 * 1024 * 1024) #define MAX_WRITE_BUFFER_SIZE (64 * 1024 * 1024)
#define DEFAULT_MAX_HEADER_LIST_SIZE (16 * 1024) #define DEFAULT_MAX_HEADER_LIST_SIZE (16 * 1024)
#define DEFAULT_KEEPALIVE_TIME_SECOND INT_MAX #define DEFAULT_CLIENT_KEEPALIVE_TIME_S INT_MAX
#define DEFAULT_KEEPALIVE_TIMEOUT_SECOND 20 #define DEFAULT_CLIENT_KEEPALIVE_TIMEOUT_S 20
#define DEFAULT_KEEPALIVE_PERMIT_WITHOUT_CALLS false #define DEFAULT_KEEPALIVE_PERMIT_WITHOUT_CALLS false
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;
#define MAX_CLIENT_STREAM_ID 0x7fffffffu #define MAX_CLIENT_STREAM_ID 0x7fffffffu
int grpc_http_trace = 0; int grpc_http_trace = 0;
int grpc_flowctl_trace = 0; int grpc_flowctl_trace = 0;
@ -345,15 +351,16 @@ static void init_transport(grpc_exec_ctx *exec_ctx, grpc_chttp2_transport *t,
/* client-side keepalive setting */ /* client-side keepalive setting */
t->keepalive_time = t->keepalive_time =
DEFAULT_KEEPALIVE_TIME_SECOND == INT_MAX g_default_client_keepalive_time_s == INT_MAX
? gpr_inf_future(GPR_TIMESPAN) ? gpr_inf_future(GPR_TIMESPAN)
: gpr_time_from_seconds(DEFAULT_KEEPALIVE_TIME_SECOND, GPR_TIMESPAN); : gpr_time_from_seconds(g_default_client_keepalive_time_s,
GPR_TIMESPAN);
t->keepalive_timeout = t->keepalive_timeout =
DEFAULT_KEEPALIVE_TIMEOUT_SECOND == INT_MAX g_default_client_keepalive_timeout_s == INT_MAX
? gpr_inf_future(GPR_TIMESPAN) ? gpr_inf_future(GPR_TIMESPAN)
: gpr_time_from_seconds(DEFAULT_KEEPALIVE_TIMEOUT_SECOND, : gpr_time_from_seconds(g_default_client_keepalive_timeout_s,
GPR_TIMESPAN); GPR_TIMESPAN);
t->keepalive_permit_without_calls = DEFAULT_KEEPALIVE_PERMIT_WITHOUT_CALLS; t->keepalive_permit_without_calls = g_default_keepalive_permit_without_calls;
if (channel_args) { if (channel_args) {
for (i = 0; i < channel_args->num_args; i++) { for (i = 0; i < channel_args->num_args; i++) {
@ -403,24 +410,25 @@ static void init_transport(grpc_exec_ctx *exec_ctx, grpc_chttp2_transport *t,
t->enable_bdp_probe = grpc_channel_arg_get_integer( t->enable_bdp_probe = grpc_channel_arg_get_integer(
&channel_args->args[i], (grpc_integer_options){1, 0, 1}); &channel_args->args[i], (grpc_integer_options){1, 0, 1});
} else if (0 == strcmp(channel_args->args[i].key, } else if (0 == strcmp(channel_args->args[i].key,
GRPC_ARG_HTTP2_KEEPALIVE_TIME)) { GRPC_ARG_CLIENT_KEEPALIVE_TIME_S)) {
const int value = grpc_channel_arg_get_integer( const int value = grpc_channel_arg_get_integer(
&channel_args->args[i], &channel_args->args[i],
(grpc_integer_options){DEFAULT_KEEPALIVE_TIME_SECOND, 1, INT_MAX}); (grpc_integer_options){g_default_client_keepalive_time_s, 1,
INT_MAX});
t->keepalive_time = value == INT_MAX t->keepalive_time = value == INT_MAX
? gpr_inf_future(GPR_TIMESPAN) ? gpr_inf_future(GPR_TIMESPAN)
: gpr_time_from_seconds(value, GPR_TIMESPAN); : gpr_time_from_seconds(value, GPR_TIMESPAN);
} else if (0 == strcmp(channel_args->args[i].key, } else if (0 == strcmp(channel_args->args[i].key,
GRPC_ARG_HTTP2_KEEPALIVE_TIMEOUT)) { GRPC_ARG_CLIENT_KEEPALIVE_TIMEOUT_S)) {
const int value = grpc_channel_arg_get_integer( const int value = grpc_channel_arg_get_integer(
&channel_args->args[i], &channel_args->args[i],
(grpc_integer_options){DEFAULT_KEEPALIVE_TIMEOUT_SECOND, 0, (grpc_integer_options){g_default_client_keepalive_timeout_s, 0,
INT_MAX}); INT_MAX});
t->keepalive_timeout = value == INT_MAX t->keepalive_timeout = value == INT_MAX
? gpr_inf_future(GPR_TIMESPAN) ? gpr_inf_future(GPR_TIMESPAN)
: gpr_time_from_seconds(value, GPR_TIMESPAN); : gpr_time_from_seconds(value, GPR_TIMESPAN);
} else if (0 == strcmp(channel_args->args[i].key, } 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 = t->keepalive_permit_without_calls =
(uint32_t)grpc_channel_arg_get_integer( (uint32_t)grpc_channel_arg_get_integer(
&channel_args->args[i], (grpc_integer_options){0, 0, 1}); &channel_args->args[i], (grpc_integer_options){0, 0, 1});
@ -2108,6 +2116,32 @@ static void finish_bdp_ping_locked(grpc_exec_ctx *exec_ctx, void *tp,
GRPC_CHTTP2_UNREF_TRANSPORT(exec_ctx, t, "bdp_ping"); 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_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_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 =
(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, static void init_keepalive_ping_locked(grpc_exec_ctx *exec_ctx, void *arg,
grpc_error *error) { grpc_error *error) {
grpc_chttp2_transport *t = arg; grpc_chttp2_transport *t = arg;

@ -40,6 +40,8 @@
#include <grpc/support/log.h> #include <grpc/support/log.h>
#include <grpc/support/string_util.h> #include <grpc/support/string_util.h>
static bool g_disable_ping_ack = false;
grpc_slice grpc_chttp2_ping_create(uint8_t ack, uint64_t opaque_8bytes) { grpc_slice grpc_chttp2_ping_create(uint8_t ack, uint64_t opaque_8bytes) {
grpc_slice slice = grpc_slice_malloc(9 + 8); grpc_slice slice = grpc_slice_malloc(9 + 8);
uint8_t *p = GRPC_SLICE_START_PTR(slice); uint8_t *p = GRPC_SLICE_START_PTR(slice);
@ -101,15 +103,21 @@ grpc_error *grpc_chttp2_ping_parser_parse(grpc_exec_ctx *exec_ctx, void *parser,
if (p->is_ack) { if (p->is_ack) {
grpc_chttp2_ack_ping(exec_ctx, t, p->opaque_8bytes); grpc_chttp2_ack_ping(exec_ctx, t, p->opaque_8bytes);
} else { } else {
if (t->ping_ack_count == t->ping_ack_capacity) { if (!g_disable_ping_ack) {
t->ping_ack_capacity = GPR_MAX(t->ping_ack_capacity * 3 / 2, 3); if (t->ping_ack_count == t->ping_ack_capacity) {
t->ping_acks = gpr_realloc( t->ping_ack_capacity = GPR_MAX(t->ping_ack_capacity * 3 / 2, 3);
t->ping_acks, t->ping_ack_capacity * sizeof(*t->ping_acks)); 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");
} }
} }
return GRPC_ERROR_NONE; return GRPC_ERROR_NONE;
} }
void grpc_set_disable_ping_ack(bool disable_ping_ack) {
g_disable_ping_ack = disable_ping_ack;
}

@ -53,4 +53,7 @@ grpc_error *grpc_chttp2_ping_parser_parse(grpc_exec_ctx *exec_ctx, void *parser,
grpc_chttp2_stream *s, grpc_chttp2_stream *s,
grpc_slice slice, int is_last); 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 */ #endif /* GRPC_CORE_EXT_TRANSPORT_CHTTP2_TRANSPORT_FRAME_PING_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); 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 */ #endif /* GRPC_CORE_EXT_TRANSPORT_CHTTP2_TRANSPORT_INTERNAL_H */

@ -41,6 +41,7 @@
#include <grpc/support/log.h> #include <grpc/support/log.h>
#include <grpc/support/time.h> #include <grpc/support/time.h>
#include <grpc/support/useful.h> #include <grpc/support/useful.h>
#include "src/core/ext/transport/chttp2/transport/frame_ping.h"
#include "src/core/lib/channel/channel_args.h" #include "src/core/lib/channel/channel_args.h"
#include "src/core/lib/iomgr/exec_ctx.h" #include "src/core/lib/iomgr/exec_ctx.h"
#include "src/core/lib/support/env.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); grpc_raw_byte_buffer_create(&response_payload_slice, 1);
gpr_timespec deadline = five_seconds_time(); gpr_timespec deadline = five_seconds_time();
grpc_arg keepalive_args[2]; grpc_arg keepalive_args[] = {{.type = GRPC_ARG_INTEGER,
keepalive_args[0].type = GRPC_ARG_INTEGER; .key = GRPC_ARG_CLIENT_KEEPALIVE_TIME_S,
keepalive_args[0].key = GRPC_ARG_HTTP2_KEEPALIVE_TIME; .value.integer = 2},
keepalive_args[0].value.integer = 2; {.type = GRPC_ARG_INTEGER,
keepalive_args[1].type = GRPC_ARG_INTEGER; .key = GRPC_ARG_CLIENT_KEEPALIVE_TIMEOUT_S,
keepalive_args[1].key = GRPC_ARG_HTTP2_KEEPALIVE_TIMEOUT; .value.integer = 0},
keepalive_args[1].value.integer = 0; {.type = GRPC_ARG_INTEGER,
.key = GRPC_ARG_HTTP2_BDP_PROBE,
.value.integer = 1}};
grpc_channel_args *client_args = NULL; grpc_channel_args *client_args = NULL;
client_args = grpc_channel_args_copy_and_add(client_args, keepalive_args, 2); 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_call_error error;
grpc_slice details; grpc_slice details;
/* Disable ping ack to trigger the keepalive timeout */
grpc_set_disable_ping_ack(true);
c = grpc_channel_create_call( c = grpc_channel_create_call(
f.client, NULL, GRPC_PROPAGATE_DEFAULTS, f.cq, f.client, NULL, GRPC_PROPAGATE_DEFAULTS, f.cq,
grpc_slice_from_static_string("/foo"), grpc_slice_from_static_string("/foo"),

Loading…
Cancel
Save