|
|
|
@ -91,7 +91,7 @@ class EdsLbConfig : public LoadBalancingPolicy::Config { |
|
|
|
|
// EDS LB policy.
|
|
|
|
|
class EdsLb : public LoadBalancingPolicy { |
|
|
|
|
public: |
|
|
|
|
explicit EdsLb(Args args); |
|
|
|
|
EdsLb(RefCountedPtr<XdsClient> xds_client, Args args); |
|
|
|
|
|
|
|
|
|
const char* name() const override { return kEds; } |
|
|
|
|
|
|
|
|
@ -198,7 +198,7 @@ class EdsLb : public LoadBalancingPolicy { |
|
|
|
|
|
|
|
|
|
// Caller must ensure that config_ is set before calling.
|
|
|
|
|
const absl::string_view GetEdsResourceName() const { |
|
|
|
|
if (xds_client_from_channel_ == nullptr) return server_name_; |
|
|
|
|
if (!is_xds_uri_) return server_name_; |
|
|
|
|
if (!config_->eds_service_name().empty()) { |
|
|
|
|
return config_->eds_service_name(); |
|
|
|
|
} |
|
|
|
@ -209,17 +209,13 @@ class EdsLb : public LoadBalancingPolicy { |
|
|
|
|
// for LRS load reporting.
|
|
|
|
|
// Caller must ensure that config_ is set before calling.
|
|
|
|
|
std::pair<absl::string_view, absl::string_view> GetLrsClusterKey() const { |
|
|
|
|
if (xds_client_from_channel_ == nullptr) return {server_name_, nullptr}; |
|
|
|
|
if (!is_xds_uri_) return {server_name_, nullptr}; |
|
|
|
|
return {config_->cluster_name(), config_->eds_service_name()}; |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
XdsClient* xds_client() const { |
|
|
|
|
return xds_client_from_channel_ != nullptr ? xds_client_from_channel_.get() |
|
|
|
|
: xds_client_.get(); |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
// Server name from target URI.
|
|
|
|
|
std::string server_name_; |
|
|
|
|
bool is_xds_uri_; |
|
|
|
|
|
|
|
|
|
// Current channel args and config from the resolver.
|
|
|
|
|
const grpc_channel_args* args_ = nullptr; |
|
|
|
@ -229,11 +225,7 @@ class EdsLb : public LoadBalancingPolicy { |
|
|
|
|
bool shutting_down_ = false; |
|
|
|
|
|
|
|
|
|
// The xds client and endpoint watcher.
|
|
|
|
|
// If we get the XdsClient from the channel, we store it in
|
|
|
|
|
// xds_client_from_channel_; if we create it ourselves, we store it in
|
|
|
|
|
// xds_client_.
|
|
|
|
|
RefCountedPtr<XdsClient> xds_client_from_channel_; |
|
|
|
|
OrphanablePtr<XdsClient> xds_client_; |
|
|
|
|
RefCountedPtr<XdsClient> xds_client_; |
|
|
|
|
// A pointer to the endpoint watcher, to be used when cancelling the watch.
|
|
|
|
|
// Note that this is not owned, so this pointer must never be derefernced.
|
|
|
|
|
EndpointWatcher* endpoint_watcher_ = nullptr; |
|
|
|
@ -380,25 +372,38 @@ void EdsLb::EndpointWatcher::Notifier::RunInWorkSerializer(grpc_error* error) { |
|
|
|
|
// EdsLb public methods
|
|
|
|
|
//
|
|
|
|
|
|
|
|
|
|
EdsLb::EdsLb(Args args) |
|
|
|
|
: LoadBalancingPolicy(std::move(args)), |
|
|
|
|
xds_client_from_channel_(XdsClient::GetFromChannelArgs(*args.args)) { |
|
|
|
|
EdsLb::EdsLb(RefCountedPtr<XdsClient> xds_client, Args args) |
|
|
|
|
: LoadBalancingPolicy(std::move(args)), xds_client_(std::move(xds_client)) { |
|
|
|
|
if (GRPC_TRACE_FLAG_ENABLED(grpc_lb_eds_trace)) { |
|
|
|
|
gpr_log(GPR_INFO, "[edslb %p] created -- xds client from channel: %p", this, |
|
|
|
|
xds_client_from_channel_.get()); |
|
|
|
|
gpr_log(GPR_INFO, "[edslb %p] created -- using xds client %p", this, |
|
|
|
|
xds_client_.get()); |
|
|
|
|
} |
|
|
|
|
// Record server name.
|
|
|
|
|
const grpc_arg* arg = grpc_channel_args_find(args.args, GRPC_ARG_SERVER_URI); |
|
|
|
|
const char* server_uri = grpc_channel_arg_get_string(arg); |
|
|
|
|
const char* server_uri = |
|
|
|
|
grpc_channel_args_find_string(args.args, GRPC_ARG_SERVER_URI); |
|
|
|
|
GPR_ASSERT(server_uri != nullptr); |
|
|
|
|
grpc_uri* uri = grpc_uri_parse(server_uri, true); |
|
|
|
|
GPR_ASSERT(uri->path[0] != '\0'); |
|
|
|
|
server_name_ = uri->path[0] == '/' ? uri->path + 1 : uri->path; |
|
|
|
|
is_xds_uri_ = strcmp(uri->scheme, "xds") == 0; |
|
|
|
|
if (GRPC_TRACE_FLAG_ENABLED(grpc_lb_eds_trace)) { |
|
|
|
|
gpr_log(GPR_INFO, "[edslb %p] server name from channel: %s", this, |
|
|
|
|
server_name_.c_str()); |
|
|
|
|
gpr_log(GPR_INFO, "[edslb %p] server name from channel (is_xds_uri=%d): %s", |
|
|
|
|
this, is_xds_uri_, server_name_.c_str()); |
|
|
|
|
} |
|
|
|
|
grpc_uri_destroy(uri); |
|
|
|
|
// EDS-only flow.
|
|
|
|
|
if (!is_xds_uri_) { |
|
|
|
|
// Setup channelz linkage.
|
|
|
|
|
channelz::ChannelNode* parent_channelz_node = |
|
|
|
|
grpc_channel_args_find_pointer<channelz::ChannelNode>( |
|
|
|
|
args.args, GRPC_ARG_CHANNELZ_CHANNEL_NODE); |
|
|
|
|
if (parent_channelz_node != nullptr) { |
|
|
|
|
xds_client_->AddChannelzLinkage(parent_channelz_node); |
|
|
|
|
} |
|
|
|
|
// Couple polling.
|
|
|
|
|
grpc_pollset_set_add_pollset_set(xds_client_->interested_parties(), |
|
|
|
|
interested_parties()); |
|
|
|
|
} |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
EdsLb::~EdsLb() { |
|
|
|
@ -417,32 +422,29 @@ void EdsLb::ShutdownLocked() { |
|
|
|
|
child_picker_.reset(); |
|
|
|
|
MaybeDestroyChildPolicyLocked(); |
|
|
|
|
drop_stats_.reset(); |
|
|
|
|
// Cancel the endpoint watch here instead of in our dtor if we are using the
|
|
|
|
|
// xds resolver, because the watcher holds a ref to us and we might not be
|
|
|
|
|
// destroying the XdsClient, leading to a situation where this LB policy is
|
|
|
|
|
// never destroyed.
|
|
|
|
|
if (xds_client_from_channel_ != nullptr) { |
|
|
|
|
if (config_ != nullptr) { |
|
|
|
|
if (GRPC_TRACE_FLAG_ENABLED(grpc_lb_eds_trace)) { |
|
|
|
|
gpr_log(GPR_INFO, "[edslb %p] cancelling xds watch for %s", this, |
|
|
|
|
std::string(GetEdsResourceName()).c_str()); |
|
|
|
|
} |
|
|
|
|
xds_client()->CancelEndpointDataWatch(GetEdsResourceName(), |
|
|
|
|
endpoint_watcher_); |
|
|
|
|
// Cancel watcher.
|
|
|
|
|
if (endpoint_watcher_ != nullptr) { |
|
|
|
|
if (GRPC_TRACE_FLAG_ENABLED(grpc_lb_eds_trace)) { |
|
|
|
|
gpr_log(GPR_INFO, "[edslb %p] cancelling xds watch for %s", this, |
|
|
|
|
std::string(GetEdsResourceName()).c_str()); |
|
|
|
|
} |
|
|
|
|
xds_client_from_channel_.reset(DEBUG_LOCATION, "EdsLb"); |
|
|
|
|
xds_client_->CancelEndpointDataWatch(GetEdsResourceName(), |
|
|
|
|
endpoint_watcher_); |
|
|
|
|
} |
|
|
|
|
if (xds_client_ != nullptr) { |
|
|
|
|
if (!is_xds_uri_) { |
|
|
|
|
// Remove channelz linkage.
|
|
|
|
|
channelz::ChannelNode* parent_channelz_node = |
|
|
|
|
grpc_channel_args_find_pointer<channelz::ChannelNode>( |
|
|
|
|
args_, GRPC_ARG_CHANNELZ_CHANNEL_NODE); |
|
|
|
|
if (parent_channelz_node != nullptr) { |
|
|
|
|
xds_client_->RemoveChannelzLinkage(parent_channelz_node); |
|
|
|
|
} |
|
|
|
|
// Decouple polling.
|
|
|
|
|
grpc_pollset_set_del_pollset_set(xds_client_->interested_parties(), |
|
|
|
|
interested_parties()); |
|
|
|
|
xds_client_.reset(); |
|
|
|
|
} |
|
|
|
|
xds_client_.reset(DEBUG_LOCATION, "EdsLb"); |
|
|
|
|
// Destroy channel args.
|
|
|
|
|
grpc_channel_args_destroy(args_); |
|
|
|
|
args_ = nullptr; |
|
|
|
|
} |
|
|
|
@ -467,35 +469,13 @@ void EdsLb::UpdateLocked(UpdateArgs args) { |
|
|
|
|
grpc_channel_args_destroy(args_); |
|
|
|
|
args_ = args.args; |
|
|
|
|
args.args = nullptr; |
|
|
|
|
if (is_initial_update) { |
|
|
|
|
// Initialize XdsClient.
|
|
|
|
|
if (xds_client_from_channel_ == nullptr) { |
|
|
|
|
grpc_error* error = GRPC_ERROR_NONE; |
|
|
|
|
xds_client_ = MakeOrphanable<XdsClient>(&error); |
|
|
|
|
// TODO(roth): If we decide that we care about EDS-only mode, add
|
|
|
|
|
// proper error handling here.
|
|
|
|
|
GPR_ASSERT(error == GRPC_ERROR_NONE); |
|
|
|
|
channelz::ChannelNode* parent_channelz_node = |
|
|
|
|
grpc_channel_args_find_pointer<channelz::ChannelNode>( |
|
|
|
|
args_, GRPC_ARG_CHANNELZ_CHANNEL_NODE); |
|
|
|
|
if (parent_channelz_node != nullptr) { |
|
|
|
|
xds_client_->AddChannelzLinkage(parent_channelz_node); |
|
|
|
|
} |
|
|
|
|
grpc_pollset_set_add_pollset_set(xds_client_->interested_parties(), |
|
|
|
|
interested_parties()); |
|
|
|
|
if (GRPC_TRACE_FLAG_ENABLED(grpc_lb_eds_trace)) { |
|
|
|
|
gpr_log(GPR_INFO, "[edslb %p] Created xds client %p", this, |
|
|
|
|
xds_client_.get()); |
|
|
|
|
} |
|
|
|
|
} |
|
|
|
|
} |
|
|
|
|
// Update drop stats for load reporting if needed.
|
|
|
|
|
if (is_initial_update || config_->lrs_load_reporting_server_name() != |
|
|
|
|
old_config->lrs_load_reporting_server_name()) { |
|
|
|
|
drop_stats_.reset(); |
|
|
|
|
if (config_->lrs_load_reporting_server_name().has_value()) { |
|
|
|
|
const auto key = GetLrsClusterKey(); |
|
|
|
|
drop_stats_ = xds_client()->AddClusterDropStats( |
|
|
|
|
drop_stats_ = xds_client_->AddClusterDropStats( |
|
|
|
|
config_->lrs_load_reporting_server_name().value(), |
|
|
|
|
key.first /*cluster_name*/, key.second /*eds_service_name*/); |
|
|
|
|
} |
|
|
|
@ -514,15 +494,14 @@ void EdsLb::UpdateLocked(UpdateArgs args) { |
|
|
|
|
auto watcher = absl::make_unique<EndpointWatcher>( |
|
|
|
|
Ref(DEBUG_LOCATION, "EndpointWatcher")); |
|
|
|
|
endpoint_watcher_ = watcher.get(); |
|
|
|
|
xds_client()->WatchEndpointData(GetEdsResourceName(), std::move(watcher)); |
|
|
|
|
xds_client_->WatchEndpointData(GetEdsResourceName(), std::move(watcher)); |
|
|
|
|
} |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
void EdsLb::ResetBackoffLocked() { |
|
|
|
|
// When the XdsClient is instantiated in the resolver instead of in this
|
|
|
|
|
// LB policy, this is done via the resolver, so we don't need to do it
|
|
|
|
|
// for xds_client_from_channel_ here.
|
|
|
|
|
if (xds_client_ != nullptr) xds_client_->ResetBackoff(); |
|
|
|
|
// LB policy, this is done via the resolver, so we don't need to do it here.
|
|
|
|
|
if (!is_xds_uri_ && xds_client_ != nullptr) xds_client_->ResetBackoff(); |
|
|
|
|
if (child_policy_ != nullptr) { |
|
|
|
|
child_policy_->ResetBackoffLocked(); |
|
|
|
|
} |
|
|
|
@ -789,9 +768,11 @@ void EdsLb::UpdateChildPolicyLocked() { |
|
|
|
|
|
|
|
|
|
grpc_channel_args* EdsLb::CreateChildPolicyArgsLocked( |
|
|
|
|
const grpc_channel_args* args) { |
|
|
|
|
absl::InlinedVector<grpc_arg, 3> args_to_add = { |
|
|
|
|
grpc_arg args_to_add[] = { |
|
|
|
|
// A channel arg indicating if the target is a backend inferred from an
|
|
|
|
|
// xds load balancer.
|
|
|
|
|
// TODO(roth): This isn't needed with the new fallback design.
|
|
|
|
|
// Remove as part of implementing the new fallback functionality.
|
|
|
|
|
grpc_channel_arg_integer_create( |
|
|
|
|
const_cast<char*>(GRPC_ARG_ADDRESS_IS_BACKEND_FROM_XDS_LOAD_BALANCER), |
|
|
|
|
1), |
|
|
|
@ -800,18 +781,8 @@ grpc_channel_args* EdsLb::CreateChildPolicyArgsLocked( |
|
|
|
|
grpc_channel_arg_integer_create( |
|
|
|
|
const_cast<char*>(GRPC_ARG_INHIBIT_HEALTH_CHECKING), 1), |
|
|
|
|
}; |
|
|
|
|
absl::InlinedVector<const char*, 1> args_to_remove; |
|
|
|
|
if (xds_client_from_channel_ == nullptr) { |
|
|
|
|
args_to_add.emplace_back(xds_client_->MakeChannelArg()); |
|
|
|
|
} else if (!config_->lrs_load_reporting_server_name().has_value()) { |
|
|
|
|
// Remove XdsClient from channel args, so that its presence doesn't
|
|
|
|
|
// prevent us from sharing subchannels between channels.
|
|
|
|
|
// If load reporting is enabled, this happens in the LRS policy instead.
|
|
|
|
|
args_to_remove.push_back(GRPC_ARG_XDS_CLIENT); |
|
|
|
|
} |
|
|
|
|
return grpc_channel_args_copy_and_add_and_remove( |
|
|
|
|
args, args_to_remove.data(), args_to_remove.size(), args_to_add.data(), |
|
|
|
|
args_to_add.size()); |
|
|
|
|
return grpc_channel_args_copy_and_add(args, args_to_add, |
|
|
|
|
GPR_ARRAY_SIZE(args_to_add)); |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
OrphanablePtr<LoadBalancingPolicy> EdsLb::CreateChildPolicyLocked( |
|
|
|
@ -863,7 +834,17 @@ class EdsLbFactory : public LoadBalancingPolicyFactory { |
|
|
|
|
public: |
|
|
|
|
OrphanablePtr<LoadBalancingPolicy> CreateLoadBalancingPolicy( |
|
|
|
|
LoadBalancingPolicy::Args args) const override { |
|
|
|
|
return MakeOrphanable<EdsChildHandler>(std::move(args), &grpc_lb_eds_trace); |
|
|
|
|
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 eds LB policy: %s", |
|
|
|
|
grpc_error_string(error)); |
|
|
|
|
GRPC_ERROR_UNREF(error); |
|
|
|
|
return nullptr; |
|
|
|
|
} |
|
|
|
|
return MakeOrphanable<EdsChildHandler>(std::move(xds_client), |
|
|
|
|
std::move(args)); |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
const char* name() const override { return kEds; } |
|
|
|
@ -974,8 +955,9 @@ class EdsLbFactory : public LoadBalancingPolicyFactory { |
|
|
|
|
private: |
|
|
|
|
class EdsChildHandler : public ChildPolicyHandler { |
|
|
|
|
public: |
|
|
|
|
EdsChildHandler(Args args, TraceFlag* tracer) |
|
|
|
|
: ChildPolicyHandler(std::move(args), tracer) {} |
|
|
|
|
EdsChildHandler(RefCountedPtr<XdsClient> xds_client, Args args) |
|
|
|
|
: ChildPolicyHandler(std::move(args), &grpc_lb_eds_trace), |
|
|
|
|
xds_client_(std::move(xds_client)) {} |
|
|
|
|
|
|
|
|
|
bool ConfigChangeRequiresNewPolicyInstance( |
|
|
|
|
LoadBalancingPolicy::Config* old_config, |
|
|
|
@ -991,8 +973,11 @@ class EdsLbFactory : public LoadBalancingPolicyFactory { |
|
|
|
|
|
|
|
|
|
OrphanablePtr<LoadBalancingPolicy> CreateLoadBalancingPolicy( |
|
|
|
|
const char* name, LoadBalancingPolicy::Args args) const override { |
|
|
|
|
return MakeOrphanable<EdsLb>(std::move(args)); |
|
|
|
|
return MakeOrphanable<EdsLb>(xds_client_, std::move(args)); |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
private: |
|
|
|
|
RefCountedPtr<XdsClient> xds_client_; |
|
|
|
|
}; |
|
|
|
|
}; |
|
|
|
|
|
|
|
|
|