|
|
|
@ -54,26 +54,27 @@ typedef struct { |
|
|
|
|
grpc_mdctx *mdctx; |
|
|
|
|
/** resolver for this channel */ |
|
|
|
|
grpc_resolver *resolver; |
|
|
|
|
/** channel arguments for this channel
|
|
|
|
|
TODO(ctiller): still needed? */ |
|
|
|
|
grpc_channel_args *args; |
|
|
|
|
|
|
|
|
|
/** mutex protecting waiting list */ |
|
|
|
|
gpr_mu mu_waiting; |
|
|
|
|
/** mutex protecting client configuration, resolution state */ |
|
|
|
|
gpr_mu mu_config; |
|
|
|
|
|
|
|
|
|
/** currently active load balancer - guarded by mu_config */ |
|
|
|
|
grpc_lb_policy *lb_policy; |
|
|
|
|
|
|
|
|
|
/** incoming configuration - set by resolver.next
|
|
|
|
|
guarded by mu_config */ |
|
|
|
|
grpc_client_config *incoming_configuration; |
|
|
|
|
/** a list of closures that are all waiting for config to come in */ |
|
|
|
|
grpc_iomgr_closure *waiting_for_config_closures; |
|
|
|
|
/** resolver callback */ |
|
|
|
|
grpc_iomgr_closure on_config_changed; |
|
|
|
|
/** connectivity state being tracked */ |
|
|
|
|
grpc_iomgr_closure *on_connectivity_state_change; |
|
|
|
|
grpc_connectivity_state *connectivity_state; |
|
|
|
|
} channel_data; |
|
|
|
|
|
|
|
|
|
typedef enum { |
|
|
|
|
CALL_CREATED, |
|
|
|
|
CALL_WAITING, |
|
|
|
|
CALL_WAITING_FOR_CONFIG, |
|
|
|
|
CALL_WAITING_FOR_PICK, |
|
|
|
|
CALL_ACTIVE, |
|
|
|
|
CALL_CANCELLED |
|
|
|
|
} call_state; |
|
|
|
@ -193,13 +194,12 @@ static void pick_target(grpc_lb_policy *lb_policy, call_data *calld) { |
|
|
|
|
abort(); |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
static void cc_start_transport_op(grpc_call_element *elem, |
|
|
|
|
static void cc_start_transport_stream_op(grpc_call_element *elem, |
|
|
|
|
grpc_transport_stream_op *op) { |
|
|
|
|
call_data *calld = elem->call_data; |
|
|
|
|
channel_data *chand = elem->channel_data; |
|
|
|
|
grpc_subchannel_call *subchannel_call; |
|
|
|
|
grpc_lb_policy *lb_policy; |
|
|
|
|
grpc_transport_stream_op waiting_op; |
|
|
|
|
GPR_ASSERT(elem->filter == &grpc_client_channel_filter); |
|
|
|
|
GRPC_CALL_LOG_OP(GPR_INFO, elem, op); |
|
|
|
|
|
|
|
|
@ -207,10 +207,8 @@ static void cc_start_transport_op(grpc_call_element *elem, |
|
|
|
|
switch (calld->state) { |
|
|
|
|
case CALL_ACTIVE: |
|
|
|
|
subchannel_call = calld->s.active.subchannel_call; |
|
|
|
|
grpc_subchannel_call_ref(subchannel_call); |
|
|
|
|
gpr_mu_unlock(&calld->mu_state); |
|
|
|
|
grpc_subchannel_call_process_op(subchannel_call, op); |
|
|
|
|
grpc_subchannel_call_unref(subchannel_call); |
|
|
|
|
break; |
|
|
|
|
case CALL_CANCELLED: |
|
|
|
|
gpr_mu_unlock(&calld->mu_state); |
|
|
|
@ -222,7 +220,6 @@ static void cc_start_transport_op(grpc_call_element *elem, |
|
|
|
|
gpr_mu_unlock(&calld->mu_state); |
|
|
|
|
handle_op_after_cancellation(elem, op); |
|
|
|
|
} else { |
|
|
|
|
calld->state = CALL_WAITING; |
|
|
|
|
calld->s.waiting_op = *op; |
|
|
|
|
|
|
|
|
|
gpr_mu_lock(&chand->mu_config); |
|
|
|
@ -230,45 +227,44 @@ static void cc_start_transport_op(grpc_call_element *elem, |
|
|
|
|
if (lb_policy) { |
|
|
|
|
grpc_lb_policy_ref(lb_policy); |
|
|
|
|
gpr_mu_unlock(&chand->mu_config); |
|
|
|
|
calld->state = CALL_WAITING_FOR_PICK; |
|
|
|
|
gpr_mu_unlock(&calld->mu_state); |
|
|
|
|
|
|
|
|
|
pick_target(lb_policy, calld); |
|
|
|
|
|
|
|
|
|
grpc_lb_policy_unref(lb_policy); |
|
|
|
|
} else { |
|
|
|
|
calld->state = CALL_WAITING_FOR_CONFIG; |
|
|
|
|
add_to_lb_policy_wait_queue_locked_state_config(chand, calld); |
|
|
|
|
gpr_mu_unlock(&chand->mu_config); |
|
|
|
|
gpr_mu_unlock(&calld->mu_state); |
|
|
|
|
} |
|
|
|
|
} |
|
|
|
|
break; |
|
|
|
|
case CALL_WAITING: |
|
|
|
|
case CALL_WAITING_FOR_CONFIG: |
|
|
|
|
case CALL_WAITING_FOR_PICK: |
|
|
|
|
if (op->cancel_with_status != GRPC_STATUS_OK) { |
|
|
|
|
waiting_op = calld->s.waiting_op; |
|
|
|
|
calld->state = CALL_CANCELLED; |
|
|
|
|
gpr_mu_unlock(&calld->mu_state); |
|
|
|
|
handle_op_after_cancellation(elem, &waiting_op); |
|
|
|
|
handle_op_after_cancellation(elem, op); |
|
|
|
|
} else { |
|
|
|
|
GPR_ASSERT((calld->s.waiting_op.send_ops == NULL) != |
|
|
|
|
(op->send_ops == NULL)); |
|
|
|
|
GPR_ASSERT((calld->s.waiting_op.recv_ops == NULL) != |
|
|
|
|
(op->recv_ops == NULL)); |
|
|
|
|
if (op->send_ops) { |
|
|
|
|
if (op->send_ops != NULL) { |
|
|
|
|
calld->s.waiting_op.send_ops = op->send_ops; |
|
|
|
|
calld->s.waiting_op.is_last_send = op->is_last_send; |
|
|
|
|
calld->s.waiting_op.on_done_send = op->on_done_send; |
|
|
|
|
calld->s.waiting_op.send_user_data = op->send_user_data; |
|
|
|
|
} |
|
|
|
|
if (op->recv_ops) { |
|
|
|
|
if (op->recv_ops != NULL) { |
|
|
|
|
calld->s.waiting_op.recv_ops = op->recv_ops; |
|
|
|
|
calld->s.waiting_op.recv_state = op->recv_state; |
|
|
|
|
calld->s.waiting_op.on_done_recv = op->on_done_recv; |
|
|
|
|
calld->s.waiting_op.recv_user_data = op->recv_user_data; |
|
|
|
|
} |
|
|
|
|
gpr_mu_unlock(&calld->mu_state); |
|
|
|
|
if (op->on_consumed) { |
|
|
|
|
op->on_consumed(op->on_consumed_user_data, 0); |
|
|
|
|
if (op->on_consumed != NULL) { |
|
|
|
|
op->on_consumed->cb(op->on_consumed->cb_arg, 0); |
|
|
|
|
} |
|
|
|
|
} |
|
|
|
|
break; |
|
|
|
@ -372,6 +368,55 @@ static void cc_start_transport_op(grpc_call_element *elem, |
|
|
|
|
#endif |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
static void update_state_locked(channel_data *chand) { |
|
|
|
|
|
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
static void cc_on_config_changed(void *arg, int iomgr_success) { |
|
|
|
|
channel_data *chand = arg; |
|
|
|
|
grpc_lb_policy *lb_policy = NULL; |
|
|
|
|
grpc_lb_policy *old_lb_policy; |
|
|
|
|
grpc_resolver *old_resolver; |
|
|
|
|
grpc_iomgr_closure *wakeup_closures = NULL; |
|
|
|
|
|
|
|
|
|
if (chand->incoming_configuration) { |
|
|
|
|
lb_policy = grpc_client_config_get_lb_policy(chand->incoming_configuration); |
|
|
|
|
grpc_lb_policy_ref(lb_policy); |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
grpc_client_config_unref(chand->incoming_configuration); |
|
|
|
|
chand->incoming_configuration = NULL; |
|
|
|
|
|
|
|
|
|
gpr_mu_lock(&chand->mu_config); |
|
|
|
|
old_lb_policy = chand->lb_policy; |
|
|
|
|
chand->lb_policy = lb_policy; |
|
|
|
|
if (lb_policy != NULL) { |
|
|
|
|
wakeup_closures = chand->waiting_for_config_closures; |
|
|
|
|
chand->waiting_for_config_closures = NULL; |
|
|
|
|
} |
|
|
|
|
gpr_mu_unlock(&chand->mu_config); |
|
|
|
|
|
|
|
|
|
while (wakeup_closures) { |
|
|
|
|
grpc_iomgr_closure *next = wakeup_closures->next; |
|
|
|
|
grpc_iomgr_add_callback(wakeup_closures); |
|
|
|
|
wakeup_closures = next; |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
grpc_lb_policy_unref(old_lb_policy); |
|
|
|
|
|
|
|
|
|
if (iomgr_success) { |
|
|
|
|
grpc_resolver_next(chand->resolver, &chand->incoming_configuration, &chand->on_config_changed); |
|
|
|
|
} else { |
|
|
|
|
gpr_mu_lock(&chand->mu_config); |
|
|
|
|
old_resolver = chand->resolver; |
|
|
|
|
chand->resolver = NULL; |
|
|
|
|
update_state_locked(chand); |
|
|
|
|
gpr_mu_unlock(&chand->mu_config); |
|
|
|
|
grpc_resolver_unref(old_resolver); |
|
|
|
|
} |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
#if 0 |
|
|
|
|
static void channel_op(grpc_channel_element *elem, |
|
|
|
|
grpc_channel_element *from_elem, grpc_channel_op *op) { |
|
|
|
|
channel_data *chand = elem->channel_data; |
|
|
|
@ -451,6 +496,9 @@ static void channel_op(grpc_channel_element *elem, |
|
|
|
|
break; |
|
|
|
|
} |
|
|
|
|
} |
|
|
|
|
#endif |
|
|
|
|
|
|
|
|
|
static void cc_start_transport_op(grpc_channel_element *elem, grpc_transport_op *op) {} |
|
|
|
|
|
|
|
|
|
/* Constructor for call_data */ |
|
|
|
|
static void init_call_elem(grpc_call_element *elem, |
|
|
|
@ -471,26 +519,28 @@ static void init_call_elem(grpc_call_element *elem, |
|
|
|
|
/* Destructor for call_data */ |
|
|
|
|
static void destroy_call_elem(grpc_call_element *elem) { |
|
|
|
|
call_data *calld = elem->call_data; |
|
|
|
|
channel_data *chand = elem->channel_data; |
|
|
|
|
grpc_subchannel_call *subchannel_call; |
|
|
|
|
|
|
|
|
|
/* if the call got activated, we need to destroy the child stack also, and
|
|
|
|
|
remove it from the in-flight requests tracked by the child_entry we |
|
|
|
|
picked */ |
|
|
|
|
gpr_mu_lock(&chand->mu); |
|
|
|
|
gpr_mu_lock(&calld->mu_state); |
|
|
|
|
switch (calld->state) { |
|
|
|
|
case CALL_ACTIVE: |
|
|
|
|
gpr_mu_unlock(&chand->mu); |
|
|
|
|
grpc_child_call_destroy(calld->s.active.child_call); |
|
|
|
|
subchannel_call = calld->s.active.subchannel_call; |
|
|
|
|
gpr_mu_unlock(&calld->mu_state); |
|
|
|
|
grpc_subchannel_call_unref(subchannel_call); |
|
|
|
|
break; |
|
|
|
|
case CALL_WAITING: |
|
|
|
|
remove_waiting_child(chand, calld); |
|
|
|
|
gpr_mu_unlock(&chand->mu); |
|
|
|
|
case CALL_CREATED: |
|
|
|
|
case CALL_CANCELLED: |
|
|
|
|
gpr_mu_unlock(&calld->mu_state); |
|
|
|
|
break; |
|
|
|
|
default: |
|
|
|
|
gpr_mu_unlock(&chand->mu); |
|
|
|
|
case CALL_WAITING_FOR_PICK: |
|
|
|
|
case CALL_WAITING_FOR_CONFIG: |
|
|
|
|
gpr_log(GPR_ERROR, "should never reach here"); |
|
|
|
|
abort(); |
|
|
|
|
break; |
|
|
|
|
} |
|
|
|
|
GPR_ASSERT(calld->state != CALL_WAITING); |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
/* Constructor for channel_data */ |
|
|
|
@ -504,41 +554,32 @@ static void init_channel_elem(grpc_channel_element *elem, |
|
|
|
|
GPR_ASSERT(is_last); |
|
|
|
|
GPR_ASSERT(elem->filter == &grpc_client_channel_filter); |
|
|
|
|
|
|
|
|
|
gpr_mu_init(&chand->mu); |
|
|
|
|
chand->active_child = NULL; |
|
|
|
|
chand->waiting_children = NULL; |
|
|
|
|
chand->waiting_child_count = 0; |
|
|
|
|
chand->waiting_child_capacity = 0; |
|
|
|
|
chand->transport_setup = NULL; |
|
|
|
|
chand->transport_setup_initiated = 0; |
|
|
|
|
chand->args = grpc_channel_args_copy(args); |
|
|
|
|
gpr_mu_init(&chand->mu_config); |
|
|
|
|
chand->resolver = NULL; |
|
|
|
|
chand->mdctx = metadata_context; |
|
|
|
|
grpc_iomgr_closure_init(&chand->on_config_changed, cc_on_config_changed, chand); |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
/* Destructor for channel_data */ |
|
|
|
|
static void destroy_channel_elem(grpc_channel_element *elem) { |
|
|
|
|
channel_data *chand = elem->channel_data; |
|
|
|
|
|
|
|
|
|
grpc_transport_setup_cancel(chand->transport_setup); |
|
|
|
|
|
|
|
|
|
if (chand->active_child) { |
|
|
|
|
grpc_child_channel_destroy(chand->active_child, 1); |
|
|
|
|
chand->active_child = NULL; |
|
|
|
|
if (chand->resolver) { |
|
|
|
|
grpc_resolver_unref(chand->resolver); |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
grpc_channel_args_destroy(chand->args); |
|
|
|
|
|
|
|
|
|
gpr_mu_destroy(&chand->mu); |
|
|
|
|
GPR_ASSERT(chand->waiting_child_count == 0); |
|
|
|
|
gpr_free(chand->waiting_children); |
|
|
|
|
if (chand->lb_policy) { |
|
|
|
|
grpc_lb_policy_unref(chand->lb_policy); |
|
|
|
|
} |
|
|
|
|
gpr_mu_destroy(&chand->mu_config); |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
const grpc_channel_filter grpc_client_channel_filter = { |
|
|
|
|
cc_start_transport_op, channel_op, sizeof(call_data), |
|
|
|
|
cc_start_transport_stream_op, cc_start_transport_op, sizeof(call_data), |
|
|
|
|
init_call_elem, destroy_call_elem, sizeof(channel_data), |
|
|
|
|
init_channel_elem, destroy_channel_elem, "client-channel", |
|
|
|
|
}; |
|
|
|
|
|
|
|
|
|
#if 0 |
|
|
|
|
grpc_transport_setup_result grpc_client_channel_transport_setup_complete( |
|
|
|
|
grpc_channel_stack *channel_stack, grpc_transport *transport, |
|
|
|
|
grpc_channel_filter const **channel_filters, size_t num_channel_filters, |
|
|
|
@ -620,6 +661,7 @@ grpc_transport_setup_result grpc_client_channel_transport_setup_complete( |
|
|
|
|
|
|
|
|
|
return result; |
|
|
|
|
} |
|
|
|
|
#endif |
|
|
|
|
|
|
|
|
|
void grpc_client_channel_set_resolver(grpc_channel_stack *channel_stack, |
|
|
|
|
grpc_resolver *resolver) { |
|
|
|
@ -628,5 +670,6 @@ void grpc_client_channel_set_resolver(grpc_channel_stack *channel_stack, |
|
|
|
|
channel_data *chand = elem->channel_data; |
|
|
|
|
GPR_ASSERT(!chand->resolver); |
|
|
|
|
chand->resolver = resolver; |
|
|
|
|
grpc_resolver_ref(resolver); |
|
|
|
|
grpc_resolver_next(resolver, &chand->incoming_configuration, &chand->on_config_changed); |
|
|
|
|
} |
|
|
|
|