|  | @@ -50,7 +50,6 @@
 | 
	
		
			
				|  |  |  #include "src/core/lib/iomgr/sockaddr.h"
 | 
	
		
			
				|  |  |  #include "src/core/lib/iomgr/sockaddr_utils.h"
 | 
	
		
			
				|  |  |  #include "src/core/lib/iomgr/timer.h"
 | 
	
		
			
				|  |  | -#include "src/core/lib/iomgr/work_serializer.h"
 | 
	
		
			
				|  |  |  #include "src/core/lib/security/credentials/credentials.h"
 | 
	
		
			
				|  |  |  #include "src/core/lib/security/credentials/fake/fake_credentials.h"
 | 
	
		
			
				|  |  |  #include "src/core/lib/slice/slice_internal.h"
 | 
	
	
		
			
				|  | @@ -169,9 +168,11 @@ class XdsClient::ChannelState::AdsCallState
 | 
	
		
			
				|  |  |     private:
 | 
	
		
			
				|  |  |      static void OnTimer(void* arg, grpc_error* error) {
 | 
	
		
			
				|  |  |        ResourceState* self = static_cast<ResourceState*>(arg);
 | 
	
		
			
				|  |  | -      GRPC_ERROR_REF(error);  // ref owned by lambda
 | 
	
		
			
				|  |  | -      self->ads_calld_->xds_client()->work_serializer_->Run(
 | 
	
		
			
				|  |  | -          [self, error]() { self->OnTimerLocked(error); }, DEBUG_LOCATION);
 | 
	
		
			
				|  |  | +      {
 | 
	
		
			
				|  |  | +        MutexLock lock(&self->ads_calld_->xds_client()->mu_);
 | 
	
		
			
				|  |  | +        self->OnTimerLocked(GRPC_ERROR_REF(error));
 | 
	
		
			
				|  |  | +      }
 | 
	
		
			
				|  |  | +      self->Unref(DEBUG_LOCATION, "timer");
 | 
	
		
			
				|  |  |      }
 | 
	
		
			
				|  |  |  
 | 
	
		
			
				|  |  |      void OnTimerLocked(grpc_error* error) {
 | 
	
	
		
			
				|  | @@ -213,7 +214,6 @@ class XdsClient::ChannelState::AdsCallState
 | 
	
		
			
				|  |  |          GRPC_ERROR_UNREF(watcher_error);
 | 
	
		
			
				|  |  |        }
 | 
	
		
			
				|  |  |        ads_calld_.reset();
 | 
	
		
			
				|  |  | -      Unref(DEBUG_LOCATION, "timer");
 | 
	
		
			
				|  |  |        GRPC_ERROR_UNREF(error);
 | 
	
		
			
				|  |  |      }
 | 
	
		
			
				|  |  |  
 | 
	
	
		
			
				|  | @@ -250,7 +250,7 @@ class XdsClient::ChannelState::AdsCallState
 | 
	
		
			
				|  |  |    static void OnRequestSent(void* arg, grpc_error* error);
 | 
	
		
			
				|  |  |    void OnRequestSentLocked(grpc_error* error);
 | 
	
		
			
				|  |  |    static void OnResponseReceived(void* arg, grpc_error* error);
 | 
	
		
			
				|  |  | -  void OnResponseReceivedLocked();
 | 
	
		
			
				|  |  | +  bool OnResponseReceivedLocked();
 | 
	
		
			
				|  |  |    static void OnStatusReceived(void* arg, grpc_error* error);
 | 
	
		
			
				|  |  |    void OnStatusReceivedLocked(grpc_error* error);
 | 
	
		
			
				|  |  |  
 | 
	
	
		
			
				|  | @@ -327,10 +327,10 @@ class XdsClient::ChannelState::LrsCallState
 | 
	
		
			
				|  |  |     private:
 | 
	
		
			
				|  |  |      void ScheduleNextReportLocked();
 | 
	
		
			
				|  |  |      static void OnNextReportTimer(void* arg, grpc_error* error);
 | 
	
		
			
				|  |  | -    void OnNextReportTimerLocked(grpc_error* error);
 | 
	
		
			
				|  |  | +    bool OnNextReportTimerLocked(grpc_error* error);
 | 
	
		
			
				|  |  |      void SendReportLocked();
 | 
	
		
			
				|  |  |      static void OnReportDone(void* arg, grpc_error* error);
 | 
	
		
			
				|  |  | -    void OnReportDoneLocked(grpc_error* error);
 | 
	
		
			
				|  |  | +    bool OnReportDoneLocked(grpc_error* error);
 | 
	
		
			
				|  |  |  
 | 
	
		
			
				|  |  |      bool IsCurrentReporterOnCall() const {
 | 
	
		
			
				|  |  |        return this == parent_->reporter_.get();
 | 
	
	
		
			
				|  | @@ -352,7 +352,7 @@ class XdsClient::ChannelState::LrsCallState
 | 
	
		
			
				|  |  |    static void OnInitialRequestSent(void* arg, grpc_error* error);
 | 
	
		
			
				|  |  |    void OnInitialRequestSentLocked();
 | 
	
		
			
				|  |  |    static void OnResponseReceived(void* arg, grpc_error* error);
 | 
	
		
			
				|  |  | -  void OnResponseReceivedLocked();
 | 
	
		
			
				|  |  | +  bool OnResponseReceivedLocked();
 | 
	
		
			
				|  |  |    static void OnStatusReceived(void* arg, grpc_error* error);
 | 
	
		
			
				|  |  |    void OnStatusReceivedLocked(grpc_error* error);
 | 
	
		
			
				|  |  |  
 | 
	
	
		
			
				|  | @@ -397,13 +397,12 @@ class XdsClient::ChannelState::StateWatcher
 | 
	
		
			
				|  |  |      : public AsyncConnectivityStateWatcherInterface {
 | 
	
		
			
				|  |  |   public:
 | 
	
		
			
				|  |  |    explicit StateWatcher(RefCountedPtr<ChannelState> parent)
 | 
	
		
			
				|  |  | -      : AsyncConnectivityStateWatcherInterface(
 | 
	
		
			
				|  |  | -            parent->xds_client()->work_serializer_),
 | 
	
		
			
				|  |  | -        parent_(std::move(parent)) {}
 | 
	
		
			
				|  |  | +      : parent_(std::move(parent)) {}
 | 
	
		
			
				|  |  |  
 | 
	
		
			
				|  |  |   private:
 | 
	
		
			
				|  |  |    void OnConnectivityStateChange(grpc_connectivity_state new_state,
 | 
	
		
			
				|  |  |                                   const absl::Status& status) override {
 | 
	
		
			
				|  |  | +    MutexLock lock(&parent_->xds_client_->mu_);
 | 
	
		
			
				|  |  |      if (!parent_->shutting_down_ &&
 | 
	
		
			
				|  |  |          new_state == GRPC_CHANNEL_TRANSIENT_FAILURE) {
 | 
	
		
			
				|  |  |        // In TRANSIENT_FAILURE.  Notify all watchers of error.
 | 
	
	
		
			
				|  | @@ -411,8 +410,9 @@ class XdsClient::ChannelState::StateWatcher
 | 
	
		
			
				|  |  |                "[xds_client %p] xds channel in state:TRANSIENT_FAILURE "
 | 
	
		
			
				|  |  |                "status_message:(%s)",
 | 
	
		
			
				|  |  |                parent_->xds_client(), status.ToString().c_str());
 | 
	
		
			
				|  |  | -      parent_->xds_client()->NotifyOnError(GRPC_ERROR_CREATE_FROM_STATIC_STRING(
 | 
	
		
			
				|  |  | -          "xds channel in TRANSIENT_FAILURE"));
 | 
	
		
			
				|  |  | +      parent_->xds_client()->NotifyOnErrorLocked(
 | 
	
		
			
				|  |  | +          GRPC_ERROR_CREATE_FROM_STATIC_STRING(
 | 
	
		
			
				|  |  | +              "xds channel in TRANSIENT_FAILURE"));
 | 
	
		
			
				|  |  |      }
 | 
	
		
			
				|  |  |    }
 | 
	
		
			
				|  |  |  
 | 
	
	
		
			
				|  | @@ -655,9 +655,11 @@ template <typename T>
 | 
	
		
			
				|  |  |  void XdsClient::ChannelState::RetryableCall<T>::OnRetryTimer(
 | 
	
		
			
				|  |  |      void* arg, grpc_error* error) {
 | 
	
		
			
				|  |  |    RetryableCall* calld = static_cast<RetryableCall*>(arg);
 | 
	
		
			
				|  |  | -  GRPC_ERROR_REF(error);  // ref owned by lambda
 | 
	
		
			
				|  |  | -  calld->chand_->xds_client()->work_serializer_->Run(
 | 
	
		
			
				|  |  | -      [calld, error]() { calld->OnRetryTimerLocked(error); }, DEBUG_LOCATION);
 | 
	
		
			
				|  |  | +  {
 | 
	
		
			
				|  |  | +    MutexLock lock(&calld->chand_->xds_client()->mu_);
 | 
	
		
			
				|  |  | +    calld->OnRetryTimerLocked(GRPC_ERROR_REF(error));
 | 
	
		
			
				|  |  | +  }
 | 
	
		
			
				|  |  | +  calld->Unref(DEBUG_LOCATION, "RetryableCall+retry_timer_done");
 | 
	
		
			
				|  |  |  }
 | 
	
		
			
				|  |  |  
 | 
	
		
			
				|  |  |  template <typename T>
 | 
	
	
		
			
				|  | @@ -673,7 +675,6 @@ void XdsClient::ChannelState::RetryableCall<T>::OnRetryTimerLocked(
 | 
	
		
			
				|  |  |      }
 | 
	
		
			
				|  |  |      StartNewCallLocked();
 | 
	
		
			
				|  |  |    }
 | 
	
		
			
				|  |  | -  this->Unref(DEBUG_LOCATION, "RetryableCall+retry_timer_done");
 | 
	
		
			
				|  |  |    GRPC_ERROR_UNREF(error);
 | 
	
		
			
				|  |  |  }
 | 
	
		
			
				|  |  |  
 | 
	
	
		
			
				|  | @@ -1125,10 +1126,11 @@ void XdsClient::ChannelState::AdsCallState::AcceptEdsUpdate(
 | 
	
		
			
				|  |  |  void XdsClient::ChannelState::AdsCallState::OnRequestSent(void* arg,
 | 
	
		
			
				|  |  |                                                            grpc_error* error) {
 | 
	
		
			
				|  |  |    AdsCallState* ads_calld = static_cast<AdsCallState*>(arg);
 | 
	
		
			
				|  |  | -  GRPC_ERROR_REF(error);  // ref owned by lambda
 | 
	
		
			
				|  |  | -  ads_calld->xds_client()->work_serializer_->Run(
 | 
	
		
			
				|  |  | -      [ads_calld, error]() { ads_calld->OnRequestSentLocked(error); },
 | 
	
		
			
				|  |  | -      DEBUG_LOCATION);
 | 
	
		
			
				|  |  | +  {
 | 
	
		
			
				|  |  | +    MutexLock lock(&ads_calld->xds_client()->mu_);
 | 
	
		
			
				|  |  | +    ads_calld->OnRequestSentLocked(GRPC_ERROR_REF(error));
 | 
	
		
			
				|  |  | +  }
 | 
	
		
			
				|  |  | +  ads_calld->Unref(DEBUG_LOCATION, "ADS+OnRequestSentLocked");
 | 
	
		
			
				|  |  |  }
 | 
	
		
			
				|  |  |  
 | 
	
		
			
				|  |  |  void XdsClient::ChannelState::AdsCallState::OnRequestSentLocked(
 | 
	
	
		
			
				|  | @@ -1152,22 +1154,24 @@ void XdsClient::ChannelState::AdsCallState::OnRequestSentLocked(
 | 
	
		
			
				|  |  |        buffered_requests_.erase(it);
 | 
	
		
			
				|  |  |      }
 | 
	
		
			
				|  |  |    }
 | 
	
		
			
				|  |  | -  Unref(DEBUG_LOCATION, "ADS+OnRequestSentLocked");
 | 
	
		
			
				|  |  |    GRPC_ERROR_UNREF(error);
 | 
	
		
			
				|  |  |  }
 | 
	
		
			
				|  |  |  
 | 
	
		
			
				|  |  |  void XdsClient::ChannelState::AdsCallState::OnResponseReceived(
 | 
	
		
			
				|  |  |      void* arg, grpc_error* /* error */) {
 | 
	
		
			
				|  |  |    AdsCallState* ads_calld = static_cast<AdsCallState*>(arg);
 | 
	
		
			
				|  |  | -  ads_calld->xds_client()->work_serializer_->Run(
 | 
	
		
			
				|  |  | -      [ads_calld]() { ads_calld->OnResponseReceivedLocked(); }, DEBUG_LOCATION);
 | 
	
		
			
				|  |  | +  bool done;
 | 
	
		
			
				|  |  | +  {
 | 
	
		
			
				|  |  | +    MutexLock lock(&ads_calld->xds_client()->mu_);
 | 
	
		
			
				|  |  | +    done = ads_calld->OnResponseReceivedLocked();
 | 
	
		
			
				|  |  | +  }
 | 
	
		
			
				|  |  | +  if (done) ads_calld->Unref(DEBUG_LOCATION, "ADS+OnResponseReceivedLocked");
 | 
	
		
			
				|  |  |  }
 | 
	
		
			
				|  |  |  
 | 
	
		
			
				|  |  | -void XdsClient::ChannelState::AdsCallState::OnResponseReceivedLocked() {
 | 
	
		
			
				|  |  | +bool XdsClient::ChannelState::AdsCallState::OnResponseReceivedLocked() {
 | 
	
		
			
				|  |  |    // Empty payload means the call was cancelled.
 | 
	
		
			
				|  |  |    if (!IsCurrentCallOnChannel() || recv_message_payload_ == nullptr) {
 | 
	
		
			
				|  |  | -    Unref(DEBUG_LOCATION, "ADS+OnResponseReceivedLocked");
 | 
	
		
			
				|  |  | -    return;
 | 
	
		
			
				|  |  | +    return true;
 | 
	
		
			
				|  |  |    }
 | 
	
		
			
				|  |  |    // Read the response.
 | 
	
		
			
				|  |  |    grpc_byte_buffer_reader bbr;
 | 
	
	
		
			
				|  | @@ -1227,10 +1231,7 @@ void XdsClient::ChannelState::AdsCallState::OnResponseReceivedLocked() {
 | 
	
		
			
				|  |  |        }
 | 
	
		
			
				|  |  |      }
 | 
	
		
			
				|  |  |    }
 | 
	
		
			
				|  |  | -  if (xds_client()->shutting_down_) {
 | 
	
		
			
				|  |  | -    Unref(DEBUG_LOCATION, "ADS+OnResponseReceivedLocked+xds_shutdown");
 | 
	
		
			
				|  |  | -    return;
 | 
	
		
			
				|  |  | -  }
 | 
	
		
			
				|  |  | +  if (xds_client()->shutting_down_) return true;
 | 
	
		
			
				|  |  |    // Keep listening for updates.
 | 
	
		
			
				|  |  |    grpc_op op;
 | 
	
		
			
				|  |  |    memset(&op, 0, sizeof(op));
 | 
	
	
		
			
				|  | @@ -1243,15 +1244,17 @@ void XdsClient::ChannelState::AdsCallState::OnResponseReceivedLocked() {
 | 
	
		
			
				|  |  |    const grpc_call_error call_error =
 | 
	
		
			
				|  |  |        grpc_call_start_batch_and_execute(call_, &op, 1, &on_response_received_);
 | 
	
		
			
				|  |  |    GPR_ASSERT(GRPC_CALL_OK == call_error);
 | 
	
		
			
				|  |  | +  return false;
 | 
	
		
			
				|  |  |  }
 | 
	
		
			
				|  |  |  
 | 
	
		
			
				|  |  |  void XdsClient::ChannelState::AdsCallState::OnStatusReceived(
 | 
	
		
			
				|  |  |      void* arg, grpc_error* error) {
 | 
	
		
			
				|  |  |    AdsCallState* ads_calld = static_cast<AdsCallState*>(arg);
 | 
	
		
			
				|  |  | -  GRPC_ERROR_REF(error);  // ref owned by lambda
 | 
	
		
			
				|  |  | -  ads_calld->xds_client()->work_serializer_->Run(
 | 
	
		
			
				|  |  | -      [ads_calld, error]() { ads_calld->OnStatusReceivedLocked(error); },
 | 
	
		
			
				|  |  | -      DEBUG_LOCATION);
 | 
	
		
			
				|  |  | +  {
 | 
	
		
			
				|  |  | +    MutexLock lock(&ads_calld->xds_client()->mu_);
 | 
	
		
			
				|  |  | +    ads_calld->OnStatusReceivedLocked(GRPC_ERROR_REF(error));
 | 
	
		
			
				|  |  | +  }
 | 
	
		
			
				|  |  | +  ads_calld->Unref(DEBUG_LOCATION, "ADS+OnStatusReceivedLocked");
 | 
	
		
			
				|  |  |  }
 | 
	
		
			
				|  |  |  
 | 
	
		
			
				|  |  |  void XdsClient::ChannelState::AdsCallState::OnStatusReceivedLocked(
 | 
	
	
		
			
				|  | @@ -1270,10 +1273,9 @@ void XdsClient::ChannelState::AdsCallState::OnStatusReceivedLocked(
 | 
	
		
			
				|  |  |      // Try to restart the call.
 | 
	
		
			
				|  |  |      parent_->OnCallFinishedLocked();
 | 
	
		
			
				|  |  |      // Send error to all watchers.
 | 
	
		
			
				|  |  | -    xds_client()->NotifyOnError(
 | 
	
		
			
				|  |  | +    xds_client()->NotifyOnErrorLocked(
 | 
	
		
			
				|  |  |          GRPC_ERROR_CREATE_FROM_STATIC_STRING("xds call failed"));
 | 
	
		
			
				|  |  |    }
 | 
	
		
			
				|  |  | -  Unref(DEBUG_LOCATION, "ADS+OnStatusReceivedLocked");
 | 
	
		
			
				|  |  |    GRPC_ERROR_UNREF(error);
 | 
	
		
			
				|  |  |  }
 | 
	
		
			
				|  |  |  
 | 
	
	
		
			
				|  | @@ -1320,21 +1322,23 @@ void XdsClient::ChannelState::LrsCallState::Reporter::
 | 
	
		
			
				|  |  |  void XdsClient::ChannelState::LrsCallState::Reporter::OnNextReportTimer(
 | 
	
		
			
				|  |  |      void* arg, grpc_error* error) {
 | 
	
		
			
				|  |  |    Reporter* self = static_cast<Reporter*>(arg);
 | 
	
		
			
				|  |  | -  GRPC_ERROR_REF(error);  // ref owned by lambda
 | 
	
		
			
				|  |  | -  self->xds_client()->work_serializer_->Run(
 | 
	
		
			
				|  |  | -      [self, error]() { self->OnNextReportTimerLocked(error); },
 | 
	
		
			
				|  |  | -      DEBUG_LOCATION);
 | 
	
		
			
				|  |  | +  bool done;
 | 
	
		
			
				|  |  | +  {
 | 
	
		
			
				|  |  | +    MutexLock lock(&self->xds_client()->mu_);
 | 
	
		
			
				|  |  | +    done = self->OnNextReportTimerLocked(GRPC_ERROR_REF(error));
 | 
	
		
			
				|  |  | +  }
 | 
	
		
			
				|  |  | +  if (done) self->Unref(DEBUG_LOCATION, "Reporter+timer");
 | 
	
		
			
				|  |  |  }
 | 
	
		
			
				|  |  |  
 | 
	
		
			
				|  |  | -void XdsClient::ChannelState::LrsCallState::Reporter::OnNextReportTimerLocked(
 | 
	
		
			
				|  |  | +bool XdsClient::ChannelState::LrsCallState::Reporter::OnNextReportTimerLocked(
 | 
	
		
			
				|  |  |      grpc_error* error) {
 | 
	
		
			
				|  |  |    next_report_timer_callback_pending_ = false;
 | 
	
		
			
				|  |  |    if (error != GRPC_ERROR_NONE || !IsCurrentReporterOnCall()) {
 | 
	
		
			
				|  |  | -    Unref(DEBUG_LOCATION, "Reporter+timer");
 | 
	
		
			
				|  |  | -  } else {
 | 
	
		
			
				|  |  | -    SendReportLocked();
 | 
	
		
			
				|  |  | +    GRPC_ERROR_UNREF(error);
 | 
	
		
			
				|  |  | +    return true;
 | 
	
		
			
				|  |  |    }
 | 
	
		
			
				|  |  | -  GRPC_ERROR_UNREF(error);
 | 
	
		
			
				|  |  | +  SendReportLocked();
 | 
	
		
			
				|  |  | +  return false;
 | 
	
		
			
				|  |  |  }
 | 
	
		
			
				|  |  |  
 | 
	
		
			
				|  |  |  namespace {
 | 
	
	
		
			
				|  | @@ -1357,8 +1361,9 @@ bool LoadReportCountersAreZero(const XdsApi::ClusterLoadReportMap& snapshot) {
 | 
	
		
			
				|  |  |  
 | 
	
		
			
				|  |  |  void XdsClient::ChannelState::LrsCallState::Reporter::SendReportLocked() {
 | 
	
		
			
				|  |  |    // Construct snapshot from all reported stats.
 | 
	
		
			
				|  |  | -  XdsApi::ClusterLoadReportMap snapshot = xds_client()->BuildLoadReportSnapshot(
 | 
	
		
			
				|  |  | -      parent_->send_all_clusters_, parent_->cluster_names_);
 | 
	
		
			
				|  |  | +  XdsApi::ClusterLoadReportMap snapshot =
 | 
	
		
			
				|  |  | +      xds_client()->BuildLoadReportSnapshotLocked(parent_->send_all_clusters_,
 | 
	
		
			
				|  |  | +                                                  parent_->cluster_names_);
 | 
	
		
			
				|  |  |    // Skip client load report if the counters were all zero in the last
 | 
	
		
			
				|  |  |    // report and they are still zero in this one.
 | 
	
		
			
				|  |  |    const bool old_val = last_report_counters_were_zero_;
 | 
	
	
		
			
				|  | @@ -1391,32 +1396,35 @@ void XdsClient::ChannelState::LrsCallState::Reporter::SendReportLocked() {
 | 
	
		
			
				|  |  |  void XdsClient::ChannelState::LrsCallState::Reporter::OnReportDone(
 | 
	
		
			
				|  |  |      void* arg, grpc_error* error) {
 | 
	
		
			
				|  |  |    Reporter* self = static_cast<Reporter*>(arg);
 | 
	
		
			
				|  |  | -  GRPC_ERROR_REF(error);  // ref owned by lambda
 | 
	
		
			
				|  |  | -  self->xds_client()->work_serializer_->Run(
 | 
	
		
			
				|  |  | -      [self, error]() { self->OnReportDoneLocked(error); }, DEBUG_LOCATION);
 | 
	
		
			
				|  |  | +  bool done;
 | 
	
		
			
				|  |  | +  {
 | 
	
		
			
				|  |  | +    MutexLock lock(&self->xds_client()->mu_);
 | 
	
		
			
				|  |  | +    done = self->OnReportDoneLocked(GRPC_ERROR_REF(error));
 | 
	
		
			
				|  |  | +  }
 | 
	
		
			
				|  |  | +  if (done) self->Unref(DEBUG_LOCATION, "Reporter+report_done");
 | 
	
		
			
				|  |  |  }
 | 
	
		
			
				|  |  |  
 | 
	
		
			
				|  |  | -void XdsClient::ChannelState::LrsCallState::Reporter::OnReportDoneLocked(
 | 
	
		
			
				|  |  | +bool XdsClient::ChannelState::LrsCallState::Reporter::OnReportDoneLocked(
 | 
	
		
			
				|  |  |      grpc_error* error) {
 | 
	
		
			
				|  |  |    grpc_byte_buffer_destroy(parent_->send_message_payload_);
 | 
	
		
			
				|  |  |    parent_->send_message_payload_ = nullptr;
 | 
	
		
			
				|  |  |    // If there are no more registered stats to report, cancel the call.
 | 
	
		
			
				|  |  |    if (xds_client()->load_report_map_.empty()) {
 | 
	
		
			
				|  |  |      parent_->chand()->StopLrsCall();
 | 
	
		
			
				|  |  | -    Unref(DEBUG_LOCATION, "Reporter+report_done+no_more_reporters");
 | 
	
		
			
				|  |  | -    return;
 | 
	
		
			
				|  |  | +    GRPC_ERROR_UNREF(error);
 | 
	
		
			
				|  |  | +    return true;
 | 
	
		
			
				|  |  |    }
 | 
	
		
			
				|  |  |    if (error != GRPC_ERROR_NONE || !IsCurrentReporterOnCall()) {
 | 
	
		
			
				|  |  | +    GRPC_ERROR_UNREF(error);
 | 
	
		
			
				|  |  |      // If this reporter is no longer the current one on the call, the reason
 | 
	
		
			
				|  |  |      // might be that it was orphaned for a new one due to config update.
 | 
	
		
			
				|  |  |      if (!IsCurrentReporterOnCall()) {
 | 
	
		
			
				|  |  |        parent_->MaybeStartReportingLocked();
 | 
	
		
			
				|  |  |      }
 | 
	
		
			
				|  |  | -    Unref(DEBUG_LOCATION, "Reporter+report_done");
 | 
	
		
			
				|  |  | -  } else {
 | 
	
		
			
				|  |  | -    ScheduleNextReportLocked();
 | 
	
		
			
				|  |  | +    return true;
 | 
	
		
			
				|  |  |    }
 | 
	
		
			
				|  |  | -  GRPC_ERROR_UNREF(error);
 | 
	
		
			
				|  |  | +  ScheduleNextReportLocked();
 | 
	
		
			
				|  |  | +  return false;
 | 
	
		
			
				|  |  |  }
 | 
	
		
			
				|  |  |  
 | 
	
		
			
				|  |  |  //
 | 
	
	
		
			
				|  | @@ -1566,9 +1574,11 @@ void XdsClient::ChannelState::LrsCallState::MaybeStartReportingLocked() {
 | 
	
		
			
				|  |  |  void XdsClient::ChannelState::LrsCallState::OnInitialRequestSent(
 | 
	
		
			
				|  |  |      void* arg, grpc_error* /*error*/) {
 | 
	
		
			
				|  |  |    LrsCallState* lrs_calld = static_cast<LrsCallState*>(arg);
 | 
	
		
			
				|  |  | -  lrs_calld->xds_client()->work_serializer_->Run(
 | 
	
		
			
				|  |  | -      [lrs_calld]() { lrs_calld->OnInitialRequestSentLocked(); },
 | 
	
		
			
				|  |  | -      DEBUG_LOCATION);
 | 
	
		
			
				|  |  | +  {
 | 
	
		
			
				|  |  | +    MutexLock lock(&lrs_calld->xds_client()->mu_);
 | 
	
		
			
				|  |  | +    lrs_calld->OnInitialRequestSentLocked();
 | 
	
		
			
				|  |  | +  }
 | 
	
		
			
				|  |  | +  lrs_calld->Unref(DEBUG_LOCATION, "LRS+OnInitialRequestSentLocked");
 | 
	
		
			
				|  |  |  }
 | 
	
		
			
				|  |  |  
 | 
	
		
			
				|  |  |  void XdsClient::ChannelState::LrsCallState::OnInitialRequestSentLocked() {
 | 
	
	
		
			
				|  | @@ -1576,21 +1586,23 @@ void XdsClient::ChannelState::LrsCallState::OnInitialRequestSentLocked() {
 | 
	
		
			
				|  |  |    grpc_byte_buffer_destroy(send_message_payload_);
 | 
	
		
			
				|  |  |    send_message_payload_ = nullptr;
 | 
	
		
			
				|  |  |    MaybeStartReportingLocked();
 | 
	
		
			
				|  |  | -  Unref(DEBUG_LOCATION, "LRS+OnInitialRequestSentLocked");
 | 
	
		
			
				|  |  |  }
 | 
	
		
			
				|  |  |  
 | 
	
		
			
				|  |  |  void XdsClient::ChannelState::LrsCallState::OnResponseReceived(
 | 
	
		
			
				|  |  |      void* arg, grpc_error* /*error*/) {
 | 
	
		
			
				|  |  |    LrsCallState* lrs_calld = static_cast<LrsCallState*>(arg);
 | 
	
		
			
				|  |  | -  lrs_calld->xds_client()->work_serializer_->Run(
 | 
	
		
			
				|  |  | -      [lrs_calld]() { lrs_calld->OnResponseReceivedLocked(); }, DEBUG_LOCATION);
 | 
	
		
			
				|  |  | +  bool done;
 | 
	
		
			
				|  |  | +  {
 | 
	
		
			
				|  |  | +    MutexLock lock(&lrs_calld->xds_client()->mu_);
 | 
	
		
			
				|  |  | +    done = lrs_calld->OnResponseReceivedLocked();
 | 
	
		
			
				|  |  | +  }
 | 
	
		
			
				|  |  | +  if (done) lrs_calld->Unref(DEBUG_LOCATION, "LRS+OnResponseReceivedLocked");
 | 
	
		
			
				|  |  |  }
 | 
	
		
			
				|  |  |  
 | 
	
		
			
				|  |  | -void XdsClient::ChannelState::LrsCallState::OnResponseReceivedLocked() {
 | 
	
		
			
				|  |  | +bool XdsClient::ChannelState::LrsCallState::OnResponseReceivedLocked() {
 | 
	
		
			
				|  |  |    // Empty payload means the call was cancelled.
 | 
	
		
			
				|  |  |    if (!IsCurrentCallOnChannel() || recv_message_payload_ == nullptr) {
 | 
	
		
			
				|  |  | -    Unref(DEBUG_LOCATION, "LRS+OnResponseReceivedLocked");
 | 
	
		
			
				|  |  | -    return;
 | 
	
		
			
				|  |  | +    return true;
 | 
	
		
			
				|  |  |    }
 | 
	
		
			
				|  |  |    // Read the response.
 | 
	
		
			
				|  |  |    grpc_byte_buffer_reader bbr;
 | 
	
	
		
			
				|  | @@ -1663,10 +1675,7 @@ void XdsClient::ChannelState::LrsCallState::OnResponseReceivedLocked() {
 | 
	
		
			
				|  |  |      MaybeStartReportingLocked();
 | 
	
		
			
				|  |  |    }();
 | 
	
		
			
				|  |  |    grpc_slice_unref_internal(response_slice);
 | 
	
		
			
				|  |  | -  if (xds_client()->shutting_down_) {
 | 
	
		
			
				|  |  | -    Unref(DEBUG_LOCATION, "LRS+OnResponseReceivedLocked+xds_shutdown");
 | 
	
		
			
				|  |  | -    return;
 | 
	
		
			
				|  |  | -  }
 | 
	
		
			
				|  |  | +  if (xds_client()->shutting_down_) return true;
 | 
	
		
			
				|  |  |    // Keep listening for LRS config updates.
 | 
	
		
			
				|  |  |    grpc_op op;
 | 
	
		
			
				|  |  |    memset(&op, 0, sizeof(op));
 | 
	
	
		
			
				|  | @@ -1679,15 +1688,17 @@ void XdsClient::ChannelState::LrsCallState::OnResponseReceivedLocked() {
 | 
	
		
			
				|  |  |    const grpc_call_error call_error =
 | 
	
		
			
				|  |  |        grpc_call_start_batch_and_execute(call_, &op, 1, &on_response_received_);
 | 
	
		
			
				|  |  |    GPR_ASSERT(GRPC_CALL_OK == call_error);
 | 
	
		
			
				|  |  | +  return false;
 | 
	
		
			
				|  |  |  }
 | 
	
		
			
				|  |  |  
 | 
	
		
			
				|  |  |  void XdsClient::ChannelState::LrsCallState::OnStatusReceived(
 | 
	
		
			
				|  |  |      void* arg, grpc_error* error) {
 | 
	
		
			
				|  |  |    LrsCallState* lrs_calld = static_cast<LrsCallState*>(arg);
 | 
	
		
			
				|  |  | -  GRPC_ERROR_REF(error);  // ref owned by lambda
 | 
	
		
			
				|  |  | -  lrs_calld->xds_client()->work_serializer_->Run(
 | 
	
		
			
				|  |  | -      [lrs_calld, error]() { lrs_calld->OnStatusReceivedLocked(error); },
 | 
	
		
			
				|  |  | -      DEBUG_LOCATION);
 | 
	
		
			
				|  |  | +  {
 | 
	
		
			
				|  |  | +    MutexLock lock(&lrs_calld->xds_client()->mu_);
 | 
	
		
			
				|  |  | +    lrs_calld->OnStatusReceivedLocked(GRPC_ERROR_REF(error));
 | 
	
		
			
				|  |  | +  }
 | 
	
		
			
				|  |  | +  lrs_calld->Unref(DEBUG_LOCATION, "LRS+OnStatusReceivedLocked");
 | 
	
		
			
				|  |  |  }
 | 
	
		
			
				|  |  |  
 | 
	
		
			
				|  |  |  void XdsClient::ChannelState::LrsCallState::OnStatusReceivedLocked(
 | 
	
	
		
			
				|  | @@ -1708,7 +1719,6 @@ void XdsClient::ChannelState::LrsCallState::OnStatusReceivedLocked(
 | 
	
		
			
				|  |  |      // Try to restart the call.
 | 
	
		
			
				|  |  |      parent_->OnCallFinishedLocked();
 | 
	
		
			
				|  |  |    }
 | 
	
		
			
				|  |  | -  Unref(DEBUG_LOCATION, "LRS+OnStatusReceivedLocked");
 | 
	
		
			
				|  |  |    GRPC_ERROR_UNREF(error);
 | 
	
		
			
				|  |  |  }
 | 
	
		
			
				|  |  |  
 | 
	
	
		
			
				|  | @@ -1765,11 +1775,9 @@ grpc_channel* CreateXdsChannel(const XdsBootstrap& bootstrap,
 | 
	
		
			
				|  |  |  
 | 
	
		
			
				|  |  |  }  // namespace
 | 
	
		
			
				|  |  |  
 | 
	
		
			
				|  |  | -XdsClient::XdsClient(std::shared_ptr<WorkSerializer> work_serializer,
 | 
	
		
			
				|  |  | -                     const grpc_channel_args& channel_args, grpc_error** error)
 | 
	
		
			
				|  |  | +XdsClient::XdsClient(const grpc_channel_args& channel_args, grpc_error** error)
 | 
	
		
			
				|  |  |      : InternallyRefCounted<XdsClient>(&grpc_xds_client_trace),
 | 
	
		
			
				|  |  |        request_timeout_(GetRequestTimeout(channel_args)),
 | 
	
		
			
				|  |  | -      work_serializer_(std::move(work_serializer)),
 | 
	
		
			
				|  |  |        interested_parties_(grpc_pollset_set_create()),
 | 
	
		
			
				|  |  |        bootstrap_(
 | 
	
		
			
				|  |  |            XdsBootstrap::ReadFromFile(this, &grpc_xds_client_trace, error)),
 | 
	
	
		
			
				|  | @@ -1809,17 +1817,20 @@ void XdsClient::Orphan() {
 | 
	
		
			
				|  |  |    if (GRPC_TRACE_FLAG_ENABLED(grpc_xds_client_trace)) {
 | 
	
		
			
				|  |  |      gpr_log(GPR_INFO, "[xds_client %p] shutting down xds client", this);
 | 
	
		
			
				|  |  |    }
 | 
	
		
			
				|  |  | -  shutting_down_ = true;
 | 
	
		
			
				|  |  | -  chand_.reset();
 | 
	
		
			
				|  |  | -  // We do not clear cluster_map_ and endpoint_map_ if the xds client was
 | 
	
		
			
				|  |  | -  // created by the XdsResolver because the maps contain refs for watchers which
 | 
	
		
			
				|  |  | -  // in turn hold refs to the loadbalancing policies. At this point, it is
 | 
	
		
			
				|  |  | -  // possible for ADS calls to be in progress. Unreffing the loadbalancing
 | 
	
		
			
				|  |  | -  // policies before those calls are done would lead to issues such as
 | 
	
		
			
				|  |  | -  // https://github.com/grpc/grpc/issues/20928.
 | 
	
		
			
				|  |  | -  if (!listener_map_.empty()) {
 | 
	
		
			
				|  |  | -    cluster_map_.clear();
 | 
	
		
			
				|  |  | -    endpoint_map_.clear();
 | 
	
		
			
				|  |  | +  {
 | 
	
		
			
				|  |  | +    MutexLock lock(&mu_);
 | 
	
		
			
				|  |  | +    shutting_down_ = true;
 | 
	
		
			
				|  |  | +    chand_.reset();
 | 
	
		
			
				|  |  | +    // We do not clear cluster_map_ and endpoint_map_ if the xds client was
 | 
	
		
			
				|  |  | +    // created by the XdsResolver because the maps contain refs for watchers
 | 
	
		
			
				|  |  | +    // which in turn hold refs to the loadbalancing policies. At this point, it
 | 
	
		
			
				|  |  | +    // is possible for ADS calls to be in progress. Unreffing the loadbalancing
 | 
	
		
			
				|  |  | +    // policies before those calls are done would lead to issues such as
 | 
	
		
			
				|  |  | +    // https://github.com/grpc/grpc/issues/20928.
 | 
	
		
			
				|  |  | +    if (!listener_map_.empty()) {
 | 
	
		
			
				|  |  | +      cluster_map_.clear();
 | 
	
		
			
				|  |  | +      endpoint_map_.clear();
 | 
	
		
			
				|  |  | +    }
 | 
	
		
			
				|  |  |    }
 | 
	
		
			
				|  |  |    Unref(DEBUG_LOCATION, "XdsClient::Orphan()");
 | 
	
		
			
				|  |  |  }
 | 
	
	
		
			
				|  | @@ -1828,6 +1839,7 @@ void XdsClient::WatchListenerData(
 | 
	
		
			
				|  |  |      absl::string_view listener_name,
 | 
	
		
			
				|  |  |      std::unique_ptr<ListenerWatcherInterface> watcher) {
 | 
	
		
			
				|  |  |    std::string listener_name_str = std::string(listener_name);
 | 
	
		
			
				|  |  | +  MutexLock lock(&mu_);
 | 
	
		
			
				|  |  |    ListenerState& listener_state = listener_map_[listener_name_str];
 | 
	
		
			
				|  |  |    ListenerWatcherInterface* w = watcher.get();
 | 
	
		
			
				|  |  |    listener_state.watchers[w] = std::move(watcher);
 | 
	
	
		
			
				|  | @@ -1846,6 +1858,7 @@ void XdsClient::WatchListenerData(
 | 
	
		
			
				|  |  |  void XdsClient::CancelListenerDataWatch(absl::string_view listener_name,
 | 
	
		
			
				|  |  |                                          ListenerWatcherInterface* watcher,
 | 
	
		
			
				|  |  |                                          bool delay_unsubscription) {
 | 
	
		
			
				|  |  | +  MutexLock lock(&mu_);
 | 
	
		
			
				|  |  |    if (shutting_down_) return;
 | 
	
		
			
				|  |  |    std::string listener_name_str = std::string(listener_name);
 | 
	
		
			
				|  |  |    ListenerState& listener_state = listener_map_[listener_name_str];
 | 
	
	
		
			
				|  | @@ -1864,6 +1877,7 @@ void XdsClient::WatchRouteConfigData(
 | 
	
		
			
				|  |  |      absl::string_view route_config_name,
 | 
	
		
			
				|  |  |      std::unique_ptr<RouteConfigWatcherInterface> watcher) {
 | 
	
		
			
				|  |  |    std::string route_config_name_str = std::string(route_config_name);
 | 
	
		
			
				|  |  | +  MutexLock lock(&mu_);
 | 
	
		
			
				|  |  |    RouteConfigState& route_config_state =
 | 
	
		
			
				|  |  |        route_config_map_[route_config_name_str];
 | 
	
		
			
				|  |  |    RouteConfigWatcherInterface* w = watcher.get();
 | 
	
	
		
			
				|  | @@ -1884,6 +1898,7 @@ void XdsClient::WatchRouteConfigData(
 | 
	
		
			
				|  |  |  void XdsClient::CancelRouteConfigDataWatch(absl::string_view route_config_name,
 | 
	
		
			
				|  |  |                                             RouteConfigWatcherInterface* watcher,
 | 
	
		
			
				|  |  |                                             bool delay_unsubscription) {
 | 
	
		
			
				|  |  | +  MutexLock lock(&mu_);
 | 
	
		
			
				|  |  |    if (shutting_down_) return;
 | 
	
		
			
				|  |  |    std::string route_config_name_str = std::string(route_config_name);
 | 
	
		
			
				|  |  |    RouteConfigState& route_config_state =
 | 
	
	
		
			
				|  | @@ -1903,6 +1918,7 @@ void XdsClient::WatchClusterData(
 | 
	
		
			
				|  |  |      absl::string_view cluster_name,
 | 
	
		
			
				|  |  |      std::unique_ptr<ClusterWatcherInterface> watcher) {
 | 
	
		
			
				|  |  |    std::string cluster_name_str = std::string(cluster_name);
 | 
	
		
			
				|  |  | +  MutexLock lock(&mu_);
 | 
	
		
			
				|  |  |    ClusterState& cluster_state = cluster_map_[cluster_name_str];
 | 
	
		
			
				|  |  |    ClusterWatcherInterface* w = watcher.get();
 | 
	
		
			
				|  |  |    cluster_state.watchers[w] = std::move(watcher);
 | 
	
	
		
			
				|  | @@ -1921,6 +1937,7 @@ void XdsClient::WatchClusterData(
 | 
	
		
			
				|  |  |  void XdsClient::CancelClusterDataWatch(absl::string_view cluster_name,
 | 
	
		
			
				|  |  |                                         ClusterWatcherInterface* watcher,
 | 
	
		
			
				|  |  |                                         bool delay_unsubscription) {
 | 
	
		
			
				|  |  | +  MutexLock lock(&mu_);
 | 
	
		
			
				|  |  |    if (shutting_down_) return;
 | 
	
		
			
				|  |  |    std::string cluster_name_str = std::string(cluster_name);
 | 
	
		
			
				|  |  |    ClusterState& cluster_state = cluster_map_[cluster_name_str];
 | 
	
	
		
			
				|  | @@ -1939,6 +1956,7 @@ void XdsClient::WatchEndpointData(
 | 
	
		
			
				|  |  |      absl::string_view eds_service_name,
 | 
	
		
			
				|  |  |      std::unique_ptr<EndpointWatcherInterface> watcher) {
 | 
	
		
			
				|  |  |    std::string eds_service_name_str = std::string(eds_service_name);
 | 
	
		
			
				|  |  | +  MutexLock lock(&mu_);
 | 
	
		
			
				|  |  |    EndpointState& endpoint_state = endpoint_map_[eds_service_name_str];
 | 
	
		
			
				|  |  |    EndpointWatcherInterface* w = watcher.get();
 | 
	
		
			
				|  |  |    endpoint_state.watchers[w] = std::move(watcher);
 | 
	
	
		
			
				|  | @@ -1957,6 +1975,7 @@ void XdsClient::WatchEndpointData(
 | 
	
		
			
				|  |  |  void XdsClient::CancelEndpointDataWatch(absl::string_view eds_service_name,
 | 
	
		
			
				|  |  |                                          EndpointWatcherInterface* watcher,
 | 
	
		
			
				|  |  |                                          bool delay_unsubscription) {
 | 
	
		
			
				|  |  | +  MutexLock lock(&mu_);
 | 
	
		
			
				|  |  |    if (shutting_down_) return;
 | 
	
		
			
				|  |  |    std::string eds_service_name_str = std::string(eds_service_name);
 | 
	
		
			
				|  |  |    EndpointState& endpoint_state = endpoint_map_[eds_service_name_str];
 | 
	
	
		
			
				|  | @@ -1978,6 +1997,7 @@ RefCountedPtr<XdsClusterDropStats> XdsClient::AddClusterDropStats(
 | 
	
		
			
				|  |  |    // server name specified in lrs_server.
 | 
	
		
			
				|  |  |    auto key =
 | 
	
		
			
				|  |  |        std::make_pair(std::string(cluster_name), std::string(eds_service_name));
 | 
	
		
			
				|  |  | +  MutexLock lock(&mu_);
 | 
	
		
			
				|  |  |    // We jump through some hoops here to make sure that the absl::string_views
 | 
	
		
			
				|  |  |    // stored in the XdsClusterDropStats object point to the strings
 | 
	
		
			
				|  |  |    // in the load_report_map_ key, so that they have the same lifetime.
 | 
	
	
		
			
				|  | @@ -1996,6 +2016,7 @@ void XdsClient::RemoveClusterDropStats(
 | 
	
		
			
				|  |  |      absl::string_view /*lrs_server*/, absl::string_view cluster_name,
 | 
	
		
			
				|  |  |      absl::string_view eds_service_name,
 | 
	
		
			
				|  |  |      XdsClusterDropStats* cluster_drop_stats) {
 | 
	
		
			
				|  |  | +  MutexLock lock(&mu_);
 | 
	
		
			
				|  |  |    auto load_report_it = load_report_map_.find(
 | 
	
		
			
				|  |  |        std::make_pair(std::string(cluster_name), std::string(eds_service_name)));
 | 
	
		
			
				|  |  |    if (load_report_it == load_report_map_.end()) return;
 | 
	
	
		
			
				|  | @@ -2021,6 +2042,7 @@ RefCountedPtr<XdsClusterLocalityStats> XdsClient::AddClusterLocalityStats(
 | 
	
		
			
				|  |  |    // server name specified in lrs_server.
 | 
	
		
			
				|  |  |    auto key =
 | 
	
		
			
				|  |  |        std::make_pair(std::string(cluster_name), std::string(eds_service_name));
 | 
	
		
			
				|  |  | +  MutexLock lock(&mu_);
 | 
	
		
			
				|  |  |    // We jump through some hoops here to make sure that the absl::string_views
 | 
	
		
			
				|  |  |    // stored in the XdsClusterLocalityStats object point to the strings
 | 
	
		
			
				|  |  |    // in the load_report_map_ key, so that they have the same lifetime.
 | 
	
	
		
			
				|  | @@ -2042,6 +2064,7 @@ void XdsClient::RemoveClusterLocalityStats(
 | 
	
		
			
				|  |  |      absl::string_view eds_service_name,
 | 
	
		
			
				|  |  |      const RefCountedPtr<XdsLocalityName>& locality,
 | 
	
		
			
				|  |  |      XdsClusterLocalityStats* cluster_locality_stats) {
 | 
	
		
			
				|  |  | +  MutexLock lock(&mu_);
 | 
	
		
			
				|  |  |    auto load_report_it = load_report_map_.find(
 | 
	
		
			
				|  |  |        std::make_pair(std::string(cluster_name), std::string(eds_service_name)));
 | 
	
		
			
				|  |  |    if (load_report_it == load_report_map_.end()) return;
 | 
	
	
		
			
				|  | @@ -2062,12 +2085,41 @@ void XdsClient::RemoveClusterLocalityStats(
 | 
	
		
			
				|  |  |  }
 | 
	
		
			
				|  |  |  
 | 
	
		
			
				|  |  |  void XdsClient::ResetBackoff() {
 | 
	
		
			
				|  |  | +  MutexLock lock(&mu_);
 | 
	
		
			
				|  |  |    if (chand_ != nullptr) {
 | 
	
		
			
				|  |  |      grpc_channel_reset_connect_backoff(chand_->channel());
 | 
	
		
			
				|  |  |    }
 | 
	
		
			
				|  |  |  }
 | 
	
		
			
				|  |  |  
 | 
	
		
			
				|  |  | -XdsApi::ClusterLoadReportMap XdsClient::BuildLoadReportSnapshot(
 | 
	
		
			
				|  |  | +void XdsClient::NotifyOnErrorLocked(grpc_error* error) {
 | 
	
		
			
				|  |  | +  for (const auto& p : listener_map_) {
 | 
	
		
			
				|  |  | +    const ListenerState& listener_state = p.second;
 | 
	
		
			
				|  |  | +    for (const auto& p : listener_state.watchers) {
 | 
	
		
			
				|  |  | +      p.first->OnError(GRPC_ERROR_REF(error));
 | 
	
		
			
				|  |  | +    }
 | 
	
		
			
				|  |  | +  }
 | 
	
		
			
				|  |  | +  for (const auto& p : route_config_map_) {
 | 
	
		
			
				|  |  | +    const RouteConfigState& route_config_state = p.second;
 | 
	
		
			
				|  |  | +    for (const auto& p : route_config_state.watchers) {
 | 
	
		
			
				|  |  | +      p.first->OnError(GRPC_ERROR_REF(error));
 | 
	
		
			
				|  |  | +    }
 | 
	
		
			
				|  |  | +  }
 | 
	
		
			
				|  |  | +  for (const auto& p : cluster_map_) {
 | 
	
		
			
				|  |  | +    const ClusterState& cluster_state = p.second;
 | 
	
		
			
				|  |  | +    for (const auto& p : cluster_state.watchers) {
 | 
	
		
			
				|  |  | +      p.first->OnError(GRPC_ERROR_REF(error));
 | 
	
		
			
				|  |  | +    }
 | 
	
		
			
				|  |  | +  }
 | 
	
		
			
				|  |  | +  for (const auto& p : endpoint_map_) {
 | 
	
		
			
				|  |  | +    const EndpointState& endpoint_state = p.second;
 | 
	
		
			
				|  |  | +    for (const auto& p : endpoint_state.watchers) {
 | 
	
		
			
				|  |  | +      p.first->OnError(GRPC_ERROR_REF(error));
 | 
	
		
			
				|  |  | +    }
 | 
	
		
			
				|  |  | +  }
 | 
	
		
			
				|  |  | +  GRPC_ERROR_UNREF(error);
 | 
	
		
			
				|  |  | +}
 | 
	
		
			
				|  |  | +
 | 
	
		
			
				|  |  | +XdsApi::ClusterLoadReportMap XdsClient::BuildLoadReportSnapshotLocked(
 | 
	
		
			
				|  |  |      bool send_all_clusters, const std::set<std::string>& clusters) {
 | 
	
		
			
				|  |  |    XdsApi::ClusterLoadReportMap snapshot_map;
 | 
	
		
			
				|  |  |    for (auto load_report_it = load_report_map_.begin();
 | 
	
	
		
			
				|  | @@ -2135,34 +2187,6 @@ XdsApi::ClusterLoadReportMap XdsClient::BuildLoadReportSnapshot(
 | 
	
		
			
				|  |  |    return snapshot_map;
 | 
	
		
			
				|  |  |  }
 | 
	
		
			
				|  |  |  
 | 
	
		
			
				|  |  | -void XdsClient::NotifyOnError(grpc_error* error) {
 | 
	
		
			
				|  |  | -  for (const auto& p : listener_map_) {
 | 
	
		
			
				|  |  | -    const ListenerState& listener_state = p.second;
 | 
	
		
			
				|  |  | -    for (const auto& p : listener_state.watchers) {
 | 
	
		
			
				|  |  | -      p.first->OnError(GRPC_ERROR_REF(error));
 | 
	
		
			
				|  |  | -    }
 | 
	
		
			
				|  |  | -  }
 | 
	
		
			
				|  |  | -  for (const auto& p : route_config_map_) {
 | 
	
		
			
				|  |  | -    const RouteConfigState& route_config_state = p.second;
 | 
	
		
			
				|  |  | -    for (const auto& p : route_config_state.watchers) {
 | 
	
		
			
				|  |  | -      p.first->OnError(GRPC_ERROR_REF(error));
 | 
	
		
			
				|  |  | -    }
 | 
	
		
			
				|  |  | -  }
 | 
	
		
			
				|  |  | -  for (const auto& p : cluster_map_) {
 | 
	
		
			
				|  |  | -    const ClusterState& cluster_state = p.second;
 | 
	
		
			
				|  |  | -    for (const auto& p : cluster_state.watchers) {
 | 
	
		
			
				|  |  | -      p.first->OnError(GRPC_ERROR_REF(error));
 | 
	
		
			
				|  |  | -    }
 | 
	
		
			
				|  |  | -  }
 | 
	
		
			
				|  |  | -  for (const auto& p : endpoint_map_) {
 | 
	
		
			
				|  |  | -    const EndpointState& endpoint_state = p.second;
 | 
	
		
			
				|  |  | -    for (const auto& p : endpoint_state.watchers) {
 | 
	
		
			
				|  |  | -      p.first->OnError(GRPC_ERROR_REF(error));
 | 
	
		
			
				|  |  | -    }
 | 
	
		
			
				|  |  | -  }
 | 
	
		
			
				|  |  | -  GRPC_ERROR_UNREF(error);
 | 
	
		
			
				|  |  | -}
 | 
	
		
			
				|  |  | -
 | 
	
		
			
				|  |  |  void* XdsClient::ChannelArgCopy(void* p) {
 | 
	
		
			
				|  |  |    XdsClient* xds_client = static_cast<XdsClient*>(p);
 | 
	
		
			
				|  |  |    xds_client->Ref(DEBUG_LOCATION, "channel arg").release();
 |