|  | @@ -80,6 +80,11 @@ class PickFirst : public LoadBalancingPolicy {
 | 
	
		
			
				|  |  |  
 | 
	
		
			
				|  |  |      void ProcessConnectivityChangeLocked(
 | 
	
		
			
				|  |  |          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
 | 
	
	
		
			
				|  | @@ -247,7 +252,8 @@ void PickFirst::StartPickingLocked() {
 | 
	
		
			
				|  |  |    if (subchannel_list_ != nullptr) {
 | 
	
		
			
				|  |  |      for (size_t i = 0; i < subchannel_list_->num_subchannels(); ++i) {
 | 
	
		
			
				|  |  |        if (subchannel_list_->subchannel(i)->subchannel() != nullptr) {
 | 
	
		
			
				|  |  | -        subchannel_list_->subchannel(i)->StartConnectivityWatchLocked();
 | 
	
		
			
				|  |  | +        subchannel_list_->subchannel(i)
 | 
	
		
			
				|  |  | +            ->CheckConnectivityStateAndStartWatchingLocked();
 | 
	
		
			
				|  |  |          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
 | 
	
		
			
				|  |  |      // subchannel in the new list.
 | 
	
		
			
				|  |  |      if (started_picking_) {
 | 
	
		
			
				|  |  | -      subchannel_list_->subchannel(0)->StartConnectivityWatchLocked();
 | 
	
		
			
				|  |  | +      subchannel_list_->subchannel(0)
 | 
	
		
			
				|  |  | +          ->CheckConnectivityStateAndStartWatchingLocked();
 | 
	
		
			
				|  |  |      }
 | 
	
		
			
				|  |  |    } else {
 | 
	
		
			
				|  |  |      // We do have a selected subchannel.
 | 
	
	
		
			
				|  | @@ -440,7 +447,7 @@ void PickFirst::UpdateLocked(const grpc_channel_args& args) {
 | 
	
		
			
				|  |  |      // subchannel in the new list.
 | 
	
		
			
				|  |  |      if (started_picking_) {
 | 
	
		
			
				|  |  |        latest_pending_subchannel_list_->subchannel(0)
 | 
	
		
			
				|  |  | -          ->StartConnectivityWatchLocked();
 | 
	
		
			
				|  |  | +          ->CheckConnectivityStateAndStartWatchingLocked();
 | 
	
		
			
				|  |  |      }
 | 
	
		
			
				|  |  |    }
 | 
	
		
			
				|  |  |  }
 | 
	
	
		
			
				|  | @@ -519,41 +526,7 @@ void PickFirst::PickFirstSubchannelData::ProcessConnectivityChangeLocked(
 | 
	
		
			
				|  |  |    //    select in place of the current one.
 | 
	
		
			
				|  |  |    switch (connectivity_state) {
 | 
	
		
			
				|  |  |      case GRPC_CHANNEL_READY: {
 | 
	
		
			
				|  |  | -      // 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, "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);
 | 
	
		
			
				|  |  | -      }
 | 
	
		
			
				|  |  | +      ProcessUnselectedReadyLocked();
 | 
	
		
			
				|  |  |        // Renew notification.
 | 
	
		
			
				|  |  |        RenewConnectivityWatchLocked();
 | 
	
		
			
				|  |  |        break;
 | 
	
	
		
			
				|  | @@ -574,7 +547,7 @@ void PickFirst::PickFirstSubchannelData::ProcessConnectivityChangeLocked(
 | 
	
		
			
				|  |  |              &p->state_tracker_, GRPC_CHANNEL_TRANSIENT_FAILURE,
 | 
	
		
			
				|  |  |              GRPC_ERROR_REF(error), "exhausted_subchannels");
 | 
	
		
			
				|  |  |        }
 | 
	
		
			
				|  |  | -      sd->StartConnectivityWatchLocked();
 | 
	
		
			
				|  |  | +      sd->CheckConnectivityStateAndStartWatchingLocked();
 | 
	
		
			
				|  |  |        break;
 | 
	
		
			
				|  |  |      }
 | 
	
		
			
				|  |  |      case GRPC_CHANNEL_CONNECTING:
 | 
	
	
		
			
				|  | @@ -595,6 +568,67 @@ void PickFirst::PickFirstSubchannelData::ProcessConnectivityChangeLocked(
 | 
	
		
			
				|  |  |    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
 | 
	
		
			
				|  |  |  //
 |