|
|
@ -80,6 +80,11 @@ class PickFirst : public LoadBalancingPolicy { |
|
|
|
|
|
|
|
|
|
|
|
void ProcessConnectivityChangeLocked( |
|
|
|
void ProcessConnectivityChangeLocked( |
|
|
|
grpc_connectivity_state connectivity_state, grpc_error* error) override; |
|
|
|
grpc_connectivity_state connectivity_state, grpc_error* error) override; |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
// Processes the connectivity change to READY for an unselected subchannel.
|
|
|
|
|
|
|
|
void ProcessUnselectedReadyLocked(); |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
void CheckConnectivityStateAndStartWatchingLocked(); |
|
|
|
}; |
|
|
|
}; |
|
|
|
|
|
|
|
|
|
|
|
class PickFirstSubchannelList |
|
|
|
class PickFirstSubchannelList |
|
|
@ -247,7 +252,8 @@ void PickFirst::StartPickingLocked() { |
|
|
|
if (subchannel_list_ != nullptr) { |
|
|
|
if (subchannel_list_ != nullptr) { |
|
|
|
for (size_t i = 0; i < subchannel_list_->num_subchannels(); ++i) { |
|
|
|
for (size_t i = 0; i < subchannel_list_->num_subchannels(); ++i) { |
|
|
|
if (subchannel_list_->subchannel(i)->subchannel() != nullptr) { |
|
|
|
if (subchannel_list_->subchannel(i)->subchannel() != nullptr) { |
|
|
|
subchannel_list_->subchannel(i)->StartConnectivityWatchLocked(); |
|
|
|
subchannel_list_->subchannel(i) |
|
|
|
|
|
|
|
->CheckConnectivityStateAndStartWatchingLocked(); |
|
|
|
break; |
|
|
|
break; |
|
|
|
} |
|
|
|
} |
|
|
|
} |
|
|
|
} |
|
|
@ -386,7 +392,8 @@ void PickFirst::UpdateLocked(const grpc_channel_args& args) { |
|
|
|
// If we've started picking, start trying to connect to the first
|
|
|
|
// If we've started picking, start trying to connect to the first
|
|
|
|
// subchannel in the new list.
|
|
|
|
// subchannel in the new list.
|
|
|
|
if (started_picking_) { |
|
|
|
if (started_picking_) { |
|
|
|
subchannel_list_->subchannel(0)->StartConnectivityWatchLocked(); |
|
|
|
subchannel_list_->subchannel(0) |
|
|
|
|
|
|
|
->CheckConnectivityStateAndStartWatchingLocked(); |
|
|
|
} |
|
|
|
} |
|
|
|
} else { |
|
|
|
} else { |
|
|
|
// We do have a selected subchannel.
|
|
|
|
// We do have a selected subchannel.
|
|
|
@ -440,7 +447,7 @@ void PickFirst::UpdateLocked(const grpc_channel_args& args) { |
|
|
|
// subchannel in the new list.
|
|
|
|
// subchannel in the new list.
|
|
|
|
if (started_picking_) { |
|
|
|
if (started_picking_) { |
|
|
|
latest_pending_subchannel_list_->subchannel(0) |
|
|
|
latest_pending_subchannel_list_->subchannel(0) |
|
|
|
->StartConnectivityWatchLocked(); |
|
|
|
->CheckConnectivityStateAndStartWatchingLocked(); |
|
|
|
} |
|
|
|
} |
|
|
|
} |
|
|
|
} |
|
|
|
} |
|
|
|
} |
|
|
@ -519,41 +526,7 @@ void PickFirst::PickFirstSubchannelData::ProcessConnectivityChangeLocked( |
|
|
|
// select in place of the current one.
|
|
|
|
// select in place of the current one.
|
|
|
|
switch (connectivity_state) { |
|
|
|
switch (connectivity_state) { |
|
|
|
case GRPC_CHANNEL_READY: { |
|
|
|
case GRPC_CHANNEL_READY: { |
|
|
|
// Case 2. Promote p->latest_pending_subchannel_list_ to
|
|
|
|
ProcessUnselectedReadyLocked(); |
|
|
|
// p->subchannel_list_.
|
|
|
|
|
|
|
|
if (subchannel_list() == p->latest_pending_subchannel_list_.get()) { |
|
|
|
|
|
|
|
if (grpc_lb_pick_first_trace.enabled()) { |
|
|
|
|
|
|
|
gpr_log(GPR_INFO, |
|
|
|
|
|
|
|
"Pick First %p promoting pending subchannel list %p to " |
|
|
|
|
|
|
|
"replace %p", |
|
|
|
|
|
|
|
p, p->latest_pending_subchannel_list_.get(), |
|
|
|
|
|
|
|
p->subchannel_list_.get()); |
|
|
|
|
|
|
|
} |
|
|
|
|
|
|
|
p->subchannel_list_ = std::move(p->latest_pending_subchannel_list_); |
|
|
|
|
|
|
|
} |
|
|
|
|
|
|
|
// Cases 1 and 2.
|
|
|
|
|
|
|
|
grpc_connectivity_state_set(&p->state_tracker_, GRPC_CHANNEL_READY, |
|
|
|
|
|
|
|
GRPC_ERROR_NONE, "connecting_ready"); |
|
|
|
|
|
|
|
p->selected_ = this; |
|
|
|
|
|
|
|
if (grpc_lb_pick_first_trace.enabled()) { |
|
|
|
|
|
|
|
gpr_log(GPR_INFO, "Pick First %p selected subchannel %p", p, |
|
|
|
|
|
|
|
subchannel()); |
|
|
|
|
|
|
|
} |
|
|
|
|
|
|
|
// Drop all other subchannels, since we are now connected.
|
|
|
|
|
|
|
|
p->DestroyUnselectedSubchannelsLocked(); |
|
|
|
|
|
|
|
// Update any calls that were waiting for a pick.
|
|
|
|
|
|
|
|
PickState* pick; |
|
|
|
|
|
|
|
while ((pick = p->pending_picks_)) { |
|
|
|
|
|
|
|
p->pending_picks_ = pick->next; |
|
|
|
|
|
|
|
pick->connected_subchannel = |
|
|
|
|
|
|
|
p->selected_->connected_subchannel()->Ref(); |
|
|
|
|
|
|
|
if (grpc_lb_pick_first_trace.enabled()) { |
|
|
|
|
|
|
|
gpr_log(GPR_INFO, |
|
|
|
|
|
|
|
"Servicing pending pick with selected subchannel %p", |
|
|
|
|
|
|
|
p->selected_->subchannel()); |
|
|
|
|
|
|
|
} |
|
|
|
|
|
|
|
GRPC_CLOSURE_SCHED(pick->on_complete, GRPC_ERROR_NONE); |
|
|
|
|
|
|
|
} |
|
|
|
|
|
|
|
// Renew notification.
|
|
|
|
// Renew notification.
|
|
|
|
RenewConnectivityWatchLocked(); |
|
|
|
RenewConnectivityWatchLocked(); |
|
|
|
break; |
|
|
|
break; |
|
|
@ -574,7 +547,7 @@ void PickFirst::PickFirstSubchannelData::ProcessConnectivityChangeLocked( |
|
|
|
&p->state_tracker_, GRPC_CHANNEL_TRANSIENT_FAILURE, |
|
|
|
&p->state_tracker_, GRPC_CHANNEL_TRANSIENT_FAILURE, |
|
|
|
GRPC_ERROR_REF(error), "exhausted_subchannels"); |
|
|
|
GRPC_ERROR_REF(error), "exhausted_subchannels"); |
|
|
|
} |
|
|
|
} |
|
|
|
sd->StartConnectivityWatchLocked(); |
|
|
|
sd->CheckConnectivityStateAndStartWatchingLocked(); |
|
|
|
break; |
|
|
|
break; |
|
|
|
} |
|
|
|
} |
|
|
|
case GRPC_CHANNEL_CONNECTING: |
|
|
|
case GRPC_CHANNEL_CONNECTING: |
|
|
@ -595,6 +568,67 @@ void PickFirst::PickFirstSubchannelData::ProcessConnectivityChangeLocked( |
|
|
|
GRPC_ERROR_UNREF(error); |
|
|
|
GRPC_ERROR_UNREF(error); |
|
|
|
} |
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
void PickFirst::PickFirstSubchannelData::ProcessUnselectedReadyLocked() { |
|
|
|
|
|
|
|
PickFirst* p = static_cast<PickFirst*>(subchannel_list()->policy()); |
|
|
|
|
|
|
|
// If we get here, there are two possible cases:
|
|
|
|
|
|
|
|
// 1. We do not currently have a selected subchannel, and the update is
|
|
|
|
|
|
|
|
// for a subchannel in p->subchannel_list_ that we're trying to
|
|
|
|
|
|
|
|
// connect to. The goal here is to find a subchannel that we can
|
|
|
|
|
|
|
|
// select.
|
|
|
|
|
|
|
|
// 2. We do currently have a selected subchannel, and the update is
|
|
|
|
|
|
|
|
// for a subchannel in p->latest_pending_subchannel_list_. The
|
|
|
|
|
|
|
|
// goal here is to find a subchannel from the update that we can
|
|
|
|
|
|
|
|
// select in place of the current one.
|
|
|
|
|
|
|
|
GPR_ASSERT(subchannel_list() == p->subchannel_list_.get() || |
|
|
|
|
|
|
|
subchannel_list() == p->latest_pending_subchannel_list_.get()); |
|
|
|
|
|
|
|
// Case 2. Promote p->latest_pending_subchannel_list_ to p->subchannel_list_.
|
|
|
|
|
|
|
|
if (subchannel_list() == p->latest_pending_subchannel_list_.get()) { |
|
|
|
|
|
|
|
if (grpc_lb_pick_first_trace.enabled()) { |
|
|
|
|
|
|
|
gpr_log(GPR_INFO, |
|
|
|
|
|
|
|
"Pick First %p promoting pending subchannel list %p to " |
|
|
|
|
|
|
|
"replace %p", |
|
|
|
|
|
|
|
p, p->latest_pending_subchannel_list_.get(), |
|
|
|
|
|
|
|
p->subchannel_list_.get()); |
|
|
|
|
|
|
|
} |
|
|
|
|
|
|
|
p->subchannel_list_ = std::move(p->latest_pending_subchannel_list_); |
|
|
|
|
|
|
|
} |
|
|
|
|
|
|
|
// Cases 1 and 2.
|
|
|
|
|
|
|
|
grpc_connectivity_state_set(&p->state_tracker_, GRPC_CHANNEL_READY, |
|
|
|
|
|
|
|
GRPC_ERROR_NONE, "subchannel_ready"); |
|
|
|
|
|
|
|
p->selected_ = this; |
|
|
|
|
|
|
|
if (grpc_lb_pick_first_trace.enabled()) { |
|
|
|
|
|
|
|
gpr_log(GPR_INFO, "Pick First %p selected subchannel %p", p, subchannel()); |
|
|
|
|
|
|
|
} |
|
|
|
|
|
|
|
// Drop all other subchannels, since we are now connected.
|
|
|
|
|
|
|
|
p->DestroyUnselectedSubchannelsLocked(); |
|
|
|
|
|
|
|
// Update any calls that were waiting for a pick.
|
|
|
|
|
|
|
|
PickState* pick; |
|
|
|
|
|
|
|
while ((pick = p->pending_picks_)) { |
|
|
|
|
|
|
|
p->pending_picks_ = pick->next; |
|
|
|
|
|
|
|
pick->connected_subchannel = p->selected_->connected_subchannel()->Ref(); |
|
|
|
|
|
|
|
if (grpc_lb_pick_first_trace.enabled()) { |
|
|
|
|
|
|
|
gpr_log(GPR_INFO, "Servicing pending pick with selected subchannel %p", |
|
|
|
|
|
|
|
p->selected_->subchannel()); |
|
|
|
|
|
|
|
} |
|
|
|
|
|
|
|
GRPC_CLOSURE_SCHED(pick->on_complete, GRPC_ERROR_NONE); |
|
|
|
|
|
|
|
} |
|
|
|
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
void PickFirst::PickFirstSubchannelData:: |
|
|
|
|
|
|
|
CheckConnectivityStateAndStartWatchingLocked() { |
|
|
|
|
|
|
|
PickFirst* p = static_cast<PickFirst*>(subchannel_list()->policy()); |
|
|
|
|
|
|
|
grpc_error* error = GRPC_ERROR_NONE; |
|
|
|
|
|
|
|
if (p->selected_ != this && |
|
|
|
|
|
|
|
CheckConnectivityStateLocked(&error) == GRPC_CHANNEL_READY) { |
|
|
|
|
|
|
|
// We must process the READY subchannel before we start watching it.
|
|
|
|
|
|
|
|
// Otherwise, we won't know it's READY because we will be waiting for its
|
|
|
|
|
|
|
|
// connectivity state to change from READY.
|
|
|
|
|
|
|
|
ProcessUnselectedReadyLocked(); |
|
|
|
|
|
|
|
} |
|
|
|
|
|
|
|
GRPC_ERROR_UNREF(error); |
|
|
|
|
|
|
|
StartConnectivityWatchLocked(); |
|
|
|
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
//
|
|
|
|
//
|
|
|
|
// factory
|
|
|
|
// factory
|
|
|
|
//
|
|
|
|
//
|
|
|
|