|  | @@ -47,6 +47,7 @@
 | 
	
		
			
				|  |  |  #include "src/core/lib/gpr/string.h"
 | 
	
		
			
				|  |  |  #include "src/core/lib/gprpp/inlined_vector.h"
 | 
	
		
			
				|  |  |  #include "src/core/lib/gprpp/manual_constructor.h"
 | 
	
		
			
				|  |  | +#include "src/core/lib/gprpp/mutex_lock.h"
 | 
	
		
			
				|  |  |  #include "src/core/lib/iomgr/combiner.h"
 | 
	
		
			
				|  |  |  #include "src/core/lib/iomgr/iomgr.h"
 | 
	
		
			
				|  |  |  #include "src/core/lib/iomgr/polling_entity.h"
 | 
	
	
		
			
				|  | @@ -77,12 +78,14 @@ class ResolvingLoadBalancingPolicy::ResolvingControlHelper
 | 
	
		
			
				|  |  |  
 | 
	
		
			
				|  |  |    Subchannel* CreateSubchannel(const grpc_channel_args& args) override {
 | 
	
		
			
				|  |  |      if (parent_->resolver_ == nullptr) return nullptr;  // Shutting down.
 | 
	
		
			
				|  |  | +    if (!CalledByCurrentChild() && !CalledByPendingChild()) return nullptr;
 | 
	
		
			
				|  |  |      return parent_->channel_control_helper()->CreateSubchannel(args);
 | 
	
		
			
				|  |  |    }
 | 
	
		
			
				|  |  |  
 | 
	
		
			
				|  |  |    grpc_channel* CreateChannel(const char* target,
 | 
	
		
			
				|  |  |                                const grpc_channel_args& args) override {
 | 
	
		
			
				|  |  |      if (parent_->resolver_ == nullptr) return nullptr;  // Shutting down.
 | 
	
		
			
				|  |  | +    if (!CalledByCurrentChild() && !CalledByPendingChild()) return nullptr;
 | 
	
		
			
				|  |  |      return parent_->channel_control_helper()->CreateChannel(target, args);
 | 
	
		
			
				|  |  |    }
 | 
	
		
			
				|  |  |  
 | 
	
	
		
			
				|  | @@ -93,11 +96,37 @@ class ResolvingLoadBalancingPolicy::ResolvingControlHelper
 | 
	
		
			
				|  |  |        GRPC_ERROR_UNREF(state_error);
 | 
	
		
			
				|  |  |        return;
 | 
	
		
			
				|  |  |      }
 | 
	
		
			
				|  |  | +    // If this request is from the pending child policy, ignore it until
 | 
	
		
			
				|  |  | +    // it reports READY, at which point we swap it into place.
 | 
	
		
			
				|  |  | +    if (CalledByPendingChild()) {
 | 
	
		
			
				|  |  | +      if (parent_->tracer_->enabled()) {
 | 
	
		
			
				|  |  | +        gpr_log(GPR_INFO,
 | 
	
		
			
				|  |  | +                "resolving_lb=%p helper=%p: pending child policy %p reports "
 | 
	
		
			
				|  |  | +                "state=%s",
 | 
	
		
			
				|  |  | +                parent_.get(), this, child_,
 | 
	
		
			
				|  |  | +                grpc_connectivity_state_name(state));
 | 
	
		
			
				|  |  | +      }
 | 
	
		
			
				|  |  | +      if (state != GRPC_CHANNEL_READY) {
 | 
	
		
			
				|  |  | +        GRPC_ERROR_UNREF(state_error);
 | 
	
		
			
				|  |  | +        return;
 | 
	
		
			
				|  |  | +      }
 | 
	
		
			
				|  |  | +      MutexLock lock(&parent_->lb_policy_mu_);
 | 
	
		
			
				|  |  | +      parent_->lb_policy_ = std::move(parent_->pending_lb_policy_);
 | 
	
		
			
				|  |  | +    } else if (!CalledByCurrentChild()) {
 | 
	
		
			
				|  |  | +      // This request is from an outdated child, so ignore it.
 | 
	
		
			
				|  |  | +      GRPC_ERROR_UNREF(state_error);
 | 
	
		
			
				|  |  | +      return;
 | 
	
		
			
				|  |  | +    }
 | 
	
		
			
				|  |  |      parent_->channel_control_helper()->UpdateState(state, state_error,
 | 
	
		
			
				|  |  |                                                     std::move(picker));
 | 
	
		
			
				|  |  |    }
 | 
	
		
			
				|  |  |  
 | 
	
		
			
				|  |  |    void RequestReresolution() override {
 | 
	
		
			
				|  |  | +    // If there is a pending child policy, ignore re-resolution requests
 | 
	
		
			
				|  |  | +    // from the current child policy (or any outdated child).
 | 
	
		
			
				|  |  | +    if (parent_->pending_lb_policy_ != nullptr && !CalledByPendingChild()) {
 | 
	
		
			
				|  |  | +      return;
 | 
	
		
			
				|  |  | +    }
 | 
	
		
			
				|  |  |      if (parent_->tracer_->enabled()) {
 | 
	
		
			
				|  |  |        gpr_log(GPR_INFO, "resolving_lb=%p: started name re-resolving",
 | 
	
		
			
				|  |  |                parent_.get());
 | 
	
	
		
			
				|  | @@ -107,8 +136,21 @@ class ResolvingLoadBalancingPolicy::ResolvingControlHelper
 | 
	
		
			
				|  |  |      }
 | 
	
		
			
				|  |  |    }
 | 
	
		
			
				|  |  |  
 | 
	
		
			
				|  |  | +  void set_child(LoadBalancingPolicy* child) { child_ = child; }
 | 
	
		
			
				|  |  | +
 | 
	
		
			
				|  |  |   private:
 | 
	
		
			
				|  |  | +  bool CalledByPendingChild() const {
 | 
	
		
			
				|  |  | +    GPR_ASSERT(child_ != nullptr);
 | 
	
		
			
				|  |  | +    return child_ == parent_->pending_lb_policy_.get();
 | 
	
		
			
				|  |  | +  }
 | 
	
		
			
				|  |  | +
 | 
	
		
			
				|  |  | +  bool CalledByCurrentChild() const {
 | 
	
		
			
				|  |  | +    GPR_ASSERT(child_ != nullptr);
 | 
	
		
			
				|  |  | +    return child_ == parent_->lb_policy_.get();
 | 
	
		
			
				|  |  | +  };
 | 
	
		
			
				|  |  | +
 | 
	
		
			
				|  |  |    RefCountedPtr<ResolvingLoadBalancingPolicy> parent_;
 | 
	
		
			
				|  |  | +  LoadBalancingPolicy* child_ = nullptr;
 | 
	
		
			
				|  |  |  };
 | 
	
		
			
				|  |  |  
 | 
	
		
			
				|  |  |  //
 | 
	
	
		
			
				|  | @@ -146,6 +188,7 @@ ResolvingLoadBalancingPolicy::ResolvingLoadBalancingPolicy(
 | 
	
		
			
				|  |  |        process_resolver_result_(process_resolver_result),
 | 
	
		
			
				|  |  |        process_resolver_result_user_data_(process_resolver_result_user_data) {
 | 
	
		
			
				|  |  |    GPR_ASSERT(process_resolver_result != nullptr);
 | 
	
		
			
				|  |  | +  gpr_mu_init(&lb_policy_mu_);
 | 
	
		
			
				|  |  |    *error = Init(*args.args);
 | 
	
		
			
				|  |  |  }
 | 
	
		
			
				|  |  |  
 | 
	
	
		
			
				|  | @@ -169,22 +212,38 @@ grpc_error* ResolvingLoadBalancingPolicy::Init(const grpc_channel_args& args) {
 | 
	
		
			
				|  |  |  ResolvingLoadBalancingPolicy::~ResolvingLoadBalancingPolicy() {
 | 
	
		
			
				|  |  |    GPR_ASSERT(resolver_ == nullptr);
 | 
	
		
			
				|  |  |    GPR_ASSERT(lb_policy_ == nullptr);
 | 
	
		
			
				|  |  | +  gpr_mu_destroy(&lb_policy_mu_);
 | 
	
		
			
				|  |  |  }
 | 
	
		
			
				|  |  |  
 | 
	
		
			
				|  |  |  void ResolvingLoadBalancingPolicy::ShutdownLocked() {
 | 
	
		
			
				|  |  |    if (resolver_ != nullptr) {
 | 
	
		
			
				|  |  |      resolver_.reset();
 | 
	
		
			
				|  |  | +    MutexLock lock(&lb_policy_mu_);
 | 
	
		
			
				|  |  |      if (lb_policy_ != nullptr) {
 | 
	
		
			
				|  |  | +      if (tracer_->enabled()) {
 | 
	
		
			
				|  |  | +        gpr_log(GPR_INFO, "resolving_lb=%p: shutting down lb_policy=%p", this,
 | 
	
		
			
				|  |  | +                lb_policy_.get());
 | 
	
		
			
				|  |  | +      }
 | 
	
		
			
				|  |  |        grpc_pollset_set_del_pollset_set(lb_policy_->interested_parties(),
 | 
	
		
			
				|  |  |                                         interested_parties());
 | 
	
		
			
				|  |  |        lb_policy_.reset();
 | 
	
		
			
				|  |  |      }
 | 
	
		
			
				|  |  | +    if (pending_lb_policy_ != nullptr) {
 | 
	
		
			
				|  |  | +      if (tracer_->enabled()) {
 | 
	
		
			
				|  |  | +        gpr_log(GPR_INFO, "resolving_lb=%p: shutting down pending lb_policy=%p",
 | 
	
		
			
				|  |  | +                this, pending_lb_policy_.get());
 | 
	
		
			
				|  |  | +      }
 | 
	
		
			
				|  |  | +      grpc_pollset_set_del_pollset_set(pending_lb_policy_->interested_parties(),
 | 
	
		
			
				|  |  | +                                       interested_parties());
 | 
	
		
			
				|  |  | +      pending_lb_policy_.reset();
 | 
	
		
			
				|  |  | +    }
 | 
	
		
			
				|  |  |    }
 | 
	
		
			
				|  |  |  }
 | 
	
		
			
				|  |  |  
 | 
	
		
			
				|  |  |  void ResolvingLoadBalancingPolicy::ExitIdleLocked() {
 | 
	
		
			
				|  |  |    if (lb_policy_ != nullptr) {
 | 
	
		
			
				|  |  |      lb_policy_->ExitIdleLocked();
 | 
	
		
			
				|  |  | +    if (pending_lb_policy_ != nullptr) pending_lb_policy_->ExitIdleLocked();
 | 
	
		
			
				|  |  |    } else {
 | 
	
		
			
				|  |  |      if (!started_resolving_ && resolver_ != nullptr) {
 | 
	
		
			
				|  |  |        StartResolvingLocked();
 | 
	
	
		
			
				|  | @@ -197,17 +256,24 @@ void ResolvingLoadBalancingPolicy::ResetBackoffLocked() {
 | 
	
		
			
				|  |  |      resolver_->ResetBackoffLocked();
 | 
	
		
			
				|  |  |      resolver_->RequestReresolutionLocked();
 | 
	
		
			
				|  |  |    }
 | 
	
		
			
				|  |  | -  if (lb_policy_ != nullptr) {
 | 
	
		
			
				|  |  | -    lb_policy_->ResetBackoffLocked();
 | 
	
		
			
				|  |  | -  }
 | 
	
		
			
				|  |  | +  if (lb_policy_ != nullptr) lb_policy_->ResetBackoffLocked();
 | 
	
		
			
				|  |  | +  if (pending_lb_policy_ != nullptr) pending_lb_policy_->ResetBackoffLocked();
 | 
	
		
			
				|  |  |  }
 | 
	
		
			
				|  |  |  
 | 
	
		
			
				|  |  |  void ResolvingLoadBalancingPolicy::FillChildRefsForChannelz(
 | 
	
		
			
				|  |  |      channelz::ChildRefsList* child_subchannels,
 | 
	
		
			
				|  |  |      channelz::ChildRefsList* child_channels) {
 | 
	
		
			
				|  |  | +  // Delegate to the lb_policy_ to fill the children subchannels.
 | 
	
		
			
				|  |  | +  // This must be done holding lb_policy_mu_, since this method does not
 | 
	
		
			
				|  |  | +  // run in the combiner.
 | 
	
		
			
				|  |  | +  MutexLock lock(&lb_policy_mu_);
 | 
	
		
			
				|  |  |    if (lb_policy_ != nullptr) {
 | 
	
		
			
				|  |  |      lb_policy_->FillChildRefsForChannelz(child_subchannels, child_channels);
 | 
	
		
			
				|  |  |    }
 | 
	
		
			
				|  |  | +  if (pending_lb_policy_ != nullptr) {
 | 
	
		
			
				|  |  | +    pending_lb_policy_->FillChildRefsForChannelz(child_subchannels,
 | 
	
		
			
				|  |  | +                                                 child_channels);
 | 
	
		
			
				|  |  | +  }
 | 
	
		
			
				|  |  |  }
 | 
	
		
			
				|  |  |  
 | 
	
		
			
				|  |  |  void ResolvingLoadBalancingPolicy::StartResolvingLocked() {
 | 
	
	
		
			
				|  | @@ -229,14 +295,26 @@ void ResolvingLoadBalancingPolicy::OnResolverShutdownLocked(grpc_error* error) {
 | 
	
		
			
				|  |  |    if (tracer_->enabled()) {
 | 
	
		
			
				|  |  |      gpr_log(GPR_INFO, "resolving_lb=%p: shutting down", this);
 | 
	
		
			
				|  |  |    }
 | 
	
		
			
				|  |  | -  if (lb_policy_ != nullptr) {
 | 
	
		
			
				|  |  | -    if (tracer_->enabled()) {
 | 
	
		
			
				|  |  | -      gpr_log(GPR_INFO, "resolving_lb=%p: shutting down lb_policy=%p", this,
 | 
	
		
			
				|  |  | -              lb_policy_.get());
 | 
	
		
			
				|  |  | +  {
 | 
	
		
			
				|  |  | +    MutexLock lock(&lb_policy_mu_);
 | 
	
		
			
				|  |  | +    if (lb_policy_ != nullptr) {
 | 
	
		
			
				|  |  | +      if (tracer_->enabled()) {
 | 
	
		
			
				|  |  | +        gpr_log(GPR_INFO, "resolving_lb=%p: shutting down lb_policy=%p", this,
 | 
	
		
			
				|  |  | +                lb_policy_.get());
 | 
	
		
			
				|  |  | +      }
 | 
	
		
			
				|  |  | +      grpc_pollset_set_del_pollset_set(lb_policy_->interested_parties(),
 | 
	
		
			
				|  |  | +                                       interested_parties());
 | 
	
		
			
				|  |  | +      lb_policy_.reset();
 | 
	
		
			
				|  |  | +    }
 | 
	
		
			
				|  |  | +    if (pending_lb_policy_ != nullptr) {
 | 
	
		
			
				|  |  | +      if (tracer_->enabled()) {
 | 
	
		
			
				|  |  | +        gpr_log(GPR_INFO, "resolving_lb=%p: shutting down pending lb_policy=%p",
 | 
	
		
			
				|  |  | +                this, pending_lb_policy_.get());
 | 
	
		
			
				|  |  | +      }
 | 
	
		
			
				|  |  | +      grpc_pollset_set_del_pollset_set(pending_lb_policy_->interested_parties(),
 | 
	
		
			
				|  |  | +                                       interested_parties());
 | 
	
		
			
				|  |  | +      pending_lb_policy_.reset();
 | 
	
		
			
				|  |  |      }
 | 
	
		
			
				|  |  | -    grpc_pollset_set_del_pollset_set(lb_policy_->interested_parties(),
 | 
	
		
			
				|  |  | -                                     interested_parties());
 | 
	
		
			
				|  |  | -    lb_policy_.reset();
 | 
	
		
			
				|  |  |    }
 | 
	
		
			
				|  |  |    if (resolver_ != nullptr) {
 | 
	
		
			
				|  |  |      // This should never happen; it can only be triggered by a resolver
 | 
	
	
		
			
				|  | @@ -260,53 +338,142 @@ void ResolvingLoadBalancingPolicy::OnResolverShutdownLocked(grpc_error* error) {
 | 
	
		
			
				|  |  |    Unref();
 | 
	
		
			
				|  |  |  }
 | 
	
		
			
				|  |  |  
 | 
	
		
			
				|  |  | -// Creates a new LB policy, replacing any previous one.
 | 
	
		
			
				|  |  | +void ResolvingLoadBalancingPolicy::CreateOrUpdateLbPolicyLocked(
 | 
	
		
			
				|  |  | +    const char* lb_policy_name, RefCountedPtr<Config> lb_policy_config,
 | 
	
		
			
				|  |  | +    TraceStringVector* trace_strings) {
 | 
	
		
			
				|  |  | +  // If the child policy name changes, we need to create a new child
 | 
	
		
			
				|  |  | +  // policy.  When this happens, we leave child_policy_ as-is and store
 | 
	
		
			
				|  |  | +  // the new child policy in pending_child_policy_.  Once the new child
 | 
	
		
			
				|  |  | +  // policy transitions into state READY, we swap it into child_policy_,
 | 
	
		
			
				|  |  | +  // replacing the original child policy.  So pending_child_policy_ is
 | 
	
		
			
				|  |  | +  // non-null only between when we apply an update that changes the child
 | 
	
		
			
				|  |  | +  // policy name and when the new child reports state READY.
 | 
	
		
			
				|  |  | +  //
 | 
	
		
			
				|  |  | +  // Updates can arrive at any point during this transition.  We always
 | 
	
		
			
				|  |  | +  // apply updates relative to the most recently created child policy,
 | 
	
		
			
				|  |  | +  // even if the most recent one is still in pending_child_policy_.  This
 | 
	
		
			
				|  |  | +  // is true both when applying the updates to an existing child policy
 | 
	
		
			
				|  |  | +  // and when determining whether we need to create a new policy.
 | 
	
		
			
				|  |  | +  //
 | 
	
		
			
				|  |  | +  // As a result of this, there are several cases to consider here:
 | 
	
		
			
				|  |  | +  //
 | 
	
		
			
				|  |  | +  // 1. We have no existing child policy (i.e., we have started up but
 | 
	
		
			
				|  |  | +  //    have not yet received a serverlist from the balancer or gone
 | 
	
		
			
				|  |  | +  //    into fallback mode; in this case, both child_policy_ and
 | 
	
		
			
				|  |  | +  //    pending_child_policy_ are null).  In this case, we create a
 | 
	
		
			
				|  |  | +  //    new child policy and store it in child_policy_.
 | 
	
		
			
				|  |  | +  //
 | 
	
		
			
				|  |  | +  // 2. We have an existing child policy and have no pending child policy
 | 
	
		
			
				|  |  | +  //    from a previous update (i.e., either there has not been a
 | 
	
		
			
				|  |  | +  //    previous update that changed the policy name, or we have already
 | 
	
		
			
				|  |  | +  //    finished swapping in the new policy; in this case, child_policy_
 | 
	
		
			
				|  |  | +  //    is non-null but pending_child_policy_ is null).  In this case:
 | 
	
		
			
				|  |  | +  //    a. If child_policy_->name() equals child_policy_name, then we
 | 
	
		
			
				|  |  | +  //       update the existing child policy.
 | 
	
		
			
				|  |  | +  //    b. If child_policy_->name() does not equal child_policy_name,
 | 
	
		
			
				|  |  | +  //       we create a new policy.  The policy will be stored in
 | 
	
		
			
				|  |  | +  //       pending_child_policy_ and will later be swapped into
 | 
	
		
			
				|  |  | +  //       child_policy_ by the helper when the new child transitions
 | 
	
		
			
				|  |  | +  //       into state READY.
 | 
	
		
			
				|  |  | +  //
 | 
	
		
			
				|  |  | +  // 3. We have an existing child policy and have a pending child policy
 | 
	
		
			
				|  |  | +  //    from a previous update (i.e., a previous update set
 | 
	
		
			
				|  |  | +  //    pending_child_policy_ as per case 2b above and that policy has
 | 
	
		
			
				|  |  | +  //    not yet transitioned into state READY and been swapped into
 | 
	
		
			
				|  |  | +  //    child_policy_; in this case, both child_policy_ and
 | 
	
		
			
				|  |  | +  //    pending_child_policy_ are non-null).  In this case:
 | 
	
		
			
				|  |  | +  //    a. If pending_child_policy_->name() equals child_policy_name,
 | 
	
		
			
				|  |  | +  //       then we update the existing pending child policy.
 | 
	
		
			
				|  |  | +  //    b. If pending_child_policy->name() does not equal
 | 
	
		
			
				|  |  | +  //       child_policy_name, then we create a new policy.  The new
 | 
	
		
			
				|  |  | +  //       policy is stored in pending_child_policy_ (replacing the one
 | 
	
		
			
				|  |  | +  //       that was there before, which will be immediately shut down)
 | 
	
		
			
				|  |  | +  //       and will later be swapped into child_policy_ by the helper
 | 
	
		
			
				|  |  | +  //       when the new child transitions into state READY.
 | 
	
		
			
				|  |  | +  const bool create_policy =
 | 
	
		
			
				|  |  | +      // case 1
 | 
	
		
			
				|  |  | +      lb_policy_ == nullptr ||
 | 
	
		
			
				|  |  | +      // case 2b
 | 
	
		
			
				|  |  | +      (pending_lb_policy_ == nullptr &&
 | 
	
		
			
				|  |  | +       strcmp(lb_policy_->name(), lb_policy_name) != 0) ||
 | 
	
		
			
				|  |  | +      // case 3b
 | 
	
		
			
				|  |  | +      (pending_lb_policy_ != nullptr &&
 | 
	
		
			
				|  |  | +       strcmp(pending_lb_policy_->name(), lb_policy_name) != 0);
 | 
	
		
			
				|  |  | +  LoadBalancingPolicy* policy_to_update = nullptr;
 | 
	
		
			
				|  |  | +  if (create_policy) {
 | 
	
		
			
				|  |  | +    // Cases 1, 2b, and 3b: create a new child policy.
 | 
	
		
			
				|  |  | +    // If lb_policy_ is null, we set it (case 1), else we set
 | 
	
		
			
				|  |  | +    // pending_lb_policy_ (cases 2b and 3b).
 | 
	
		
			
				|  |  | +    if (tracer_->enabled()) {
 | 
	
		
			
				|  |  | +      gpr_log(GPR_INFO, "resolving_lb=%p: Creating new %schild policy %s", this,
 | 
	
		
			
				|  |  | +              lb_policy_ == nullptr ? "" : "pending ", lb_policy_name);
 | 
	
		
			
				|  |  | +    }
 | 
	
		
			
				|  |  | +    auto new_policy = CreateLbPolicyLocked(lb_policy_name, trace_strings);
 | 
	
		
			
				|  |  | +    auto& lb_policy = lb_policy_ == nullptr ? lb_policy_ : pending_lb_policy_;
 | 
	
		
			
				|  |  | +    {
 | 
	
		
			
				|  |  | +      MutexLock lock(&lb_policy_mu_);
 | 
	
		
			
				|  |  | +      lb_policy = std::move(new_policy);
 | 
	
		
			
				|  |  | +    }
 | 
	
		
			
				|  |  | +    policy_to_update = lb_policy.get();
 | 
	
		
			
				|  |  | +  } else {
 | 
	
		
			
				|  |  | +    // Cases 2a and 3a: update an existing policy.
 | 
	
		
			
				|  |  | +    // If we have a pending child policy, send the update to the pending
 | 
	
		
			
				|  |  | +    // policy (case 3a), else send it to the current policy (case 2a).
 | 
	
		
			
				|  |  | +    policy_to_update = pending_lb_policy_ != nullptr ? pending_lb_policy_.get()
 | 
	
		
			
				|  |  | +                                                     : lb_policy_.get();
 | 
	
		
			
				|  |  | +  }
 | 
	
		
			
				|  |  | +  GPR_ASSERT(policy_to_update != nullptr);
 | 
	
		
			
				|  |  | +  // Update the policy.
 | 
	
		
			
				|  |  | +  if (tracer_->enabled()) {
 | 
	
		
			
				|  |  | +    gpr_log(GPR_INFO, "resolving_lb=%p: Updating %schild policy %p", this,
 | 
	
		
			
				|  |  | +            policy_to_update == pending_lb_policy_.get() ? "pending " : "",
 | 
	
		
			
				|  |  | +            policy_to_update);
 | 
	
		
			
				|  |  | +  }
 | 
	
		
			
				|  |  | +  policy_to_update->UpdateLocked(*resolver_result_,
 | 
	
		
			
				|  |  | +                                 std::move(lb_policy_config));
 | 
	
		
			
				|  |  | +}
 | 
	
		
			
				|  |  | +
 | 
	
		
			
				|  |  | +// Creates a new LB policy.
 | 
	
		
			
				|  |  |  // Updates trace_strings to indicate what was done.
 | 
	
		
			
				|  |  | -void ResolvingLoadBalancingPolicy::CreateNewLbPolicyLocked(
 | 
	
		
			
				|  |  | +OrphanablePtr<LoadBalancingPolicy>
 | 
	
		
			
				|  |  | +ResolvingLoadBalancingPolicy::CreateLbPolicyLocked(
 | 
	
		
			
				|  |  |      const char* lb_policy_name, TraceStringVector* trace_strings) {
 | 
	
		
			
				|  |  | +  ResolvingControlHelper* helper = New<ResolvingControlHelper>(Ref());
 | 
	
		
			
				|  |  |    LoadBalancingPolicy::Args lb_policy_args;
 | 
	
		
			
				|  |  |    lb_policy_args.combiner = combiner();
 | 
	
		
			
				|  |  |    lb_policy_args.channel_control_helper =
 | 
	
		
			
				|  |  | -      UniquePtr<ChannelControlHelper>(New<ResolvingControlHelper>(Ref()));
 | 
	
		
			
				|  |  | +      UniquePtr<ChannelControlHelper>(helper);
 | 
	
		
			
				|  |  |    lb_policy_args.args = resolver_result_;
 | 
	
		
			
				|  |  | -  OrphanablePtr<LoadBalancingPolicy> new_lb_policy =
 | 
	
		
			
				|  |  | +  OrphanablePtr<LoadBalancingPolicy> lb_policy =
 | 
	
		
			
				|  |  |        LoadBalancingPolicyRegistry::CreateLoadBalancingPolicy(
 | 
	
		
			
				|  |  |            lb_policy_name, std::move(lb_policy_args));
 | 
	
		
			
				|  |  | -  if (GPR_UNLIKELY(new_lb_policy == nullptr)) {
 | 
	
		
			
				|  |  | +  if (GPR_UNLIKELY(lb_policy == nullptr)) {
 | 
	
		
			
				|  |  |      gpr_log(GPR_ERROR, "could not create LB policy \"%s\"", lb_policy_name);
 | 
	
		
			
				|  |  |      if (channelz_node() != nullptr) {
 | 
	
		
			
				|  |  |        char* str;
 | 
	
		
			
				|  |  |        gpr_asprintf(&str, "Could not create LB policy \"%s\"", lb_policy_name);
 | 
	
		
			
				|  |  |        trace_strings->push_back(str);
 | 
	
		
			
				|  |  |      }
 | 
	
		
			
				|  |  | -  } else {
 | 
	
		
			
				|  |  | -    if (tracer_->enabled()) {
 | 
	
		
			
				|  |  | -      gpr_log(GPR_INFO, "resolving_lb=%p: created new LB policy \"%s\" (%p)",
 | 
	
		
			
				|  |  | -              this, lb_policy_name, new_lb_policy.get());
 | 
	
		
			
				|  |  | -    }
 | 
	
		
			
				|  |  | -    if (channelz_node() != nullptr) {
 | 
	
		
			
				|  |  | -      char* str;
 | 
	
		
			
				|  |  | -      gpr_asprintf(&str, "Created new LB policy \"%s\"", lb_policy_name);
 | 
	
		
			
				|  |  | -      trace_strings->push_back(str);
 | 
	
		
			
				|  |  | -    }
 | 
	
		
			
				|  |  | -    // Propagate channelz node.
 | 
	
		
			
				|  |  | -    auto* channelz = channelz_node();
 | 
	
		
			
				|  |  | -    if (channelz != nullptr) {
 | 
	
		
			
				|  |  | -      new_lb_policy->set_channelz_node(channelz->Ref());
 | 
	
		
			
				|  |  | -    }
 | 
	
		
			
				|  |  | -    // Swap out the LB policy and update the fds in interested_parties_.
 | 
	
		
			
				|  |  | -    if (lb_policy_ != nullptr) {
 | 
	
		
			
				|  |  | -      if (tracer_->enabled()) {
 | 
	
		
			
				|  |  | -        gpr_log(GPR_INFO, "resolving_lb=%p: shutting down lb_policy=%p", this,
 | 
	
		
			
				|  |  | -                lb_policy_.get());
 | 
	
		
			
				|  |  | -      }
 | 
	
		
			
				|  |  | -      grpc_pollset_set_del_pollset_set(lb_policy_->interested_parties(),
 | 
	
		
			
				|  |  | -                                       interested_parties());
 | 
	
		
			
				|  |  | -    }
 | 
	
		
			
				|  |  | -    lb_policy_ = std::move(new_lb_policy);
 | 
	
		
			
				|  |  | -    grpc_pollset_set_add_pollset_set(lb_policy_->interested_parties(),
 | 
	
		
			
				|  |  | -                                     interested_parties());
 | 
	
		
			
				|  |  | +    return nullptr;
 | 
	
		
			
				|  |  | +  }
 | 
	
		
			
				|  |  | +  helper->set_child(lb_policy.get());
 | 
	
		
			
				|  |  | +  if (tracer_->enabled()) {
 | 
	
		
			
				|  |  | +    gpr_log(GPR_INFO, "resolving_lb=%p: created new LB policy \"%s\" (%p)",
 | 
	
		
			
				|  |  | +            this, lb_policy_name, lb_policy.get());
 | 
	
		
			
				|  |  | +  }
 | 
	
		
			
				|  |  | +  if (channelz_node() != nullptr) {
 | 
	
		
			
				|  |  | +    char* str;
 | 
	
		
			
				|  |  | +    gpr_asprintf(&str, "Created new LB policy \"%s\"", lb_policy_name);
 | 
	
		
			
				|  |  | +    trace_strings->push_back(str);
 | 
	
		
			
				|  |  | +  }
 | 
	
		
			
				|  |  | +  // Propagate channelz node.
 | 
	
		
			
				|  |  | +  auto* channelz = channelz_node();
 | 
	
		
			
				|  |  | +  if (channelz != nullptr) {
 | 
	
		
			
				|  |  | +    lb_policy->set_channelz_node(channelz->Ref());
 | 
	
		
			
				|  |  |    }
 | 
	
		
			
				|  |  | +  grpc_pollset_set_add_pollset_set(lb_policy->interested_parties(),
 | 
	
		
			
				|  |  | +                                   interested_parties());
 | 
	
		
			
				|  |  | +  return lb_policy;
 | 
	
		
			
				|  |  |  }
 | 
	
		
			
				|  |  |  
 | 
	
		
			
				|  |  |  void ResolvingLoadBalancingPolicy::MaybeAddTraceMessagesForAddressChangesLocked(
 | 
	
	
		
			
				|  | @@ -415,23 +582,8 @@ void ResolvingLoadBalancingPolicy::OnResolverResultChangedLocked(
 | 
	
		
			
				|  |  |        lb_policy_config = self->child_lb_config_;
 | 
	
		
			
				|  |  |      }
 | 
	
		
			
				|  |  |      GPR_ASSERT(lb_policy_name != nullptr);
 | 
	
		
			
				|  |  | -    // If we're not already using the right LB policy name, instantiate
 | 
	
		
			
				|  |  | -    // a new one.
 | 
	
		
			
				|  |  | -    if (self->lb_policy_ == nullptr ||
 | 
	
		
			
				|  |  | -        strcmp(self->lb_policy_->name(), lb_policy_name) != 0) {
 | 
	
		
			
				|  |  | -      if (self->tracer_->enabled()) {
 | 
	
		
			
				|  |  | -        gpr_log(GPR_INFO, "resolving_lb=%p: creating new LB policy \"%s\"",
 | 
	
		
			
				|  |  | -                self, lb_policy_name);
 | 
	
		
			
				|  |  | -      }
 | 
	
		
			
				|  |  | -      self->CreateNewLbPolicyLocked(lb_policy_name, &trace_strings);
 | 
	
		
			
				|  |  | -    }
 | 
	
		
			
				|  |  | -    // Update the LB policy with the new addresses and config.
 | 
	
		
			
				|  |  | -    if (self->tracer_->enabled()) {
 | 
	
		
			
				|  |  | -      gpr_log(GPR_INFO, "resolving_lb=%p: updating LB policy \"%s\" (%p)", self,
 | 
	
		
			
				|  |  | -              lb_policy_name, self->lb_policy_.get());
 | 
	
		
			
				|  |  | -    }
 | 
	
		
			
				|  |  | -    self->lb_policy_->UpdateLocked(*self->resolver_result_,
 | 
	
		
			
				|  |  | -                                   std::move(lb_policy_config));
 | 
	
		
			
				|  |  | +    self->CreateOrUpdateLbPolicyLocked(
 | 
	
		
			
				|  |  | +        lb_policy_name, std::move(lb_policy_config), &trace_strings);
 | 
	
		
			
				|  |  |      // Add channel trace event.
 | 
	
		
			
				|  |  |      if (self->channelz_node() != nullptr) {
 | 
	
		
			
				|  |  |        if (service_config_changed) {
 |