|
|
|
@ -16,20 +16,30 @@ |
|
|
|
|
|
|
|
|
|
#include <grpc/support/port_platform.h> |
|
|
|
|
|
|
|
|
|
#include <functional> |
|
|
|
|
#include <map> |
|
|
|
|
#include <memory> |
|
|
|
|
#include <string> |
|
|
|
|
#include <unordered_set> |
|
|
|
|
#include <utility> |
|
|
|
|
#include <vector> |
|
|
|
|
|
|
|
|
|
#include "absl/base/thread_annotations.h" |
|
|
|
|
#include "absl/status/status.h" |
|
|
|
|
#include "absl/status/statusor.h" |
|
|
|
|
#include "absl/strings/string_view.h" |
|
|
|
|
#include "absl/synchronization/mutex.h" |
|
|
|
|
#include "absl/types/optional.h" |
|
|
|
|
#include "absl/types/variant.h" |
|
|
|
|
|
|
|
|
|
#include <grpc/event_engine/event_engine.h> |
|
|
|
|
#include <grpc/impl/connectivity_state.h> |
|
|
|
|
#include <grpc/support/log.h> |
|
|
|
|
|
|
|
|
|
#include "src/core/ext/filters/client_channel/lb_call_state_internal.h" |
|
|
|
|
#include "src/core/ext/filters/client_channel/lb_policy/child_policy_handler.h" |
|
|
|
|
#include "src/core/ext/filters/stateful_session/stateful_session_filter.h" |
|
|
|
|
#include "src/core/lib/address_utils/sockaddr_utils.h" |
|
|
|
|
#include "src/core/lib/channel/channel_args.h" |
|
|
|
|
#include "src/core/lib/config/core_configuration.h" |
|
|
|
|
#include "src/core/lib/debug/trace.h" |
|
|
|
@ -101,12 +111,13 @@ class XdsOverrideHostLb : public LoadBalancingPolicy { |
|
|
|
|
// present.
|
|
|
|
|
class Picker : public SubchannelPicker { |
|
|
|
|
public: |
|
|
|
|
Picker(XdsOverrideHostLb* xds_override_host_lb, |
|
|
|
|
Picker(RefCountedPtr<XdsOverrideHostLb> xds_override_host_lb, |
|
|
|
|
RefCountedPtr<SubchannelPicker> picker); |
|
|
|
|
|
|
|
|
|
PickResult Pick(PickArgs args) override; |
|
|
|
|
|
|
|
|
|
private: |
|
|
|
|
RefCountedPtr<XdsOverrideHostLb> policy_; |
|
|
|
|
RefCountedPtr<SubchannelPicker> picker_; |
|
|
|
|
}; |
|
|
|
|
|
|
|
|
@ -133,6 +144,42 @@ class XdsOverrideHostLb : public LoadBalancingPolicy { |
|
|
|
|
RefCountedPtr<XdsOverrideHostLb> xds_override_host_policy_; |
|
|
|
|
}; |
|
|
|
|
|
|
|
|
|
class SubchannelWrapper : public DelegatingSubchannel { |
|
|
|
|
public: |
|
|
|
|
SubchannelWrapper(RefCountedPtr<SubchannelInterface> subchannel, |
|
|
|
|
RefCountedPtr<XdsOverrideHostLb> policy, |
|
|
|
|
absl::optional<const std::string> key); |
|
|
|
|
|
|
|
|
|
~SubchannelWrapper() override; |
|
|
|
|
|
|
|
|
|
private: |
|
|
|
|
const absl::optional<const std::string> key_; |
|
|
|
|
RefCountedPtr<XdsOverrideHostLb> policy_; |
|
|
|
|
}; |
|
|
|
|
|
|
|
|
|
class SubchannelEntry { |
|
|
|
|
public: |
|
|
|
|
void SetSubchannel(SubchannelWrapper* subchannel) { |
|
|
|
|
subchannel_ = subchannel; |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
void ResetSubchannel(SubchannelWrapper* expected) { |
|
|
|
|
if (subchannel_ == expected) { |
|
|
|
|
subchannel_ = nullptr; |
|
|
|
|
} |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
RefCountedPtr<SubchannelWrapper> GetSubchannel() { |
|
|
|
|
if (subchannel_ == nullptr) { |
|
|
|
|
return nullptr; |
|
|
|
|
} |
|
|
|
|
return subchannel_->Ref(); |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
private: |
|
|
|
|
SubchannelWrapper* subchannel_ = nullptr; |
|
|
|
|
}; |
|
|
|
|
|
|
|
|
|
~XdsOverrideHostLb() override; |
|
|
|
|
|
|
|
|
|
void ShutdownLocked() override; |
|
|
|
@ -142,6 +189,15 @@ class XdsOverrideHostLb : public LoadBalancingPolicy { |
|
|
|
|
|
|
|
|
|
void MaybeUpdatePickerLocked(); |
|
|
|
|
|
|
|
|
|
RefCountedPtr<SubchannelWrapper> LookupSubchannel(absl::string_view address); |
|
|
|
|
|
|
|
|
|
void UpdateAddressMap(const absl::StatusOr<ServerAddressList>& addresses); |
|
|
|
|
|
|
|
|
|
RefCountedPtr<SubchannelWrapper> AdoptSubchannel( |
|
|
|
|
ServerAddress address, RefCountedPtr<SubchannelInterface> subchannel); |
|
|
|
|
|
|
|
|
|
void ResetSubchannel(absl::string_view key, SubchannelWrapper* subchannel); |
|
|
|
|
|
|
|
|
|
// Current config from the resolver.
|
|
|
|
|
RefCountedPtr<XdsOverrideHostLbConfig> config_; |
|
|
|
|
|
|
|
|
@ -154,29 +210,47 @@ class XdsOverrideHostLb : public LoadBalancingPolicy { |
|
|
|
|
grpc_connectivity_state state_ = GRPC_CHANNEL_IDLE; |
|
|
|
|
absl::Status status_; |
|
|
|
|
RefCountedPtr<SubchannelPicker> picker_; |
|
|
|
|
absl::Mutex subchannel_map_mu_; |
|
|
|
|
std::map<std::string, SubchannelEntry, std::less<>> subchannel_map_ |
|
|
|
|
ABSL_GUARDED_BY(subchannel_map_mu_); |
|
|
|
|
}; |
|
|
|
|
|
|
|
|
|
//
|
|
|
|
|
// XdsOverrideHostLb::Picker
|
|
|
|
|
//
|
|
|
|
|
|
|
|
|
|
XdsOverrideHostLb::Picker::Picker(XdsOverrideHostLb* xds_override_host_lb, |
|
|
|
|
XdsOverrideHostLb::Picker::Picker( |
|
|
|
|
RefCountedPtr<XdsOverrideHostLb> xds_override_host_lb, |
|
|
|
|
RefCountedPtr<SubchannelPicker> picker) |
|
|
|
|
: picker_(std::move(picker)) { |
|
|
|
|
: policy_(std::move(xds_override_host_lb)), picker_(std::move(picker)) { |
|
|
|
|
if (GRPC_TRACE_FLAG_ENABLED(grpc_lb_xds_override_host_trace)) { |
|
|
|
|
gpr_log(GPR_INFO, "[xds_override_host_lb %p] constructed new picker %p", |
|
|
|
|
xds_override_host_lb, this); |
|
|
|
|
policy_.get(), this); |
|
|
|
|
} |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
LoadBalancingPolicy::PickResult XdsOverrideHostLb::Picker::Pick( |
|
|
|
|
LoadBalancingPolicy::PickArgs args) { |
|
|
|
|
auto* call_state = static_cast<LbCallStateInternal*>(args.call_state); |
|
|
|
|
auto override_host = call_state->GetCallAttribute(XdsHostOverrideTypeName()); |
|
|
|
|
if (!override_host.empty()) { |
|
|
|
|
auto subchannel = policy_->LookupSubchannel(override_host); |
|
|
|
|
if (subchannel != nullptr) { |
|
|
|
|
return PickResult::Complete(subchannel->wrapped_subchannel()); |
|
|
|
|
} |
|
|
|
|
} |
|
|
|
|
if (picker_ == nullptr) { // Should never happen.
|
|
|
|
|
return PickResult::Fail(absl::InternalError( |
|
|
|
|
"xds_override_host picker not given any child picker")); |
|
|
|
|
} |
|
|
|
|
// Delegate to child picker
|
|
|
|
|
return picker_->Pick(args); |
|
|
|
|
auto result = picker_->Pick(args); |
|
|
|
|
auto complete_pick = absl::get_if<PickResult::Complete>(&result.result); |
|
|
|
|
if (complete_pick != nullptr) { |
|
|
|
|
complete_pick->subchannel = |
|
|
|
|
static_cast<SubchannelWrapper*>(complete_pick->subchannel.get()) |
|
|
|
|
->wrapped_subchannel(); |
|
|
|
|
} |
|
|
|
|
return result; |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
//
|
|
|
|
@ -237,6 +311,7 @@ absl::Status XdsOverrideHostLb::UpdateLocked(UpdateArgs args) { |
|
|
|
|
if (child_policy_ == nullptr) { |
|
|
|
|
child_policy_ = CreateChildPolicyLocked(args.args); |
|
|
|
|
} |
|
|
|
|
UpdateAddressMap(args.addresses); |
|
|
|
|
// Update child policy.
|
|
|
|
|
UpdateArgs update_args; |
|
|
|
|
update_args.addresses = std::move(args.addresses); |
|
|
|
@ -253,7 +328,7 @@ absl::Status XdsOverrideHostLb::UpdateLocked(UpdateArgs args) { |
|
|
|
|
|
|
|
|
|
void XdsOverrideHostLb::MaybeUpdatePickerLocked() { |
|
|
|
|
if (picker_ != nullptr) { |
|
|
|
|
auto xds_override_host_picker = MakeRefCounted<Picker>(this, picker_); |
|
|
|
|
auto xds_override_host_picker = MakeRefCounted<Picker>(Ref(), picker_); |
|
|
|
|
if (GRPC_TRACE_FLAG_ENABLED(grpc_lb_xds_override_host_trace)) { |
|
|
|
|
gpr_log(GPR_INFO, |
|
|
|
|
"[xds_override_host_lb %p] updating connectivity: state=%s " |
|
|
|
@ -289,27 +364,87 @@ OrphanablePtr<LoadBalancingPolicy> XdsOverrideHostLb::CreateChildPolicyLocked( |
|
|
|
|
return lb_policy; |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
RefCountedPtr<XdsOverrideHostLb::SubchannelWrapper> |
|
|
|
|
XdsOverrideHostLb::LookupSubchannel(absl::string_view address) { |
|
|
|
|
absl::MutexLock lock(&subchannel_map_mu_); |
|
|
|
|
auto it = subchannel_map_.find(address); |
|
|
|
|
if (it != subchannel_map_.end()) { |
|
|
|
|
return it->second.GetSubchannel(); |
|
|
|
|
} |
|
|
|
|
return nullptr; |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
void XdsOverrideHostLb::UpdateAddressMap( |
|
|
|
|
const absl::StatusOr<ServerAddressList>& addresses) { |
|
|
|
|
std::unordered_set<std::string> keys(addresses->size()); |
|
|
|
|
if (addresses.ok()) { |
|
|
|
|
for (const auto& address : *addresses) { |
|
|
|
|
auto key = grpc_sockaddr_to_string(&address.address(), false); |
|
|
|
|
if (key.ok()) { |
|
|
|
|
keys.insert(std::move(*key)); |
|
|
|
|
} |
|
|
|
|
} |
|
|
|
|
} |
|
|
|
|
absl::MutexLock lock(&subchannel_map_mu_); |
|
|
|
|
for (auto it = subchannel_map_.begin(); it != subchannel_map_.end();) { |
|
|
|
|
if (keys.find(it->first) == keys.end()) { |
|
|
|
|
it = subchannel_map_.erase(it); |
|
|
|
|
} else { |
|
|
|
|
++it; |
|
|
|
|
} |
|
|
|
|
} |
|
|
|
|
for (const auto& key : keys) { |
|
|
|
|
if (subchannel_map_.find(key) == subchannel_map_.end()) { |
|
|
|
|
subchannel_map_.emplace(key, SubchannelEntry()); |
|
|
|
|
} |
|
|
|
|
} |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
RefCountedPtr<XdsOverrideHostLb::SubchannelWrapper> |
|
|
|
|
XdsOverrideHostLb::AdoptSubchannel( |
|
|
|
|
ServerAddress address, RefCountedPtr<SubchannelInterface> subchannel) { |
|
|
|
|
auto subchannel_key = grpc_sockaddr_to_string(&address.address(), false); |
|
|
|
|
absl::optional<std::string> key; |
|
|
|
|
if (subchannel_key.ok()) { |
|
|
|
|
key = std::move(*subchannel_key); |
|
|
|
|
} |
|
|
|
|
auto wrapper = |
|
|
|
|
MakeRefCounted<SubchannelWrapper>(std::move(subchannel), Ref(), key); |
|
|
|
|
if (key.has_value()) { |
|
|
|
|
absl::MutexLock lock(&subchannel_map_mu_); |
|
|
|
|
auto it = subchannel_map_.find(*key); |
|
|
|
|
if (it != subchannel_map_.end()) { |
|
|
|
|
it->second.SetSubchannel(wrapper.get()); |
|
|
|
|
} |
|
|
|
|
} |
|
|
|
|
return wrapper; |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
void XdsOverrideHostLb::ResetSubchannel(absl::string_view key, |
|
|
|
|
SubchannelWrapper* subchannel) { |
|
|
|
|
absl::MutexLock lock(&subchannel_map_mu_); |
|
|
|
|
auto it = subchannel_map_.find(key); |
|
|
|
|
if (it != subchannel_map_.end()) { |
|
|
|
|
it->second.ResetSubchannel(subchannel); |
|
|
|
|
} |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
//
|
|
|
|
|
// XdsOverrideHostLb::Helper
|
|
|
|
|
//
|
|
|
|
|
|
|
|
|
|
RefCountedPtr<SubchannelInterface> XdsOverrideHostLb::Helper::CreateSubchannel( |
|
|
|
|
ServerAddress address, const ChannelArgs& args) { |
|
|
|
|
return xds_override_host_policy_->channel_control_helper()->CreateSubchannel( |
|
|
|
|
auto subchannel = |
|
|
|
|
xds_override_host_policy_->channel_control_helper()->CreateSubchannel( |
|
|
|
|
address, args); |
|
|
|
|
return xds_override_host_policy_->AdoptSubchannel(address, subchannel); |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
void XdsOverrideHostLb::Helper::UpdateState( |
|
|
|
|
grpc_connectivity_state state, const absl::Status& status, |
|
|
|
|
RefCountedPtr<SubchannelPicker> picker) { |
|
|
|
|
if (xds_override_host_policy_->shutting_down_) return; |
|
|
|
|
if (GRPC_TRACE_FLAG_ENABLED(grpc_lb_xds_override_host_trace)) { |
|
|
|
|
gpr_log(GPR_INFO, |
|
|
|
|
"[xds_override_host_lb %p] child connectivity state update: " |
|
|
|
|
"state=%s (%s) picker=%p", |
|
|
|
|
xds_override_host_policy_.get(), ConnectivityStateName(state), |
|
|
|
|
status.ToString().c_str(), picker.get()); |
|
|
|
|
} |
|
|
|
|
// Save the state and picker.
|
|
|
|
|
xds_override_host_policy_->state_ = state; |
|
|
|
|
xds_override_host_policy_->status_ = status; |
|
|
|
@ -339,6 +474,24 @@ void XdsOverrideHostLb::Helper::AddTraceEvent(TraceSeverity severity, |
|
|
|
|
message); |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
//
|
|
|
|
|
// XdsOverrideHostLb::SubchannelWrapper::SubchannelWrapper
|
|
|
|
|
//
|
|
|
|
|
|
|
|
|
|
XdsOverrideHostLb::SubchannelWrapper::SubchannelWrapper( |
|
|
|
|
RefCountedPtr<SubchannelInterface> subchannel, |
|
|
|
|
RefCountedPtr<XdsOverrideHostLb> policy, |
|
|
|
|
absl::optional<const std::string> key) |
|
|
|
|
: DelegatingSubchannel(std::move(subchannel)), |
|
|
|
|
key_(std::move(key)), |
|
|
|
|
policy_(std::move(policy)) {} |
|
|
|
|
|
|
|
|
|
XdsOverrideHostLb::SubchannelWrapper::~SubchannelWrapper() { |
|
|
|
|
if (key_.has_value()) { |
|
|
|
|
policy_->ResetSubchannel(*key_, this); |
|
|
|
|
} |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
//
|
|
|
|
|
// factory
|
|
|
|
|
//
|
|
|
|
|