Unref unselected subchannels in Pick First.

pull/19357/head
Qiancheng Zhao 6 years ago
parent 4d5f32ed2d
commit a75acbb6ae
  1. 117
      src/core/ext/filters/client_channel/lb_policy/pick_first/pick_first.cc

@ -128,6 +128,10 @@ class PickFirst : public LoadBalancingPolicy {
void ShutdownLocked() override; void ShutdownLocked() override;
void AttemptToConnectUsingLatestUpdateArgsLocked();
// Lateset update args.
UpdateArgs latest_update_args_;
// All our subchannels. // All our subchannels.
OrphanablePtr<PickFirstSubchannelList> subchannel_list_; OrphanablePtr<PickFirstSubchannelList> subchannel_list_;
// Latest pending subchannel list. // Latest pending subchannel list.
@ -167,18 +171,7 @@ void PickFirst::ExitIdleLocked() {
if (shutdown_) return; if (shutdown_) return;
if (idle_) { if (idle_) {
idle_ = false; idle_ = false;
if (subchannel_list_ == nullptr || AttemptToConnectUsingLatestUpdateArgsLocked();
subchannel_list_->num_subchannels() == 0) {
grpc_error* error = grpc_error_set_int(
GRPC_ERROR_CREATE_FROM_STATIC_STRING("No addresses to connect to"),
GRPC_ERROR_INT_GRPC_STATUS, GRPC_STATUS_UNAVAILABLE);
channel_control_helper()->UpdateState(
GRPC_CHANNEL_TRANSIENT_FAILURE,
UniquePtr<SubchannelPicker>(New<TransientFailurePicker>(error)));
} else {
subchannel_list_->subchannel(0)
->CheckConnectivityStateAndStartWatchingLocked();
}
} }
} }
@ -189,36 +182,26 @@ void PickFirst::ResetBackoffLocked() {
} }
} }
void PickFirst::UpdateLocked(UpdateArgs args) { void PickFirst::AttemptToConnectUsingLatestUpdateArgsLocked() {
if (GRPC_TRACE_FLAG_ENABLED(grpc_lb_pick_first_trace)) { // Create a subchannel list from the latest_update_args_.
gpr_log(GPR_INFO,
"Pick First %p received update with %" PRIuPTR " addresses", this,
args.addresses.size());
}
grpc_arg new_arg = grpc_channel_arg_integer_create(
const_cast<char*>(GRPC_ARG_INHIBIT_HEALTH_CHECKING), 1);
grpc_channel_args* new_args =
grpc_channel_args_copy_and_add(args.args, &new_arg, 1);
auto subchannel_list = MakeOrphanable<PickFirstSubchannelList>( auto subchannel_list = MakeOrphanable<PickFirstSubchannelList>(
this, &grpc_lb_pick_first_trace, args.addresses, combiner(), *new_args); this, &grpc_lb_pick_first_trace, latest_update_args_.addresses,
grpc_channel_args_destroy(new_args); combiner(), *latest_update_args_.args);
// Empty update or no valid subchannels.
if (subchannel_list->num_subchannels() == 0) { if (subchannel_list->num_subchannels() == 0) {
// Empty update or no valid subchannels. Unsubscribe from all current // Unsubscribe from all current subchannels.
// subchannels.
subchannel_list_ = std::move(subchannel_list); // Empty list. subchannel_list_ = std::move(subchannel_list); // Empty list.
selected_ = nullptr; selected_ = nullptr;
// If not idle, put the channel in TRANSIENT_FAILURE. // If not idle, put the channel in TRANSIENT_FAILURE.
// (If we are idle, then this will happen in ExitIdleLocked() if we // (If we are idle, then this will happen in ExitIdleLocked() if we
// haven't gotten a non-empty update by the time the application tries // haven't gotten a non-empty update by the time the application tries
// to start a new call.) // to start a new call.)
if (!idle_) { grpc_error* error =
grpc_error* error = grpc_error_set_int( grpc_error_set_int(GRPC_ERROR_CREATE_FROM_STATIC_STRING("Empty update"),
GRPC_ERROR_CREATE_FROM_STATIC_STRING("Empty update"), GRPC_ERROR_INT_GRPC_STATUS, GRPC_STATUS_UNAVAILABLE);
GRPC_ERROR_INT_GRPC_STATUS, GRPC_STATUS_UNAVAILABLE); channel_control_helper()->UpdateState(
channel_control_helper()->UpdateState( GRPC_CHANNEL_TRANSIENT_FAILURE,
GRPC_CHANNEL_TRANSIENT_FAILURE, UniquePtr<SubchannelPicker>(New<TransientFailurePicker>(error)));
UniquePtr<SubchannelPicker>(New<TransientFailurePicker>(error)));
}
return; return;
} }
// If one of the subchannels in the new list is already in state // If one of the subchannels in the new list is already in state
@ -226,8 +209,6 @@ void PickFirst::UpdateLocked(UpdateArgs args) {
// currently selected subchannel is also present in the update. It // currently selected subchannel is also present in the update. It
// can also happen if one of the subchannels in the update is already // can also happen if one of the subchannels in the update is already
// in the global subchannel pool because it's in use by another channel. // in the global subchannel pool because it's in use by another channel.
// TODO(roth): If we're in IDLE state, we should probably defer this
// check and instead do it in ExitIdleLocked().
for (size_t i = 0; i < subchannel_list->num_subchannels(); ++i) { for (size_t i = 0; i < subchannel_list->num_subchannels(); ++i) {
PickFirstSubchannelData* sd = subchannel_list->subchannel(i); PickFirstSubchannelData* sd = subchannel_list->subchannel(i);
grpc_connectivity_state state = sd->CheckConnectivityStateLocked(); grpc_connectivity_state state = sd->CheckConnectivityStateLocked();
@ -239,10 +220,6 @@ void PickFirst::UpdateLocked(UpdateArgs args) {
// not have contained the currently selected subchannel), drop // not have contained the currently selected subchannel), drop
// it, so that it doesn't override what we've done here. // it, so that it doesn't override what we've done here.
latest_pending_subchannel_list_.reset(); latest_pending_subchannel_list_.reset();
// Make sure that subsequent calls to ExitIdleLocked() don't cause
// us to start watching a subchannel other than the one we've
// selected.
idle_ = false;
return; return;
} }
} }
@ -252,13 +229,11 @@ void PickFirst::UpdateLocked(UpdateArgs args) {
subchannel_list_ = std::move(subchannel_list); subchannel_list_ = std::move(subchannel_list);
// If we're not in IDLE state, start trying to connect to the first // If we're not in IDLE state, start trying to connect to the first
// subchannel in the new list. // subchannel in the new list.
if (!idle_) { // Note: No need to use CheckConnectivityStateAndStartWatchingLocked()
// Note: No need to use CheckConnectivityStateAndStartWatchingLocked() // here, since we've already checked the initial connectivity
// here, since we've already checked the initial connectivity // state of all subchannels above.
// state of all subchannels above. subchannel_list_->subchannel(0)->StartConnectivityWatchLocked();
subchannel_list_->subchannel(0)->StartConnectivityWatchLocked(); subchannel_list_->subchannel(0)->subchannel()->AttemptToConnect();
subchannel_list_->subchannel(0)->subchannel()->AttemptToConnect();
}
} else { } else {
// We do have a selected subchannel (which means it's READY), so keep // We do have a selected subchannel (which means it's READY), so keep
// using it until one of the subchannels in the new list reports READY. // using it until one of the subchannels in the new list reports READY.
@ -274,16 +249,35 @@ void PickFirst::UpdateLocked(UpdateArgs args) {
latest_pending_subchannel_list_ = std::move(subchannel_list); latest_pending_subchannel_list_ = std::move(subchannel_list);
// If we're not in IDLE state, start trying to connect to the first // If we're not in IDLE state, start trying to connect to the first
// subchannel in the new list. // subchannel in the new list.
if (!idle_) { // Note: No need to use CheckConnectivityStateAndStartWatchingLocked()
// Note: No need to use CheckConnectivityStateAndStartWatchingLocked() // here, since we've already checked the initial connectivity
// here, since we've already checked the initial connectivity // state of all subchannels above.
// state of all subchannels above. latest_pending_subchannel_list_->subchannel(0)
latest_pending_subchannel_list_->subchannel(0) ->StartConnectivityWatchLocked();
->StartConnectivityWatchLocked(); latest_pending_subchannel_list_->subchannel(0)
latest_pending_subchannel_list_->subchannel(0) ->subchannel()
->subchannel() ->AttemptToConnect();
->AttemptToConnect(); }
} }
void PickFirst::UpdateLocked(UpdateArgs args) {
if (GRPC_TRACE_FLAG_ENABLED(grpc_lb_pick_first_trace)) {
gpr_log(GPR_INFO,
"Pick First %p received update with %" PRIuPTR " addresses", this,
args.addresses.size());
}
// Update the latest_update_args_
grpc_arg new_arg = grpc_channel_arg_integer_create(
const_cast<char*>(GRPC_ARG_INHIBIT_HEALTH_CHECKING), 1);
const grpc_channel_args* new_args =
grpc_channel_args_copy_and_add(args.args, &new_arg, 1);
GPR_SWAP(const grpc_channel_args*, new_args, args.args);
grpc_channel_args_destroy(new_args);
latest_update_args_ = std::move(args);
// If we are not in idle, start connection attempt immediately.
// Otherwise, we defer the attempt into ExitIdleLocked().
if (!idle_) {
AttemptToConnectUsingLatestUpdateArgsLocked();
} }
} }
@ -338,10 +332,12 @@ void PickFirst::PickFirstSubchannelData::ProcessConnectivityChangeLocked(
// also set the channel state to IDLE. The reason is that if the new // also set the channel state to IDLE. The reason is that if the new
// state is TRANSIENT_FAILURE due to a GOAWAY reception we don't want // state is TRANSIENT_FAILURE due to a GOAWAY reception we don't want
// to connect to the re-resolved backends until we leave IDLE state. // to connect to the re-resolved backends until we leave IDLE state.
// TODO(qianchengz): We may want to request re-resolution in
// ExitIdleLocked().
p->idle_ = true; p->idle_ = true;
p->channel_control_helper()->RequestReresolution(); p->channel_control_helper()->RequestReresolution();
p->selected_ = nullptr; p->selected_ = nullptr;
CancelConnectivityWatchLocked("selected subchannel failed; going IDLE"); p->subchannel_list_.reset();
p->channel_control_helper()->UpdateState( p->channel_control_helper()->UpdateState(
GRPC_CHANNEL_IDLE, UniquePtr<SubchannelPicker>(New<QueuePicker>( GRPC_CHANNEL_IDLE, UniquePtr<SubchannelPicker>(New<QueuePicker>(
p->Ref(DEBUG_LOCATION, "QueuePicker")))); p->Ref(DEBUG_LOCATION, "QueuePicker"))));
@ -454,6 +450,11 @@ void PickFirst::PickFirstSubchannelData::ProcessUnselectedReadyLocked() {
if (GRPC_TRACE_FLAG_ENABLED(grpc_lb_pick_first_trace)) { if (GRPC_TRACE_FLAG_ENABLED(grpc_lb_pick_first_trace)) {
gpr_log(GPR_INFO, "Pick First %p selected subchannel %p", p, subchannel()); gpr_log(GPR_INFO, "Pick First %p selected subchannel %p", p, subchannel());
} }
for (size_t i = 0; i < subchannel_list()->num_subchannels(); ++i) {
if (i != Index()) {
subchannel_list()->subchannel(i)->ShutdownLocked();
}
}
} }
void PickFirst::PickFirstSubchannelData:: void PickFirst::PickFirstSubchannelData::

Loading…
Cancel
Save