|
|
|
@ -41,6 +41,7 @@ |
|
|
|
|
#include "src/core/lib/transport/service_config.h" |
|
|
|
|
|
|
|
|
|
#define DEFAULT_MAX_CONNECTION_AGE_S INT_MAX |
|
|
|
|
#define DEFAULT_MAX_CONNECTION_AGE_GRACE_S INT_MAX |
|
|
|
|
|
|
|
|
|
typedef struct channel_data { |
|
|
|
|
// We take a reference to the channel stack for the timer callback
|
|
|
|
@ -49,19 +50,31 @@ typedef struct channel_data { |
|
|
|
|
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
|
|
|
|
|
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
|
|
|
|
|
grpc_timer max_age_grace_timer; |
|
|
|
|
// 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 reaches its max age and should be closed
|
|
|
|
|
// gracefully
|
|
|
|
|
grpc_closure close_max_age_channel; |
|
|
|
|
// Closure to run when the init fo channel stack is done and the timer should
|
|
|
|
|
// be started
|
|
|
|
|
grpc_closure start_timer_after_init; |
|
|
|
|
// 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_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; |
|
|
|
|
} channel_data; |
|
|
|
|
|
|
|
|
|
static void start_timer_after_init(grpc_exec_ctx* exec_ctx, void* arg, |
|
|
|
|
grpc_error* error) { |
|
|
|
|
static void start_max_age_timer_after_init(grpc_exec_ctx* exec_ctx, void* arg, |
|
|
|
|
grpc_error* error) { |
|
|
|
|
channel_data* chand = arg; |
|
|
|
|
gpr_mu_lock(&chand->max_age_timer_mu); |
|
|
|
|
chand->max_age_timer_pending = true; |
|
|
|
@ -71,7 +84,23 @@ static void start_timer_after_init(grpc_exec_ctx* exec_ctx, void* arg, |
|
|
|
|
&chand->close_max_age_channel, gpr_now(GPR_CLOCK_MONOTONIC)); |
|
|
|
|
gpr_mu_unlock(&chand->max_age_timer_mu); |
|
|
|
|
GRPC_CHANNEL_STACK_UNREF(exec_ctx, chand->channel_stack, |
|
|
|
|
"max_age start_timer_after_init"); |
|
|
|
|
"max_age start_max_age_timer_after_init"); |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
static void start_max_age_grace_timer_after_goaway_op(grpc_exec_ctx* exec_ctx, |
|
|
|
|
void* arg, |
|
|
|
|
grpc_error* error) { |
|
|
|
|
channel_data* chand = arg; |
|
|
|
|
gpr_mu_lock(&chand->max_age_timer_mu); |
|
|
|
|
chand->max_age_grace_timer_pending = true; |
|
|
|
|
grpc_timer_init(exec_ctx, &chand->max_age_grace_timer, |
|
|
|
|
gpr_time_add(gpr_now(GPR_CLOCK_MONOTONIC), |
|
|
|
|
chand->max_connection_age_grace), |
|
|
|
|
&chand->force_close_max_age_channel, |
|
|
|
|
gpr_now(GPR_CLOCK_MONOTONIC)); |
|
|
|
|
gpr_mu_unlock(&chand->max_age_timer_mu); |
|
|
|
|
GRPC_CHANNEL_STACK_UNREF(exec_ctx, chand->channel_stack, |
|
|
|
|
"max_age start_max_age_grace_timer_after_goaway_op"); |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
static void close_max_age_channel(grpc_exec_ctx* exec_ctx, void* arg, |
|
|
|
@ -81,7 +110,10 @@ static void close_max_age_channel(grpc_exec_ctx* exec_ctx, void* arg, |
|
|
|
|
chand->max_age_timer_pending = false; |
|
|
|
|
gpr_mu_unlock(&chand->max_age_timer_mu); |
|
|
|
|
if (error == GRPC_ERROR_NONE) { |
|
|
|
|
grpc_transport_op* op = grpc_make_transport_op(NULL); |
|
|
|
|
GRPC_CHANNEL_STACK_REF(chand->channel_stack, |
|
|
|
|
"max_age start_max_age_grace_timer_after_goaway_op"); |
|
|
|
|
grpc_transport_op* op = grpc_make_transport_op( |
|
|
|
|
&chand->start_max_age_grace_timer_after_goaway_op); |
|
|
|
|
op->goaway_error = |
|
|
|
|
grpc_error_set_int(GRPC_ERROR_CREATE_FROM_STATIC_STRING("max_age"), |
|
|
|
|
GRPC_ERROR_INT_HTTP2_ERROR, GRPC_HTTP2_NO_ERROR); |
|
|
|
@ -93,6 +125,24 @@ static void close_max_age_channel(grpc_exec_ctx* exec_ctx, void* arg, |
|
|
|
|
} |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
static void force_close_max_age_channel(grpc_exec_ctx* exec_ctx, void* arg, |
|
|
|
|
grpc_error* error) { |
|
|
|
|
channel_data* chand = arg; |
|
|
|
|
gpr_mu_lock(&chand->max_age_timer_mu); |
|
|
|
|
chand->max_age_grace_timer_pending = false; |
|
|
|
|
gpr_mu_unlock(&chand->max_age_timer_mu); |
|
|
|
|
if (error == GRPC_ERROR_NONE) { |
|
|
|
|
grpc_transport_op* op = grpc_make_transport_op(NULL); |
|
|
|
|
op->disconnect_with_error = |
|
|
|
|
GRPC_ERROR_CREATE_FROM_STATIC_STRING("Channel reaches max age"); |
|
|
|
|
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("force_close_max_age_channel", error); |
|
|
|
|
} |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
// Constructor for call_data.
|
|
|
|
|
static grpc_error* init_call_elem(grpc_exec_ctx* exec_ctx, |
|
|
|
|
grpc_call_element* elem, |
|
|
|
@ -115,11 +165,17 @@ static grpc_error* init_channel_elem(grpc_exec_ctx* exec_ctx, |
|
|
|
|
channel_data* chand = elem->channel_data; |
|
|
|
|
gpr_mu_init(&chand->max_age_timer_mu); |
|
|
|
|
chand->max_age_timer_pending = false; |
|
|
|
|
chand->max_age_grace_timer_pending = false; |
|
|
|
|
chand->channel_stack = args->channel_stack; |
|
|
|
|
chand->max_connection_age = |
|
|
|
|
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 = |
|
|
|
|
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); |
|
|
|
|
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)) { |
|
|
|
@ -129,10 +185,28 @@ static grpc_error* init_channel_elem(grpc_exec_ctx* exec_ctx, |
|
|
|
|
chand->max_connection_age = |
|
|
|
|
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_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, |
|
|
|
|
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_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_age_timer_after_init, |
|
|
|
|
start_max_age_timer_after_init, chand, |
|
|
|
|
grpc_schedule_on_exec_ctx); |
|
|
|
|
grpc_closure_init(&chand->start_max_age_grace_timer_after_goaway_op, |
|
|
|
|
start_max_age_grace_timer_after_goaway_op, chand, |
|
|
|
|
grpc_schedule_on_exec_ctx); |
|
|
|
|
|
|
|
|
|
if (gpr_time_cmp(chand->max_connection_age, gpr_inf_future(GPR_TIMESPAN)) != |
|
|
|
|
0) { |
|
|
|
@ -144,10 +218,8 @@ static grpc_error* init_channel_elem(grpc_exec_ctx* exec_ctx, |
|
|
|
|
// timer, and we schedule that closure to be run after call stack
|
|
|
|
|
// initialization is done.
|
|
|
|
|
GRPC_CHANNEL_STACK_REF(chand->channel_stack, |
|
|
|
|
"max_age start_timer_after_init"); |
|
|
|
|
grpc_closure_init(&chand->start_timer_after_init, start_timer_after_init, |
|
|
|
|
chand, grpc_schedule_on_exec_ctx); |
|
|
|
|
grpc_closure_sched(exec_ctx, &chand->start_timer_after_init, |
|
|
|
|
"max_age start_max_age_timer_after_init"); |
|
|
|
|
grpc_closure_sched(exec_ctx, &chand->start_max_age_timer_after_init, |
|
|
|
|
GRPC_ERROR_NONE); |
|
|
|
|
} |
|
|
|
|
|
|
|
|
@ -162,6 +234,9 @@ static void destroy_channel_elem(grpc_exec_ctx* exec_ctx, |
|
|
|
|
if (chand->max_age_timer_pending) { |
|
|
|
|
grpc_timer_cancel(exec_ctx, &chand->max_age_timer); |
|
|
|
|
} |
|
|
|
|
if (chand->max_age_grace_timer_pending) { |
|
|
|
|
grpc_timer_cancel(exec_ctx, &chand->max_age_grace_timer); |
|
|
|
|
} |
|
|
|
|
gpr_mu_unlock(&chand->max_age_timer_mu); |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|