|
|
|
@ -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 = { |
|
|
|
|