|  | @@ -1,537 +0,0 @@
 | 
	
		
			
				|  |  | -//
 | 
	
		
			
				|  |  | -// Copyright 2018 gRPC authors.
 | 
	
		
			
				|  |  | -//
 | 
	
		
			
				|  |  | -// Licensed under the Apache License, Version 2.0 (the "License");
 | 
	
		
			
				|  |  | -// you may not use this file except in compliance with the License.
 | 
	
		
			
				|  |  | -// You may obtain a copy of the License at
 | 
	
		
			
				|  |  | -//
 | 
	
		
			
				|  |  | -//     http://www.apache.org/licenses/LICENSE-2.0
 | 
	
		
			
				|  |  | -//
 | 
	
		
			
				|  |  | -// Unless required by applicable law or agreed to in writing, software
 | 
	
		
			
				|  |  | -// distributed under the License is distributed on an "AS IS" BASIS,
 | 
	
		
			
				|  |  | -// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 | 
	
		
			
				|  |  | -// See the License for the specific language governing permissions and
 | 
	
		
			
				|  |  | -// limitations under the License.
 | 
	
		
			
				|  |  | -//
 | 
	
		
			
				|  |  | -
 | 
	
		
			
				|  |  | -#include <grpc/support/port_platform.h>
 | 
	
		
			
				|  |  | -
 | 
	
		
			
				|  |  | -#include <grpc/grpc.h>
 | 
	
		
			
				|  |  | -
 | 
	
		
			
				|  |  | -#include "src/core/ext/filters/client_channel/lb_policy.h"
 | 
	
		
			
				|  |  | -#include "src/core/ext/filters/client_channel/lb_policy/child_policy_handler.h"
 | 
	
		
			
				|  |  | -#include "src/core/ext/filters/client_channel/lb_policy_factory.h"
 | 
	
		
			
				|  |  | -#include "src/core/ext/filters/client_channel/lb_policy_registry.h"
 | 
	
		
			
				|  |  | -#include "src/core/ext/xds/xds_client.h"
 | 
	
		
			
				|  |  | -#include "src/core/ext/xds/xds_client_stats.h"
 | 
	
		
			
				|  |  | -#include "src/core/lib/channel/channel_args.h"
 | 
	
		
			
				|  |  | -#include "src/core/lib/gprpp/orphanable.h"
 | 
	
		
			
				|  |  | -#include "src/core/lib/gprpp/ref_counted_ptr.h"
 | 
	
		
			
				|  |  | -#include "src/core/lib/iomgr/work_serializer.h"
 | 
	
		
			
				|  |  | -
 | 
	
		
			
				|  |  | -namespace grpc_core {
 | 
	
		
			
				|  |  | -
 | 
	
		
			
				|  |  | -TraceFlag grpc_lb_lrs_trace(false, "lrs_lb");
 | 
	
		
			
				|  |  | -
 | 
	
		
			
				|  |  | -namespace {
 | 
	
		
			
				|  |  | -
 | 
	
		
			
				|  |  | -constexpr char kLrs[] = "lrs_experimental";
 | 
	
		
			
				|  |  | -
 | 
	
		
			
				|  |  | -// Config for LRS LB policy.
 | 
	
		
			
				|  |  | -class LrsLbConfig : public LoadBalancingPolicy::Config {
 | 
	
		
			
				|  |  | - public:
 | 
	
		
			
				|  |  | -  LrsLbConfig(RefCountedPtr<LoadBalancingPolicy::Config> child_policy,
 | 
	
		
			
				|  |  | -              std::string cluster_name, std::string eds_service_name,
 | 
	
		
			
				|  |  | -              std::string lrs_load_reporting_server_name,
 | 
	
		
			
				|  |  | -              RefCountedPtr<XdsLocalityName> locality_name)
 | 
	
		
			
				|  |  | -      : child_policy_(std::move(child_policy)),
 | 
	
		
			
				|  |  | -        cluster_name_(std::move(cluster_name)),
 | 
	
		
			
				|  |  | -        eds_service_name_(std::move(eds_service_name)),
 | 
	
		
			
				|  |  | -        lrs_load_reporting_server_name_(
 | 
	
		
			
				|  |  | -            std::move(lrs_load_reporting_server_name)),
 | 
	
		
			
				|  |  | -        locality_name_(std::move(locality_name)) {}
 | 
	
		
			
				|  |  | -
 | 
	
		
			
				|  |  | -  const char* name() const override { return kLrs; }
 | 
	
		
			
				|  |  | -
 | 
	
		
			
				|  |  | -  RefCountedPtr<LoadBalancingPolicy::Config> child_policy() const {
 | 
	
		
			
				|  |  | -    return child_policy_;
 | 
	
		
			
				|  |  | -  }
 | 
	
		
			
				|  |  | -  const std::string& cluster_name() const { return cluster_name_; }
 | 
	
		
			
				|  |  | -  const std::string& eds_service_name() const { return eds_service_name_; }
 | 
	
		
			
				|  |  | -  const std::string& lrs_load_reporting_server_name() const {
 | 
	
		
			
				|  |  | -    return lrs_load_reporting_server_name_;
 | 
	
		
			
				|  |  | -  };
 | 
	
		
			
				|  |  | -  RefCountedPtr<XdsLocalityName> locality_name() const {
 | 
	
		
			
				|  |  | -    return locality_name_;
 | 
	
		
			
				|  |  | -  }
 | 
	
		
			
				|  |  | -
 | 
	
		
			
				|  |  | - private:
 | 
	
		
			
				|  |  | -  RefCountedPtr<LoadBalancingPolicy::Config> child_policy_;
 | 
	
		
			
				|  |  | -  std::string cluster_name_;
 | 
	
		
			
				|  |  | -  std::string eds_service_name_;
 | 
	
		
			
				|  |  | -  std::string lrs_load_reporting_server_name_;
 | 
	
		
			
				|  |  | -  RefCountedPtr<XdsLocalityName> locality_name_;
 | 
	
		
			
				|  |  | -};
 | 
	
		
			
				|  |  | -
 | 
	
		
			
				|  |  | -// LRS LB policy.
 | 
	
		
			
				|  |  | -class LrsLb : public LoadBalancingPolicy {
 | 
	
		
			
				|  |  | - public:
 | 
	
		
			
				|  |  | -  LrsLb(RefCountedPtr<XdsClient> xds_client, Args args);
 | 
	
		
			
				|  |  | -
 | 
	
		
			
				|  |  | -  const char* name() const override { return kLrs; }
 | 
	
		
			
				|  |  | -
 | 
	
		
			
				|  |  | -  void UpdateLocked(UpdateArgs args) override;
 | 
	
		
			
				|  |  | -  void ExitIdleLocked() override;
 | 
	
		
			
				|  |  | -  void ResetBackoffLocked() override;
 | 
	
		
			
				|  |  | -
 | 
	
		
			
				|  |  | - private:
 | 
	
		
			
				|  |  | -  // A simple wrapper for ref-counting a picker from the child policy.
 | 
	
		
			
				|  |  | -  class RefCountedPicker : public RefCounted<RefCountedPicker> {
 | 
	
		
			
				|  |  | -   public:
 | 
	
		
			
				|  |  | -    explicit RefCountedPicker(std::unique_ptr<SubchannelPicker> picker)
 | 
	
		
			
				|  |  | -        : picker_(std::move(picker)) {}
 | 
	
		
			
				|  |  | -    PickResult Pick(PickArgs args) { return picker_->Pick(args); }
 | 
	
		
			
				|  |  | -
 | 
	
		
			
				|  |  | -   private:
 | 
	
		
			
				|  |  | -    std::unique_ptr<SubchannelPicker> picker_;
 | 
	
		
			
				|  |  | -  };
 | 
	
		
			
				|  |  | -
 | 
	
		
			
				|  |  | -  // A picker that wraps the picker from the child to perform load reporting.
 | 
	
		
			
				|  |  | -  class LoadReportingPicker : public SubchannelPicker {
 | 
	
		
			
				|  |  | -   public:
 | 
	
		
			
				|  |  | -    LoadReportingPicker(RefCountedPtr<RefCountedPicker> picker,
 | 
	
		
			
				|  |  | -                        RefCountedPtr<XdsClusterLocalityStats> locality_stats)
 | 
	
		
			
				|  |  | -        : picker_(std::move(picker)),
 | 
	
		
			
				|  |  | -          locality_stats_(std::move(locality_stats)) {}
 | 
	
		
			
				|  |  | -
 | 
	
		
			
				|  |  | -    PickResult Pick(PickArgs args);
 | 
	
		
			
				|  |  | -
 | 
	
		
			
				|  |  | -   private:
 | 
	
		
			
				|  |  | -    RefCountedPtr<RefCountedPicker> picker_;
 | 
	
		
			
				|  |  | -    RefCountedPtr<XdsClusterLocalityStats> locality_stats_;
 | 
	
		
			
				|  |  | -  };
 | 
	
		
			
				|  |  | -
 | 
	
		
			
				|  |  | -  class Helper : public ChannelControlHelper {
 | 
	
		
			
				|  |  | -   public:
 | 
	
		
			
				|  |  | -    explicit Helper(RefCountedPtr<LrsLb> lrs_policy)
 | 
	
		
			
				|  |  | -        : lrs_policy_(std::move(lrs_policy)) {}
 | 
	
		
			
				|  |  | -
 | 
	
		
			
				|  |  | -    ~Helper() { lrs_policy_.reset(DEBUG_LOCATION, "Helper"); }
 | 
	
		
			
				|  |  | -
 | 
	
		
			
				|  |  | -    RefCountedPtr<SubchannelInterface> CreateSubchannel(
 | 
	
		
			
				|  |  | -        ServerAddress address, const grpc_channel_args& args) override;
 | 
	
		
			
				|  |  | -    void UpdateState(grpc_connectivity_state state, const absl::Status& status,
 | 
	
		
			
				|  |  | -                     std::unique_ptr<SubchannelPicker> picker) override;
 | 
	
		
			
				|  |  | -    void RequestReresolution() override;
 | 
	
		
			
				|  |  | -    void AddTraceEvent(TraceSeverity severity,
 | 
	
		
			
				|  |  | -                       absl::string_view message) override;
 | 
	
		
			
				|  |  | -
 | 
	
		
			
				|  |  | -   private:
 | 
	
		
			
				|  |  | -    RefCountedPtr<LrsLb> lrs_policy_;
 | 
	
		
			
				|  |  | -  };
 | 
	
		
			
				|  |  | -
 | 
	
		
			
				|  |  | -  ~LrsLb();
 | 
	
		
			
				|  |  | -
 | 
	
		
			
				|  |  | -  void ShutdownLocked() override;
 | 
	
		
			
				|  |  | -
 | 
	
		
			
				|  |  | -  OrphanablePtr<LoadBalancingPolicy> CreateChildPolicyLocked(
 | 
	
		
			
				|  |  | -      const grpc_channel_args* args);
 | 
	
		
			
				|  |  | -  void UpdateChildPolicyLocked(ServerAddressList addresses,
 | 
	
		
			
				|  |  | -                               const grpc_channel_args* args);
 | 
	
		
			
				|  |  | -
 | 
	
		
			
				|  |  | -  void MaybeUpdatePickerLocked();
 | 
	
		
			
				|  |  | -
 | 
	
		
			
				|  |  | -  // Current config from the resolver.
 | 
	
		
			
				|  |  | -  RefCountedPtr<LrsLbConfig> config_;
 | 
	
		
			
				|  |  | -
 | 
	
		
			
				|  |  | -  // Internal state.
 | 
	
		
			
				|  |  | -  bool shutting_down_ = false;
 | 
	
		
			
				|  |  | -
 | 
	
		
			
				|  |  | -  // The xds client.
 | 
	
		
			
				|  |  | -  RefCountedPtr<XdsClient> xds_client_;
 | 
	
		
			
				|  |  | -
 | 
	
		
			
				|  |  | -  // The stats for client-side load reporting.
 | 
	
		
			
				|  |  | -  RefCountedPtr<XdsClusterLocalityStats> locality_stats_;
 | 
	
		
			
				|  |  | -
 | 
	
		
			
				|  |  | -  OrphanablePtr<LoadBalancingPolicy> child_policy_;
 | 
	
		
			
				|  |  | -
 | 
	
		
			
				|  |  | -  // Latest state and picker reported by the child policy.
 | 
	
		
			
				|  |  | -  grpc_connectivity_state state_ = GRPC_CHANNEL_IDLE;
 | 
	
		
			
				|  |  | -  absl::Status status_;
 | 
	
		
			
				|  |  | -  RefCountedPtr<RefCountedPicker> picker_;
 | 
	
		
			
				|  |  | -};
 | 
	
		
			
				|  |  | -
 | 
	
		
			
				|  |  | -//
 | 
	
		
			
				|  |  | -// LrsLb::LoadReportingPicker
 | 
	
		
			
				|  |  | -//
 | 
	
		
			
				|  |  | -
 | 
	
		
			
				|  |  | -LoadBalancingPolicy::PickResult LrsLb::LoadReportingPicker::Pick(
 | 
	
		
			
				|  |  | -    LoadBalancingPolicy::PickArgs args) {
 | 
	
		
			
				|  |  | -  // Forward the pick to the picker returned from the child policy.
 | 
	
		
			
				|  |  | -  PickResult result = picker_->Pick(args);
 | 
	
		
			
				|  |  | -  if (result.type == PickResult::PICK_COMPLETE &&
 | 
	
		
			
				|  |  | -      result.subchannel != nullptr) {
 | 
	
		
			
				|  |  | -    // Record a call started.
 | 
	
		
			
				|  |  | -    locality_stats_->AddCallStarted();
 | 
	
		
			
				|  |  | -    // Intercept the recv_trailing_metadata op to record call completion.
 | 
	
		
			
				|  |  | -    XdsClusterLocalityStats* locality_stats =
 | 
	
		
			
				|  |  | -        locality_stats_->Ref(DEBUG_LOCATION, "LocalityStats+call").release();
 | 
	
		
			
				|  |  | -    result.recv_trailing_metadata_ready =
 | 
	
		
			
				|  |  | -        // Note: This callback does not run in either the control plane
 | 
	
		
			
				|  |  | -        // work serializer or in the data plane mutex.
 | 
	
		
			
				|  |  | -        [locality_stats](grpc_error* error, MetadataInterface* /*metadata*/,
 | 
	
		
			
				|  |  | -                         CallState* /*call_state*/) {
 | 
	
		
			
				|  |  | -          const bool call_failed = error != GRPC_ERROR_NONE;
 | 
	
		
			
				|  |  | -          locality_stats->AddCallFinished(call_failed);
 | 
	
		
			
				|  |  | -          locality_stats->Unref(DEBUG_LOCATION, "LocalityStats+call");
 | 
	
		
			
				|  |  | -        };
 | 
	
		
			
				|  |  | -  }
 | 
	
		
			
				|  |  | -  return result;
 | 
	
		
			
				|  |  | -}
 | 
	
		
			
				|  |  | -
 | 
	
		
			
				|  |  | -//
 | 
	
		
			
				|  |  | -// LrsLb
 | 
	
		
			
				|  |  | -//
 | 
	
		
			
				|  |  | -
 | 
	
		
			
				|  |  | -LrsLb::LrsLb(RefCountedPtr<XdsClient> xds_client, Args args)
 | 
	
		
			
				|  |  | -    : LoadBalancingPolicy(std::move(args)), xds_client_(std::move(xds_client)) {
 | 
	
		
			
				|  |  | -  if (GRPC_TRACE_FLAG_ENABLED(grpc_lb_lrs_trace)) {
 | 
	
		
			
				|  |  | -    gpr_log(GPR_INFO, "[lrs_lb %p] created -- using xds client %p", this,
 | 
	
		
			
				|  |  | -            xds_client_.get());
 | 
	
		
			
				|  |  | -  }
 | 
	
		
			
				|  |  | -}
 | 
	
		
			
				|  |  | -
 | 
	
		
			
				|  |  | -LrsLb::~LrsLb() {
 | 
	
		
			
				|  |  | -  if (GRPC_TRACE_FLAG_ENABLED(grpc_lb_lrs_trace)) {
 | 
	
		
			
				|  |  | -    gpr_log(GPR_INFO, "[lrs_lb %p] destroying xds LB policy", this);
 | 
	
		
			
				|  |  | -  }
 | 
	
		
			
				|  |  | -}
 | 
	
		
			
				|  |  | -
 | 
	
		
			
				|  |  | -void LrsLb::ShutdownLocked() {
 | 
	
		
			
				|  |  | -  if (GRPC_TRACE_FLAG_ENABLED(grpc_lb_lrs_trace)) {
 | 
	
		
			
				|  |  | -    gpr_log(GPR_INFO, "[lrs_lb %p] shutting down", this);
 | 
	
		
			
				|  |  | -  }
 | 
	
		
			
				|  |  | -  shutting_down_ = true;
 | 
	
		
			
				|  |  | -  // Remove the child policy's interested_parties pollset_set from the
 | 
	
		
			
				|  |  | -  // xDS policy.
 | 
	
		
			
				|  |  | -  if (child_policy_ != nullptr) {
 | 
	
		
			
				|  |  | -    grpc_pollset_set_del_pollset_set(child_policy_->interested_parties(),
 | 
	
		
			
				|  |  | -                                     interested_parties());
 | 
	
		
			
				|  |  | -    child_policy_.reset();
 | 
	
		
			
				|  |  | -  }
 | 
	
		
			
				|  |  | -  // Drop our ref to the child's picker, in case it's holding a ref to
 | 
	
		
			
				|  |  | -  // the child.
 | 
	
		
			
				|  |  | -  picker_.reset();
 | 
	
		
			
				|  |  | -  locality_stats_.reset();
 | 
	
		
			
				|  |  | -  xds_client_.reset();
 | 
	
		
			
				|  |  | -}
 | 
	
		
			
				|  |  | -
 | 
	
		
			
				|  |  | -void LrsLb::ExitIdleLocked() {
 | 
	
		
			
				|  |  | -  if (child_policy_ != nullptr) child_policy_->ExitIdleLocked();
 | 
	
		
			
				|  |  | -}
 | 
	
		
			
				|  |  | -
 | 
	
		
			
				|  |  | -void LrsLb::ResetBackoffLocked() {
 | 
	
		
			
				|  |  | -  // The XdsClient will have its backoff reset by the xds resolver, so we
 | 
	
		
			
				|  |  | -  // don't need to do it here.
 | 
	
		
			
				|  |  | -  if (child_policy_ != nullptr) child_policy_->ResetBackoffLocked();
 | 
	
		
			
				|  |  | -}
 | 
	
		
			
				|  |  | -
 | 
	
		
			
				|  |  | -void LrsLb::UpdateLocked(UpdateArgs args) {
 | 
	
		
			
				|  |  | -  if (GRPC_TRACE_FLAG_ENABLED(grpc_lb_lrs_trace)) {
 | 
	
		
			
				|  |  | -    gpr_log(GPR_INFO, "[lrs_lb %p] Received update", this);
 | 
	
		
			
				|  |  | -  }
 | 
	
		
			
				|  |  | -  // Update config.
 | 
	
		
			
				|  |  | -  auto old_config = std::move(config_);
 | 
	
		
			
				|  |  | -  config_ = std::move(args.config);
 | 
	
		
			
				|  |  | -  // Update load reporting if needed.
 | 
	
		
			
				|  |  | -  if (old_config == nullptr ||
 | 
	
		
			
				|  |  | -      config_->lrs_load_reporting_server_name() !=
 | 
	
		
			
				|  |  | -          old_config->lrs_load_reporting_server_name() ||
 | 
	
		
			
				|  |  | -      config_->cluster_name() != old_config->cluster_name() ||
 | 
	
		
			
				|  |  | -      config_->eds_service_name() != old_config->eds_service_name() ||
 | 
	
		
			
				|  |  | -      *config_->locality_name() != *old_config->locality_name()) {
 | 
	
		
			
				|  |  | -    locality_stats_ = xds_client_->AddClusterLocalityStats(
 | 
	
		
			
				|  |  | -        config_->lrs_load_reporting_server_name(), config_->cluster_name(),
 | 
	
		
			
				|  |  | -        config_->eds_service_name(), config_->locality_name());
 | 
	
		
			
				|  |  | -    MaybeUpdatePickerLocked();
 | 
	
		
			
				|  |  | -  }
 | 
	
		
			
				|  |  | -  // Update child policy.
 | 
	
		
			
				|  |  | -  UpdateChildPolicyLocked(std::move(args.addresses), args.args);
 | 
	
		
			
				|  |  | -  args.args = nullptr;
 | 
	
		
			
				|  |  | -}
 | 
	
		
			
				|  |  | -
 | 
	
		
			
				|  |  | -void LrsLb::MaybeUpdatePickerLocked() {
 | 
	
		
			
				|  |  | -  if (picker_ != nullptr) {
 | 
	
		
			
				|  |  | -    auto lrs_picker =
 | 
	
		
			
				|  |  | -        absl::make_unique<LoadReportingPicker>(picker_, locality_stats_);
 | 
	
		
			
				|  |  | -    if (GRPC_TRACE_FLAG_ENABLED(grpc_lb_lrs_trace)) {
 | 
	
		
			
				|  |  | -      gpr_log(
 | 
	
		
			
				|  |  | -          GPR_INFO,
 | 
	
		
			
				|  |  | -          "[lrs_lb %p] updating connectivity: state=%s status=(%s) picker=%p",
 | 
	
		
			
				|  |  | -          this, ConnectivityStateName(state_), status_.ToString().c_str(),
 | 
	
		
			
				|  |  | -          lrs_picker.get());
 | 
	
		
			
				|  |  | -    }
 | 
	
		
			
				|  |  | -    channel_control_helper()->UpdateState(state_, status_,
 | 
	
		
			
				|  |  | -                                          std::move(lrs_picker));
 | 
	
		
			
				|  |  | -  }
 | 
	
		
			
				|  |  | -}
 | 
	
		
			
				|  |  | -
 | 
	
		
			
				|  |  | -OrphanablePtr<LoadBalancingPolicy> LrsLb::CreateChildPolicyLocked(
 | 
	
		
			
				|  |  | -    const grpc_channel_args* args) {
 | 
	
		
			
				|  |  | -  LoadBalancingPolicy::Args lb_policy_args;
 | 
	
		
			
				|  |  | -  lb_policy_args.work_serializer = work_serializer();
 | 
	
		
			
				|  |  | -  lb_policy_args.args = args;
 | 
	
		
			
				|  |  | -  lb_policy_args.channel_control_helper =
 | 
	
		
			
				|  |  | -      absl::make_unique<Helper>(Ref(DEBUG_LOCATION, "Helper"));
 | 
	
		
			
				|  |  | -  OrphanablePtr<LoadBalancingPolicy> lb_policy =
 | 
	
		
			
				|  |  | -      MakeOrphanable<ChildPolicyHandler>(std::move(lb_policy_args),
 | 
	
		
			
				|  |  | -                                         &grpc_lb_lrs_trace);
 | 
	
		
			
				|  |  | -  if (GRPC_TRACE_FLAG_ENABLED(grpc_lb_lrs_trace)) {
 | 
	
		
			
				|  |  | -    gpr_log(GPR_INFO, "[lrs_lb %p] Created new child policy handler %p", this,
 | 
	
		
			
				|  |  | -            lb_policy.get());
 | 
	
		
			
				|  |  | -  }
 | 
	
		
			
				|  |  | -  // Add our interested_parties pollset_set to that of the newly created
 | 
	
		
			
				|  |  | -  // child policy. This will make the child policy progress upon activity on
 | 
	
		
			
				|  |  | -  // this policy, which in turn is tied to the application's call.
 | 
	
		
			
				|  |  | -  grpc_pollset_set_add_pollset_set(lb_policy->interested_parties(),
 | 
	
		
			
				|  |  | -                                   interested_parties());
 | 
	
		
			
				|  |  | -  return lb_policy;
 | 
	
		
			
				|  |  | -}
 | 
	
		
			
				|  |  | -
 | 
	
		
			
				|  |  | -void LrsLb::UpdateChildPolicyLocked(ServerAddressList addresses,
 | 
	
		
			
				|  |  | -                                    const grpc_channel_args* args) {
 | 
	
		
			
				|  |  | -  // Create policy if needed.
 | 
	
		
			
				|  |  | -  if (child_policy_ == nullptr) {
 | 
	
		
			
				|  |  | -    child_policy_ = CreateChildPolicyLocked(args);
 | 
	
		
			
				|  |  | -  }
 | 
	
		
			
				|  |  | -  // Construct update args.
 | 
	
		
			
				|  |  | -  UpdateArgs update_args;
 | 
	
		
			
				|  |  | -  update_args.addresses = std::move(addresses);
 | 
	
		
			
				|  |  | -  update_args.config = config_->child_policy();
 | 
	
		
			
				|  |  | -  update_args.args = args;
 | 
	
		
			
				|  |  | -  // Update the policy.
 | 
	
		
			
				|  |  | -  if (GRPC_TRACE_FLAG_ENABLED(grpc_lb_lrs_trace)) {
 | 
	
		
			
				|  |  | -    gpr_log(GPR_INFO, "[lrs_lb %p] Updating child policy handler %p", this,
 | 
	
		
			
				|  |  | -            child_policy_.get());
 | 
	
		
			
				|  |  | -  }
 | 
	
		
			
				|  |  | -  child_policy_->UpdateLocked(std::move(update_args));
 | 
	
		
			
				|  |  | -}
 | 
	
		
			
				|  |  | -
 | 
	
		
			
				|  |  | -//
 | 
	
		
			
				|  |  | -// LrsLb::Helper
 | 
	
		
			
				|  |  | -//
 | 
	
		
			
				|  |  | -
 | 
	
		
			
				|  |  | -RefCountedPtr<SubchannelInterface> LrsLb::Helper::CreateSubchannel(
 | 
	
		
			
				|  |  | -    ServerAddress address, const grpc_channel_args& args) {
 | 
	
		
			
				|  |  | -  if (lrs_policy_->shutting_down_) return nullptr;
 | 
	
		
			
				|  |  | -  return lrs_policy_->channel_control_helper()->CreateSubchannel(
 | 
	
		
			
				|  |  | -      std::move(address), args);
 | 
	
		
			
				|  |  | -}
 | 
	
		
			
				|  |  | -
 | 
	
		
			
				|  |  | -void LrsLb::Helper::UpdateState(grpc_connectivity_state state,
 | 
	
		
			
				|  |  | -                                const absl::Status& status,
 | 
	
		
			
				|  |  | -                                std::unique_ptr<SubchannelPicker> picker) {
 | 
	
		
			
				|  |  | -  if (lrs_policy_->shutting_down_) return;
 | 
	
		
			
				|  |  | -  if (GRPC_TRACE_FLAG_ENABLED(grpc_lb_lrs_trace)) {
 | 
	
		
			
				|  |  | -    gpr_log(
 | 
	
		
			
				|  |  | -        GPR_INFO,
 | 
	
		
			
				|  |  | -        "[lrs_lb %p] child connectivity state update: state=%s (%s) picker=%p",
 | 
	
		
			
				|  |  | -        lrs_policy_.get(), ConnectivityStateName(state),
 | 
	
		
			
				|  |  | -        status.ToString().c_str(), picker.get());
 | 
	
		
			
				|  |  | -  }
 | 
	
		
			
				|  |  | -  // Save the state and picker.
 | 
	
		
			
				|  |  | -  lrs_policy_->state_ = state;
 | 
	
		
			
				|  |  | -  lrs_policy_->status_ = status;
 | 
	
		
			
				|  |  | -  lrs_policy_->picker_ = MakeRefCounted<RefCountedPicker>(std::move(picker));
 | 
	
		
			
				|  |  | -  // Wrap the picker and return it to the channel.
 | 
	
		
			
				|  |  | -  lrs_policy_->MaybeUpdatePickerLocked();
 | 
	
		
			
				|  |  | -}
 | 
	
		
			
				|  |  | -
 | 
	
		
			
				|  |  | -void LrsLb::Helper::RequestReresolution() {
 | 
	
		
			
				|  |  | -  if (lrs_policy_->shutting_down_) return;
 | 
	
		
			
				|  |  | -  lrs_policy_->channel_control_helper()->RequestReresolution();
 | 
	
		
			
				|  |  | -}
 | 
	
		
			
				|  |  | -
 | 
	
		
			
				|  |  | -void LrsLb::Helper::AddTraceEvent(TraceSeverity severity,
 | 
	
		
			
				|  |  | -                                  absl::string_view message) {
 | 
	
		
			
				|  |  | -  if (lrs_policy_->shutting_down_) return;
 | 
	
		
			
				|  |  | -  lrs_policy_->channel_control_helper()->AddTraceEvent(severity, message);
 | 
	
		
			
				|  |  | -}
 | 
	
		
			
				|  |  | -
 | 
	
		
			
				|  |  | -//
 | 
	
		
			
				|  |  | -// factory
 | 
	
		
			
				|  |  | -//
 | 
	
		
			
				|  |  | -
 | 
	
		
			
				|  |  | -class LrsLbFactory : public LoadBalancingPolicyFactory {
 | 
	
		
			
				|  |  | - public:
 | 
	
		
			
				|  |  | -  OrphanablePtr<LoadBalancingPolicy> CreateLoadBalancingPolicy(
 | 
	
		
			
				|  |  | -      LoadBalancingPolicy::Args args) const override {
 | 
	
		
			
				|  |  | -    grpc_error* error = GRPC_ERROR_NONE;
 | 
	
		
			
				|  |  | -    RefCountedPtr<XdsClient> xds_client = XdsClient::GetOrCreate(&error);
 | 
	
		
			
				|  |  | -    if (error != GRPC_ERROR_NONE) {
 | 
	
		
			
				|  |  | -      gpr_log(GPR_ERROR,
 | 
	
		
			
				|  |  | -              "cannot get XdsClient to instantiate lrs LB policy: %s",
 | 
	
		
			
				|  |  | -              grpc_error_string(error));
 | 
	
		
			
				|  |  | -      GRPC_ERROR_UNREF(error);
 | 
	
		
			
				|  |  | -      return nullptr;
 | 
	
		
			
				|  |  | -    }
 | 
	
		
			
				|  |  | -    return MakeOrphanable<LrsLb>(std::move(xds_client), std::move(args));
 | 
	
		
			
				|  |  | -  }
 | 
	
		
			
				|  |  | -
 | 
	
		
			
				|  |  | -  const char* name() const override { return kLrs; }
 | 
	
		
			
				|  |  | -
 | 
	
		
			
				|  |  | -  RefCountedPtr<LoadBalancingPolicy::Config> ParseLoadBalancingConfig(
 | 
	
		
			
				|  |  | -      const Json& json, grpc_error** error) const override {
 | 
	
		
			
				|  |  | -    GPR_DEBUG_ASSERT(error != nullptr && *error == GRPC_ERROR_NONE);
 | 
	
		
			
				|  |  | -    if (json.type() == Json::Type::JSON_NULL) {
 | 
	
		
			
				|  |  | -      // lrs was mentioned as a policy in the deprecated loadBalancingPolicy
 | 
	
		
			
				|  |  | -      // field or in the client API.
 | 
	
		
			
				|  |  | -      *error = GRPC_ERROR_CREATE_FROM_STATIC_STRING(
 | 
	
		
			
				|  |  | -          "field:loadBalancingPolicy error:lrs policy requires configuration. "
 | 
	
		
			
				|  |  | -          "Please use loadBalancingConfig field of service config instead.");
 | 
	
		
			
				|  |  | -      return nullptr;
 | 
	
		
			
				|  |  | -    }
 | 
	
		
			
				|  |  | -    std::vector<grpc_error*> error_list;
 | 
	
		
			
				|  |  | -    // Child policy.
 | 
	
		
			
				|  |  | -    RefCountedPtr<LoadBalancingPolicy::Config> child_policy;
 | 
	
		
			
				|  |  | -    auto it = json.object_value().find("childPolicy");
 | 
	
		
			
				|  |  | -    if (it == json.object_value().end()) {
 | 
	
		
			
				|  |  | -      error_list.push_back(GRPC_ERROR_CREATE_FROM_STATIC_STRING(
 | 
	
		
			
				|  |  | -          "field:childPolicy error:required field missing"));
 | 
	
		
			
				|  |  | -    } else {
 | 
	
		
			
				|  |  | -      grpc_error* parse_error = GRPC_ERROR_NONE;
 | 
	
		
			
				|  |  | -      child_policy = LoadBalancingPolicyRegistry::ParseLoadBalancingConfig(
 | 
	
		
			
				|  |  | -          it->second, &parse_error);
 | 
	
		
			
				|  |  | -      if (child_policy == nullptr) {
 | 
	
		
			
				|  |  | -        GPR_DEBUG_ASSERT(parse_error != GRPC_ERROR_NONE);
 | 
	
		
			
				|  |  | -        std::vector<grpc_error*> child_errors;
 | 
	
		
			
				|  |  | -        child_errors.push_back(parse_error);
 | 
	
		
			
				|  |  | -        error_list.push_back(
 | 
	
		
			
				|  |  | -            GRPC_ERROR_CREATE_FROM_VECTOR("field:childPolicy", &child_errors));
 | 
	
		
			
				|  |  | -      }
 | 
	
		
			
				|  |  | -    }
 | 
	
		
			
				|  |  | -    // Cluster name.
 | 
	
		
			
				|  |  | -    std::string cluster_name;
 | 
	
		
			
				|  |  | -    it = json.object_value().find("clusterName");
 | 
	
		
			
				|  |  | -    if (it == json.object_value().end()) {
 | 
	
		
			
				|  |  | -      error_list.push_back(GRPC_ERROR_CREATE_FROM_STATIC_STRING(
 | 
	
		
			
				|  |  | -          "field:clusterName error:required field missing"));
 | 
	
		
			
				|  |  | -    } else if (it->second.type() != Json::Type::STRING) {
 | 
	
		
			
				|  |  | -      error_list.push_back(GRPC_ERROR_CREATE_FROM_STATIC_STRING(
 | 
	
		
			
				|  |  | -          "field:clusterName error:type should be string"));
 | 
	
		
			
				|  |  | -    } else {
 | 
	
		
			
				|  |  | -      cluster_name = it->second.string_value();
 | 
	
		
			
				|  |  | -    }
 | 
	
		
			
				|  |  | -    // EDS service name.
 | 
	
		
			
				|  |  | -    std::string eds_service_name;
 | 
	
		
			
				|  |  | -    it = json.object_value().find("edsServiceName");
 | 
	
		
			
				|  |  | -    if (it != json.object_value().end()) {
 | 
	
		
			
				|  |  | -      if (it->second.type() != Json::Type::STRING) {
 | 
	
		
			
				|  |  | -        error_list.push_back(GRPC_ERROR_CREATE_FROM_STATIC_STRING(
 | 
	
		
			
				|  |  | -            "field:edsServiceName error:type should be string"));
 | 
	
		
			
				|  |  | -      } else {
 | 
	
		
			
				|  |  | -        eds_service_name = it->second.string_value();
 | 
	
		
			
				|  |  | -      }
 | 
	
		
			
				|  |  | -    }
 | 
	
		
			
				|  |  | -    // Locality.
 | 
	
		
			
				|  |  | -    RefCountedPtr<XdsLocalityName> locality_name;
 | 
	
		
			
				|  |  | -    it = json.object_value().find("locality");
 | 
	
		
			
				|  |  | -    if (it == json.object_value().end()) {
 | 
	
		
			
				|  |  | -      error_list.push_back(GRPC_ERROR_CREATE_FROM_STATIC_STRING(
 | 
	
		
			
				|  |  | -          "field:locality error:required field missing"));
 | 
	
		
			
				|  |  | -    } else {
 | 
	
		
			
				|  |  | -      std::vector<grpc_error*> child_errors =
 | 
	
		
			
				|  |  | -          ParseLocality(it->second, &locality_name);
 | 
	
		
			
				|  |  | -      if (!child_errors.empty()) {
 | 
	
		
			
				|  |  | -        error_list.push_back(
 | 
	
		
			
				|  |  | -            GRPC_ERROR_CREATE_FROM_VECTOR("field:locality", &child_errors));
 | 
	
		
			
				|  |  | -      }
 | 
	
		
			
				|  |  | -    }
 | 
	
		
			
				|  |  | -    // LRS load reporting server name.
 | 
	
		
			
				|  |  | -    std::string lrs_load_reporting_server_name;
 | 
	
		
			
				|  |  | -    it = json.object_value().find("lrsLoadReportingServerName");
 | 
	
		
			
				|  |  | -    if (it == json.object_value().end()) {
 | 
	
		
			
				|  |  | -      error_list.push_back(GRPC_ERROR_CREATE_FROM_STATIC_STRING(
 | 
	
		
			
				|  |  | -          "field:lrsLoadReportingServerName error:required field missing"));
 | 
	
		
			
				|  |  | -    } else if (it->second.type() != Json::Type::STRING) {
 | 
	
		
			
				|  |  | -      error_list.push_back(GRPC_ERROR_CREATE_FROM_STATIC_STRING(
 | 
	
		
			
				|  |  | -          "field:lrsLoadReportingServerName error:type should be string"));
 | 
	
		
			
				|  |  | -    } else {
 | 
	
		
			
				|  |  | -      lrs_load_reporting_server_name = it->second.string_value();
 | 
	
		
			
				|  |  | -    }
 | 
	
		
			
				|  |  | -    if (!error_list.empty()) {
 | 
	
		
			
				|  |  | -      *error = GRPC_ERROR_CREATE_FROM_VECTOR(
 | 
	
		
			
				|  |  | -          "lrs_experimental LB policy config", &error_list);
 | 
	
		
			
				|  |  | -      return nullptr;
 | 
	
		
			
				|  |  | -    }
 | 
	
		
			
				|  |  | -    return MakeRefCounted<LrsLbConfig>(
 | 
	
		
			
				|  |  | -        std::move(child_policy), std::move(cluster_name),
 | 
	
		
			
				|  |  | -        std::move(eds_service_name), std::move(lrs_load_reporting_server_name),
 | 
	
		
			
				|  |  | -        std::move(locality_name));
 | 
	
		
			
				|  |  | -  }
 | 
	
		
			
				|  |  | -
 | 
	
		
			
				|  |  | - private:
 | 
	
		
			
				|  |  | -  static std::vector<grpc_error*> ParseLocality(
 | 
	
		
			
				|  |  | -      const Json& json, RefCountedPtr<XdsLocalityName>* name) {
 | 
	
		
			
				|  |  | -    std::vector<grpc_error*> error_list;
 | 
	
		
			
				|  |  | -    if (json.type() != Json::Type::OBJECT) {
 | 
	
		
			
				|  |  | -      error_list.push_back(GRPC_ERROR_CREATE_FROM_STATIC_STRING(
 | 
	
		
			
				|  |  | -          "locality field is not an object"));
 | 
	
		
			
				|  |  | -      return error_list;
 | 
	
		
			
				|  |  | -    }
 | 
	
		
			
				|  |  | -    std::string region;
 | 
	
		
			
				|  |  | -    auto it = json.object_value().find("region");
 | 
	
		
			
				|  |  | -    if (it != json.object_value().end()) {
 | 
	
		
			
				|  |  | -      if (it->second.type() != Json::Type::STRING) {
 | 
	
		
			
				|  |  | -        error_list.push_back(GRPC_ERROR_CREATE_FROM_STATIC_STRING(
 | 
	
		
			
				|  |  | -            "\"region\" field is not a string"));
 | 
	
		
			
				|  |  | -      } else {
 | 
	
		
			
				|  |  | -        region = it->second.string_value();
 | 
	
		
			
				|  |  | -      }
 | 
	
		
			
				|  |  | -    }
 | 
	
		
			
				|  |  | -    std::string zone;
 | 
	
		
			
				|  |  | -    it = json.object_value().find("zone");
 | 
	
		
			
				|  |  | -    if (it != json.object_value().end()) {
 | 
	
		
			
				|  |  | -      if (it->second.type() != Json::Type::STRING) {
 | 
	
		
			
				|  |  | -        error_list.push_back(GRPC_ERROR_CREATE_FROM_STATIC_STRING(
 | 
	
		
			
				|  |  | -            "\"zone\" field is not a string"));
 | 
	
		
			
				|  |  | -      } else {
 | 
	
		
			
				|  |  | -        zone = it->second.string_value();
 | 
	
		
			
				|  |  | -      }
 | 
	
		
			
				|  |  | -    }
 | 
	
		
			
				|  |  | -    std::string subzone;
 | 
	
		
			
				|  |  | -    it = json.object_value().find("subzone");
 | 
	
		
			
				|  |  | -    if (it != json.object_value().end()) {
 | 
	
		
			
				|  |  | -      if (it->second.type() != Json::Type::STRING) {
 | 
	
		
			
				|  |  | -        error_list.push_back(GRPC_ERROR_CREATE_FROM_STATIC_STRING(
 | 
	
		
			
				|  |  | -            "\"subzone\" field is not a string"));
 | 
	
		
			
				|  |  | -      } else {
 | 
	
		
			
				|  |  | -        subzone = it->second.string_value();
 | 
	
		
			
				|  |  | -      }
 | 
	
		
			
				|  |  | -    }
 | 
	
		
			
				|  |  | -    if (region.empty() && zone.empty() && subzone.empty()) {
 | 
	
		
			
				|  |  | -      error_list.push_back(GRPC_ERROR_CREATE_FROM_STATIC_STRING(
 | 
	
		
			
				|  |  | -          "at least one of region, zone, or subzone must be set"));
 | 
	
		
			
				|  |  | -    }
 | 
	
		
			
				|  |  | -    if (error_list.empty()) {
 | 
	
		
			
				|  |  | -      *name = MakeRefCounted<XdsLocalityName>(region, zone, subzone);
 | 
	
		
			
				|  |  | -    }
 | 
	
		
			
				|  |  | -    return error_list;
 | 
	
		
			
				|  |  | -  }
 | 
	
		
			
				|  |  | -};
 | 
	
		
			
				|  |  | -
 | 
	
		
			
				|  |  | -}  // namespace
 | 
	
		
			
				|  |  | -
 | 
	
		
			
				|  |  | -}  // namespace grpc_core
 | 
	
		
			
				|  |  | -
 | 
	
		
			
				|  |  | -//
 | 
	
		
			
				|  |  | -// Plugin registration
 | 
	
		
			
				|  |  | -//
 | 
	
		
			
				|  |  | -
 | 
	
		
			
				|  |  | -void grpc_lb_policy_lrs_init() {
 | 
	
		
			
				|  |  | -  grpc_core::LoadBalancingPolicyRegistry::Builder::
 | 
	
		
			
				|  |  | -      RegisterLoadBalancingPolicyFactory(
 | 
	
		
			
				|  |  | -          absl::make_unique<grpc_core::LrsLbFactory>());
 | 
	
		
			
				|  |  | -}
 | 
	
		
			
				|  |  | -
 | 
	
		
			
				|  |  | -void grpc_lb_policy_lrs_shutdown() {}
 |