Add max_connection_idle enforcement

pull/10318/head
Yuchen Zeng 8 years ago
parent a1506c4e8f
commit 367428ad58
  1. 3
      include/grpc/impl/codegen/grpc_types.h
  2. 98
      src/core/lib/channel/max_age_filter.c

@ -163,6 +163,9 @@ typedef struct {
/** Maximum message length that the channel can send. Int valued, bytes.
-1 means unlimited. */
#define GRPC_ARG_MAX_SEND_MESSAGE_LENGTH "grpc.max_send_message_length"
/** Maximum time that a channel may have no outstanding rpcs. Int valued,
seconds. INT_MAX means unlimited. */
#define GPRC_ARG_MAX_CONNECION_IDLE_S "grpc.max_connection_idle"
/** Maximum time that a channel may exist. Int valued, seconds. INT_MAX means
unlimited. */
#define GPRC_ARG_MAX_CONNECION_AGE_S "grpc.max_connection_age"

@ -42,37 +42,76 @@
#define DEFAULT_MAX_CONNECTION_AGE_S INT_MAX
#define DEFAULT_MAX_CONNECTION_AGE_GRACE_S INT_MAX
#define DEFAULT_MAX_CONNECTION_IDLE_S INT_MAX
typedef struct channel_data {
// We take a reference to the channel stack for the timer callback
grpc_channel_stack* channel_stack;
// Guards access to max_age_timer and max_age_timer_pending
// Guards access to max_age_timer, max_age_timer_pending, max_age_grace_timer
// and max_age_grace_timer_pending
gpr_mu max_age_timer_mu;
// True if the max_age timer callback is currently pending
bool max_age_timer_pending;
// True if the max_age timer callback is currently pending
// True if the max_age_grace timer callback is currently pending
bool max_age_grace_timer_pending;
// The timer for checking if the channel has reached its max age
grpc_timer max_age_timer;
// The timer for checking if the channel has reached its max age
// The timer for checking if the max-aged channel has uesed up the grace
// period
grpc_timer max_age_grace_timer;
// The timer for checking if the channel's idle duration reaches
// max_connection_idle
grpc_timer max_idle_timer;
// Allowed max time a channel may have no outstanding rpcs
gpr_timespec max_connection_idle;
// Allowed max time a channel may exist
gpr_timespec max_connection_age;
// Allowed grace period after the channel reaches its max age
gpr_timespec max_connection_age_grace;
// Closure to run when the channel's idle duration reaches max_connection_idle
// and should be closed gracefully
grpc_closure close_max_idle_channel;
// Closure to run when the channel reaches its max age and should be closed
// gracefully
grpc_closure close_max_age_channel;
// Closure to run the channel uses up its max age grace time and should be
// closed forcibly
grpc_closure force_close_max_age_channel;
// Closure to run when the init fo channel stack is done and the max_idle
// timer should be started
grpc_closure start_max_idle_timer_after_init;
// Closure to run when the init fo channel stack is done and the max_age timer
// should be started
grpc_closure start_max_age_timer_after_init;
// Closure to run when the goaway op is finished and the max_age_timer
grpc_closure start_max_age_grace_timer_after_goaway_op;
// Number of active calls
gpr_atm call_count;
} channel_data;
static void increase_call_count(grpc_exec_ctx* exec_ctx, channel_data* chand) {
if (gpr_atm_full_fetch_add(&chand->call_count, 1) == 0) {
grpc_timer_cancel(exec_ctx, &chand->max_idle_timer);
}
}
static void decrease_call_count(grpc_exec_ctx* exec_ctx, channel_data* chand) {
if (gpr_atm_full_fetch_add(&chand->call_count, -1) == 1) {
grpc_timer_init(
exec_ctx, &chand->max_idle_timer,
gpr_time_add(gpr_now(GPR_CLOCK_MONOTONIC), chand->max_connection_idle),
&chand->close_max_idle_channel, gpr_now(GPR_CLOCK_MONOTONIC));
}
}
static void start_max_idle_timer_after_init(grpc_exec_ctx* exec_ctx, void* arg,
grpc_error* error) {
channel_data* chand = arg;
decrease_call_count(exec_ctx, chand);
GRPC_CHANNEL_STACK_UNREF(exec_ctx, chand->channel_stack,
"max_age start_max_idle_timer_after_init");
}
static void start_max_age_timer_after_init(grpc_exec_ctx* exec_ctx, void* arg,
grpc_error* error) {
channel_data* chand = arg;
@ -103,6 +142,23 @@ static void start_max_age_grace_timer_after_goaway_op(grpc_exec_ctx* exec_ctx,
"max_age start_max_age_grace_timer_after_goaway_op");
}
static void close_max_idle_channel(grpc_exec_ctx* exec_ctx, void* arg,
grpc_error* error) {
channel_data* chand = arg;
gpr_atm_no_barrier_fetch_add(&chand->call_count, 1);
if (error == GRPC_ERROR_NONE) {
grpc_transport_op* op = grpc_make_transport_op(NULL);
op->goaway_error =
grpc_error_set_int(GRPC_ERROR_CREATE_FROM_STATIC_STRING("max_idle"),
GRPC_ERROR_INT_HTTP2_ERROR, GRPC_HTTP2_NO_ERROR);
grpc_channel_element* elem =
grpc_channel_stack_element(chand->channel_stack, 0);
elem->filter->start_transport_op(exec_ctx, elem, op);
} else if (error != GRPC_ERROR_CANCELLED) {
GRPC_LOG_IF_ERROR("close_max_idle_channel", error);
}
}
static void close_max_age_channel(grpc_exec_ctx* exec_ctx, void* arg,
grpc_error* error) {
channel_data* chand = arg;
@ -147,7 +203,8 @@ static void force_close_max_age_channel(grpc_exec_ctx* exec_ctx, void* arg,
static grpc_error* init_call_elem(grpc_exec_ctx* exec_ctx,
grpc_call_element* elem,
const grpc_call_element_args* args) {
// call_num ++;
channel_data* chand = elem->channel_data;
increase_call_count(exec_ctx, chand);
return GRPC_ERROR_NONE;
}
@ -155,7 +212,8 @@ static grpc_error* init_call_elem(grpc_exec_ctx* exec_ctx,
static void destroy_call_elem(grpc_exec_ctx* exec_ctx, grpc_call_element* elem,
const grpc_call_final_info* final_info,
grpc_closure* ignored) {
// call_num --;
channel_data* chand = elem->channel_data;
decrease_call_count(exec_ctx, chand);
}
// Constructor for channel_data.
@ -171,11 +229,15 @@ static grpc_error* init_channel_elem(grpc_exec_ctx* exec_ctx,
DEFAULT_MAX_CONNECTION_AGE_S == INT_MAX
? gpr_inf_future(GPR_TIMESPAN)
: gpr_time_from_seconds(DEFAULT_MAX_CONNECTION_AGE_S, GPR_TIMESPAN);
chand->max_connection_age =
chand->max_connection_age_grace =
DEFAULT_MAX_CONNECTION_AGE_GRACE_S == INT_MAX
? gpr_inf_future(GPR_TIMESPAN)
: gpr_time_from_seconds(DEFAULT_MAX_CONNECTION_AGE_GRACE_S,
GPR_TIMESPAN);
chand->max_connection_idle =
DEFAULT_MAX_CONNECTION_IDLE_S == INT_MAX
? gpr_inf_future(GPR_TIMESPAN)
: gpr_time_from_seconds(DEFAULT_MAX_CONNECTION_IDLE_S, GPR_TIMESPAN);
for (size_t i = 0; i < args->channel_args->num_args; ++i) {
if (0 ==
strcmp(args->channel_args->args[i].key, GPRC_ARG_MAX_CONNECION_AGE_S)) {
@ -189,18 +251,31 @@ static grpc_error* init_channel_elem(grpc_exec_ctx* exec_ctx,
GPRC_ARG_MAX_CONNECION_AGE_GRACE_S)) {
const int value = grpc_channel_arg_get_integer(
&args->channel_args->args[i],
(grpc_integer_options){DEFAULT_MAX_CONNECTION_AGE_GRACE_S, 1,
(grpc_integer_options){DEFAULT_MAX_CONNECTION_AGE_GRACE_S, 0,
INT_MAX});
chand->max_connection_age_grace =
value == INT_MAX ? gpr_inf_future(GPR_TIMESPAN)
: gpr_time_from_seconds(value, GPR_TIMESPAN);
} else if (0 == strcmp(args->channel_args->args[i].key,
GPRC_ARG_MAX_CONNECION_IDLE_S)) {
const int value = grpc_channel_arg_get_integer(
&args->channel_args->args[i],
(grpc_integer_options){DEFAULT_MAX_CONNECTION_IDLE_S, 1, INT_MAX});
chand->max_connection_age_grace =
value == INT_MAX ? gpr_inf_future(GPR_TIMESPAN)
: gpr_time_from_seconds(value, GPR_TIMESPAN);
}
}
grpc_closure_init(&chand->close_max_idle_channel, close_max_idle_channel,
chand, grpc_schedule_on_exec_ctx);
grpc_closure_init(&chand->close_max_age_channel, close_max_age_channel, chand,
grpc_schedule_on_exec_ctx);
grpc_closure_init(&chand->force_close_max_age_channel,
force_close_max_age_channel, chand,
grpc_schedule_on_exec_ctx);
grpc_closure_init(&chand->start_max_idle_timer_after_init,
start_max_idle_timer_after_init, chand,
grpc_schedule_on_exec_ctx);
grpc_closure_init(&chand->start_max_age_timer_after_init,
start_max_age_timer_after_init, chand,
grpc_schedule_on_exec_ctx);
@ -223,6 +298,14 @@ static grpc_error* init_channel_elem(grpc_exec_ctx* exec_ctx,
GRPC_ERROR_NONE);
}
gpr_atm_rel_store(&chand->call_count, 1);
if (gpr_time_cmp(chand->max_connection_idle, gpr_inf_future(GPR_TIMESPAN)) !=
0) {
GRPC_CHANNEL_STACK_REF(chand->channel_stack,
"max_age start_max_idle_timer_after_init");
grpc_closure_sched(exec_ctx, &chand->start_max_idle_timer_after_init,
GRPC_ERROR_NONE);
}
return GRPC_ERROR_NONE;
}
@ -238,6 +321,7 @@ static void destroy_channel_elem(grpc_exec_ctx* exec_ctx,
grpc_timer_cancel(exec_ctx, &chand->max_age_grace_timer);
}
gpr_mu_unlock(&chand->max_age_timer_mu);
increase_call_count(exec_ctx, chand);
}
const grpc_channel_filter grpc_max_age_filter = {

Loading…
Cancel
Save