|  | @@ -273,6 +273,12 @@ class ChannelData {
 | 
	
		
			
				|  |  |    bool received_first_resolver_result_ = false;
 | 
	
		
			
				|  |  |    // The number of SubchannelWrapper instances referencing a given Subchannel.
 | 
	
		
			
				|  |  |    Map<Subchannel*, int> subchannel_refcount_map_;
 | 
	
		
			
				|  |  | +  // The set of SubchannelWrappers that currently exist.
 | 
	
		
			
				|  |  | +  // No need to hold a ref, since the map is updated in the control-plane
 | 
	
		
			
				|  |  | +  // combiner when the SubchannelWrappers are created and destroyed.
 | 
	
		
			
				|  |  | +  // TODO(roth): We really want to use a set here, not a map.  Since we don't
 | 
	
		
			
				|  |  | +  // currently have a set implementation, we use a map and ignore the value.
 | 
	
		
			
				|  |  | +  Map<SubchannelWrapper*, bool> subchannel_wrappers_;
 | 
	
		
			
				|  |  |    // Pending ConnectedSubchannel updates for each SubchannelWrapper.
 | 
	
		
			
				|  |  |    // Updates are queued here in the control plane combiner and then applied
 | 
	
		
			
				|  |  |    // in the data plane combiner when the picker is updated.
 | 
	
	
		
			
				|  | @@ -799,14 +805,14 @@ class ChannelData::SubchannelWrapper : public SubchannelInterface {
 | 
	
		
			
				|  |  |      GRPC_CHANNEL_STACK_REF(chand_->owning_stack_, "SubchannelWrapper");
 | 
	
		
			
				|  |  |      auto* subchannel_node = subchannel_->channelz_node();
 | 
	
		
			
				|  |  |      if (subchannel_node != nullptr) {
 | 
	
		
			
				|  |  | -      intptr_t subchannel_uuid = subchannel_node->uuid();
 | 
	
		
			
				|  |  |        auto it = chand_->subchannel_refcount_map_.find(subchannel_);
 | 
	
		
			
				|  |  |        if (it == chand_->subchannel_refcount_map_.end()) {
 | 
	
		
			
				|  |  | -        chand_->channelz_node_->AddChildSubchannel(subchannel_uuid);
 | 
	
		
			
				|  |  | +        chand_->channelz_node_->AddChildSubchannel(subchannel_node->uuid());
 | 
	
		
			
				|  |  |          it = chand_->subchannel_refcount_map_.emplace(subchannel_, 0).first;
 | 
	
		
			
				|  |  |        }
 | 
	
		
			
				|  |  |        ++it->second;
 | 
	
		
			
				|  |  |      }
 | 
	
		
			
				|  |  | +    chand_->subchannel_wrappers_[this] = true;
 | 
	
		
			
				|  |  |    }
 | 
	
		
			
				|  |  |  
 | 
	
		
			
				|  |  |    ~SubchannelWrapper() {
 | 
	
	
		
			
				|  | @@ -815,14 +821,14 @@ class ChannelData::SubchannelWrapper : public SubchannelInterface {
 | 
	
		
			
				|  |  |                "chand=%p: destroying subchannel wrapper %p for subchannel %p",
 | 
	
		
			
				|  |  |                chand_, this, subchannel_);
 | 
	
		
			
				|  |  |      }
 | 
	
		
			
				|  |  | +    chand_->subchannel_wrappers_.erase(this);
 | 
	
		
			
				|  |  |      auto* subchannel_node = subchannel_->channelz_node();
 | 
	
		
			
				|  |  |      if (subchannel_node != nullptr) {
 | 
	
		
			
				|  |  | -      intptr_t subchannel_uuid = subchannel_node->uuid();
 | 
	
		
			
				|  |  |        auto it = chand_->subchannel_refcount_map_.find(subchannel_);
 | 
	
		
			
				|  |  |        GPR_ASSERT(it != chand_->subchannel_refcount_map_.end());
 | 
	
		
			
				|  |  |        --it->second;
 | 
	
		
			
				|  |  |        if (it->second == 0) {
 | 
	
		
			
				|  |  | -        chand_->channelz_node_->RemoveChildSubchannel(subchannel_uuid);
 | 
	
		
			
				|  |  | +        chand_->channelz_node_->RemoveChildSubchannel(subchannel_node->uuid());
 | 
	
		
			
				|  |  |          chand_->subchannel_refcount_map_.erase(it);
 | 
	
		
			
				|  |  |        }
 | 
	
		
			
				|  |  |      }
 | 
	
	
		
			
				|  | @@ -844,8 +850,9 @@ class ChannelData::SubchannelWrapper : public SubchannelInterface {
 | 
	
		
			
				|  |  |        UniquePtr<ConnectivityStateWatcherInterface> watcher) override {
 | 
	
		
			
				|  |  |      auto& watcher_wrapper = watcher_map_[watcher.get()];
 | 
	
		
			
				|  |  |      GPR_ASSERT(watcher_wrapper == nullptr);
 | 
	
		
			
				|  |  | -    watcher_wrapper = New<WatcherWrapper>(
 | 
	
		
			
				|  |  | -        std::move(watcher), Ref(DEBUG_LOCATION, "WatcherWrapper"));
 | 
	
		
			
				|  |  | +    watcher_wrapper = New<WatcherWrapper>(std::move(watcher),
 | 
	
		
			
				|  |  | +                                          Ref(DEBUG_LOCATION, "WatcherWrapper"),
 | 
	
		
			
				|  |  | +                                          initial_state);
 | 
	
		
			
				|  |  |      subchannel_->WatchConnectivityState(
 | 
	
		
			
				|  |  |          initial_state,
 | 
	
		
			
				|  |  |          UniquePtr<char>(gpr_strdup(health_check_service_name_.get())),
 | 
	
	
		
			
				|  | @@ -870,6 +877,40 @@ class ChannelData::SubchannelWrapper : public SubchannelInterface {
 | 
	
		
			
				|  |  |      return subchannel_->channel_args();
 | 
	
		
			
				|  |  |    }
 | 
	
		
			
				|  |  |  
 | 
	
		
			
				|  |  | +  void UpdateHealthCheckServiceName(UniquePtr<char> health_check_service_name) {
 | 
	
		
			
				|  |  | +    if (GRPC_TRACE_FLAG_ENABLED(grpc_client_channel_routing_trace)) {
 | 
	
		
			
				|  |  | +      gpr_log(GPR_INFO,
 | 
	
		
			
				|  |  | +              "chand=%p: subchannel wrapper %p: updating health check service "
 | 
	
		
			
				|  |  | +              "name from \"%s\" to \"%s\"",
 | 
	
		
			
				|  |  | +              chand_, this, health_check_service_name_.get(),
 | 
	
		
			
				|  |  | +              health_check_service_name.get());
 | 
	
		
			
				|  |  | +    }
 | 
	
		
			
				|  |  | +    for (auto& p : watcher_map_) {
 | 
	
		
			
				|  |  | +      WatcherWrapper*& watcher_wrapper = p.second;
 | 
	
		
			
				|  |  | +      // Cancel the current watcher and create a new one using the new
 | 
	
		
			
				|  |  | +      // health check service name.
 | 
	
		
			
				|  |  | +      // TODO(roth): If there is not already an existing health watch
 | 
	
		
			
				|  |  | +      // call for the new name, then the watcher will initially report
 | 
	
		
			
				|  |  | +      // state CONNECTING.  If the LB policy is currently reporting
 | 
	
		
			
				|  |  | +      // state READY, this may cause it to switch to CONNECTING before
 | 
	
		
			
				|  |  | +      // switching back to READY.  This could cause a small delay for
 | 
	
		
			
				|  |  | +      // RPCs being started on the channel.  If/when this becomes a
 | 
	
		
			
				|  |  | +      // problem, we may be able to handle it by waiting for the new
 | 
	
		
			
				|  |  | +      // watcher to report READY before we use it to replace the old one.
 | 
	
		
			
				|  |  | +      WatcherWrapper* replacement = watcher_wrapper->MakeReplacement();
 | 
	
		
			
				|  |  | +      subchannel_->CancelConnectivityStateWatch(
 | 
	
		
			
				|  |  | +          health_check_service_name_.get(), watcher_wrapper);
 | 
	
		
			
				|  |  | +      watcher_wrapper = replacement;
 | 
	
		
			
				|  |  | +      subchannel_->WatchConnectivityState(
 | 
	
		
			
				|  |  | +          replacement->last_seen_state(),
 | 
	
		
			
				|  |  | +          UniquePtr<char>(gpr_strdup(health_check_service_name.get())),
 | 
	
		
			
				|  |  | +          OrphanablePtr<Subchannel::ConnectivityStateWatcherInterface>(
 | 
	
		
			
				|  |  | +              replacement));
 | 
	
		
			
				|  |  | +    }
 | 
	
		
			
				|  |  | +    // Save the new health check service name.
 | 
	
		
			
				|  |  | +    health_check_service_name_ = std::move(health_check_service_name);
 | 
	
		
			
				|  |  | +  }
 | 
	
		
			
				|  |  | +
 | 
	
		
			
				|  |  |    // Caller must be holding the control-plane combiner.
 | 
	
		
			
				|  |  |    ConnectedSubchannel* connected_subchannel() const {
 | 
	
		
			
				|  |  |      return connected_subchannel_.get();
 | 
	
	
		
			
				|  | @@ -904,8 +945,11 @@ class ChannelData::SubchannelWrapper : public SubchannelInterface {
 | 
	
		
			
				|  |  |      WatcherWrapper(
 | 
	
		
			
				|  |  |          UniquePtr<SubchannelInterface::ConnectivityStateWatcherInterface>
 | 
	
		
			
				|  |  |              watcher,
 | 
	
		
			
				|  |  | -        RefCountedPtr<SubchannelWrapper> parent)
 | 
	
		
			
				|  |  | -        : watcher_(std::move(watcher)), parent_(std::move(parent)) {}
 | 
	
		
			
				|  |  | +        RefCountedPtr<SubchannelWrapper> parent,
 | 
	
		
			
				|  |  | +        grpc_connectivity_state initial_state)
 | 
	
		
			
				|  |  | +        : watcher_(std::move(watcher)),
 | 
	
		
			
				|  |  | +          parent_(std::move(parent)),
 | 
	
		
			
				|  |  | +          last_seen_state_(initial_state) {}
 | 
	
		
			
				|  |  |  
 | 
	
		
			
				|  |  |      ~WatcherWrapper() { parent_.reset(DEBUG_LOCATION, "WatcherWrapper"); }
 | 
	
		
			
				|  |  |  
 | 
	
	
		
			
				|  | @@ -928,9 +972,21 @@ class ChannelData::SubchannelWrapper : public SubchannelInterface {
 | 
	
		
			
				|  |  |      }
 | 
	
		
			
				|  |  |  
 | 
	
		
			
				|  |  |      grpc_pollset_set* interested_parties() override {
 | 
	
		
			
				|  |  | -      return watcher_->interested_parties();
 | 
	
		
			
				|  |  | +      SubchannelInterface::ConnectivityStateWatcherInterface* watcher =
 | 
	
		
			
				|  |  | +          watcher_.get();
 | 
	
		
			
				|  |  | +      if (watcher_ == nullptr) watcher = replacement_->watcher_.get();
 | 
	
		
			
				|  |  | +      return watcher->interested_parties();
 | 
	
		
			
				|  |  |      }
 | 
	
		
			
				|  |  |  
 | 
	
		
			
				|  |  | +    WatcherWrapper* MakeReplacement() {
 | 
	
		
			
				|  |  | +      auto* replacement =
 | 
	
		
			
				|  |  | +          New<WatcherWrapper>(std::move(watcher_), parent_, last_seen_state_);
 | 
	
		
			
				|  |  | +      replacement_ = replacement;
 | 
	
		
			
				|  |  | +      return replacement;
 | 
	
		
			
				|  |  | +    }
 | 
	
		
			
				|  |  | +
 | 
	
		
			
				|  |  | +    grpc_connectivity_state last_seen_state() const { return last_seen_state_; }
 | 
	
		
			
				|  |  | +
 | 
	
		
			
				|  |  |     private:
 | 
	
		
			
				|  |  |      class Updater {
 | 
	
		
			
				|  |  |       public:
 | 
	
	
		
			
				|  | @@ -954,12 +1010,17 @@ class ChannelData::SubchannelWrapper : public SubchannelInterface {
 | 
	
		
			
				|  |  |            gpr_log(GPR_INFO,
 | 
	
		
			
				|  |  |                    "chand=%p: processing connectivity change in combiner "
 | 
	
		
			
				|  |  |                    "for subchannel wrapper %p subchannel %p "
 | 
	
		
			
				|  |  | -                  "(connected_subchannel=%p state=%s)",
 | 
	
		
			
				|  |  | +                  "(connected_subchannel=%p state=%s): watcher=%p",
 | 
	
		
			
				|  |  |                    self->parent_->parent_->chand_, self->parent_->parent_.get(),
 | 
	
		
			
				|  |  |                    self->parent_->parent_->subchannel_,
 | 
	
		
			
				|  |  |                    self->connected_subchannel_.get(),
 | 
	
		
			
				|  |  | -                  grpc_connectivity_state_name(self->state_));
 | 
	
		
			
				|  |  | +                  grpc_connectivity_state_name(self->state_),
 | 
	
		
			
				|  |  | +                  self->parent_->watcher_.get());
 | 
	
		
			
				|  |  |          }
 | 
	
		
			
				|  |  | +        // Ignore update if the parent WatcherWrapper has been replaced
 | 
	
		
			
				|  |  | +        // since this callback was scheduled.
 | 
	
		
			
				|  |  | +        if (self->parent_->watcher_ == nullptr) return;
 | 
	
		
			
				|  |  | +        self->parent_->last_seen_state_ = self->state_;
 | 
	
		
			
				|  |  |          self->parent_->parent_->MaybeUpdateConnectedSubchannel(
 | 
	
		
			
				|  |  |              std::move(self->connected_subchannel_));
 | 
	
		
			
				|  |  |          self->parent_->watcher_->OnConnectivityStateChange(self->state_);
 | 
	
	
		
			
				|  | @@ -974,6 +1035,8 @@ class ChannelData::SubchannelWrapper : public SubchannelInterface {
 | 
	
		
			
				|  |  |  
 | 
	
		
			
				|  |  |      UniquePtr<SubchannelInterface::ConnectivityStateWatcherInterface> watcher_;
 | 
	
		
			
				|  |  |      RefCountedPtr<SubchannelWrapper> parent_;
 | 
	
		
			
				|  |  | +    grpc_connectivity_state last_seen_state_;
 | 
	
		
			
				|  |  | +    WatcherWrapper* replacement_ = nullptr;
 | 
	
		
			
				|  |  |    };
 | 
	
		
			
				|  |  |  
 | 
	
		
			
				|  |  |    void MaybeUpdateConnectedSubchannel(
 | 
	
	
		
			
				|  | @@ -1655,6 +1718,11 @@ bool ChannelData::ProcessResolverResultLocked(
 | 
	
		
			
				|  |  |      } else {
 | 
	
		
			
				|  |  |        chand->health_check_service_name_.reset();
 | 
	
		
			
				|  |  |      }
 | 
	
		
			
				|  |  | +    // Update health check service name used by existing subchannel wrappers.
 | 
	
		
			
				|  |  | +    for (const auto& p : chand->subchannel_wrappers_) {
 | 
	
		
			
				|  |  | +      p.first->UpdateHealthCheckServiceName(
 | 
	
		
			
				|  |  | +          UniquePtr<char>(gpr_strdup(chand->health_check_service_name_.get())));
 | 
	
		
			
				|  |  | +    }
 | 
	
		
			
				|  |  |      // Save service config.
 | 
	
		
			
				|  |  |      chand->saved_service_config_ = std::move(service_config);
 | 
	
		
			
				|  |  |    }
 |