|
|
@ -47,7 +47,6 @@ |
|
|
|
|
|
|
|
|
|
|
|
#include <grpc/grpc.h> |
|
|
|
#include <grpc/grpc.h> |
|
|
|
|
|
|
|
|
|
|
|
#include "src/core/lib/gprpp/unique_type_name.h" |
|
|
|
|
|
|
|
#include "src/core/lib/slice/slice.h" |
|
|
|
#include "src/core/lib/slice/slice.h" |
|
|
|
|
|
|
|
|
|
|
|
#define XXH_INLINE_ALL |
|
|
|
#define XXH_INLINE_ALL |
|
|
@ -102,11 +101,6 @@ namespace grpc_core { |
|
|
|
|
|
|
|
|
|
|
|
TraceFlag grpc_xds_resolver_trace(false, "xds_resolver"); |
|
|
|
TraceFlag grpc_xds_resolver_trace(false, "xds_resolver"); |
|
|
|
|
|
|
|
|
|
|
|
UniqueTypeName XdsClusterAttribute::TypeName() { |
|
|
|
|
|
|
|
static UniqueTypeName::Factory kFactory("xds_cluster_name"); |
|
|
|
|
|
|
|
return kFactory.Create(); |
|
|
|
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
namespace { |
|
|
|
namespace { |
|
|
|
|
|
|
|
|
|
|
|
std::string GetDefaultAuthorityInternal(const URI& uri) { |
|
|
|
std::string GetDefaultAuthorityInternal(const URI& uri) { |
|
|
@ -246,15 +240,15 @@ class XdsResolver : public Resolver { |
|
|
|
// the cluster by the ConfigSelector. The ref for each call is held
|
|
|
|
// the cluster by the ConfigSelector. The ref for each call is held
|
|
|
|
// until the call is committed. When the strong refs go away, we hop
|
|
|
|
// until the call is committed. When the strong refs go away, we hop
|
|
|
|
// back into the WorkSerializer to remove the entry from the map.
|
|
|
|
// back into the WorkSerializer to remove the entry from the map.
|
|
|
|
class ClusterState : public DualRefCounted<ClusterState> { |
|
|
|
class ClusterRef : public DualRefCounted<ClusterRef> { |
|
|
|
public: |
|
|
|
public: |
|
|
|
ClusterState(RefCountedPtr<XdsResolver> resolver, |
|
|
|
ClusterRef(RefCountedPtr<XdsResolver> resolver, |
|
|
|
absl::string_view cluster_name) |
|
|
|
absl::string_view cluster_name) |
|
|
|
: resolver_(std::move(resolver)), cluster_name_(cluster_name) {} |
|
|
|
: resolver_(std::move(resolver)), cluster_name_(cluster_name) {} |
|
|
|
|
|
|
|
|
|
|
|
void Orphan() override { |
|
|
|
void Orphan() override { |
|
|
|
auto* resolver = resolver_.get(); |
|
|
|
XdsResolver* resolver_ptr = resolver_.get(); |
|
|
|
resolver->work_serializer_->Run( |
|
|
|
resolver_ptr->work_serializer_->Run( |
|
|
|
[resolver = std::move(resolver_)]() { |
|
|
|
[resolver = std::move(resolver_)]() { |
|
|
|
resolver->MaybeRemoveUnusedClusters(); |
|
|
|
resolver->MaybeRemoveUnusedClusters(); |
|
|
|
}, |
|
|
|
}, |
|
|
@ -268,21 +262,49 @@ class XdsResolver : public Resolver { |
|
|
|
std::string cluster_name_; |
|
|
|
std::string cluster_name_; |
|
|
|
}; |
|
|
|
}; |
|
|
|
|
|
|
|
|
|
|
|
// A map containing cluster refs held by the XdsConfigSelector. A ref to
|
|
|
|
// A routing data including cluster refs and routes table held by the
|
|
|
|
// this map will be taken by each call processed by the XdsConfigSelector,
|
|
|
|
// XdsConfigSelector. A ref to this map will be taken by each call processed
|
|
|
|
// stored in a the call's call attributes, and later unreffed
|
|
|
|
// by the XdsConfigSelector, stored in a the call's call attributes, and later
|
|
|
|
// by the ClusterSelection filter.
|
|
|
|
// unreffed by the ClusterSelection filter.
|
|
|
|
class XdsClusterMap : public RefCounted<XdsClusterMap> { |
|
|
|
class RouteConfigData : public RefCounted<RouteConfigData> { |
|
|
|
public: |
|
|
|
public: |
|
|
|
explicit XdsClusterMap( |
|
|
|
struct RouteEntry { |
|
|
|
std::map<absl::string_view, RefCountedPtr<ClusterState>> clusters) |
|
|
|
struct ClusterWeightState { |
|
|
|
: clusters_(std::move(clusters)) {} |
|
|
|
uint32_t range_end; |
|
|
|
|
|
|
|
absl::string_view cluster; |
|
|
|
|
|
|
|
RefCountedPtr<ServiceConfig> method_config; |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
bool operator==(const ClusterWeightState& other) const { |
|
|
|
|
|
|
|
return range_end == other.range_end && cluster == other.cluster && |
|
|
|
|
|
|
|
MethodConfigsEqual(method_config.get(), |
|
|
|
|
|
|
|
other.method_config.get()); |
|
|
|
|
|
|
|
} |
|
|
|
|
|
|
|
}; |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
XdsRouteConfigResource::Route route; |
|
|
|
|
|
|
|
RefCountedPtr<ServiceConfig> method_config; |
|
|
|
|
|
|
|
std::vector<ClusterWeightState> weighted_cluster_state; |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
explicit RouteEntry(const XdsRouteConfigResource::Route& r) : route(r) {} |
|
|
|
|
|
|
|
|
|
|
|
bool operator==(const XdsClusterMap& other) const { |
|
|
|
bool operator==(const RouteEntry& other) const { |
|
|
|
return clusters_ == other.clusters_; |
|
|
|
return route == other.route && |
|
|
|
|
|
|
|
weighted_cluster_state == other.weighted_cluster_state && |
|
|
|
|
|
|
|
MethodConfigsEqual(method_config.get(), |
|
|
|
|
|
|
|
other.method_config.get()); |
|
|
|
|
|
|
|
} |
|
|
|
|
|
|
|
}; |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
static absl::StatusOr<RefCountedPtr<RouteConfigData>> Create( |
|
|
|
|
|
|
|
XdsResolver* resolver, |
|
|
|
|
|
|
|
const std::vector<XdsRouteConfigResource::Route>& routes, |
|
|
|
|
|
|
|
const Duration& default_max_stream_duration); |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
bool operator==(const RouteConfigData& other) const { |
|
|
|
|
|
|
|
return clusters_ == other.clusters_ && routes_ == other.routes_; |
|
|
|
} |
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
RefCountedPtr<ClusterState> Find(absl::string_view name) const { |
|
|
|
RefCountedPtr<ClusterRef> FindClusterRef(absl::string_view name) const { |
|
|
|
auto it = clusters_.find(name); |
|
|
|
auto it = clusters_.find(name); |
|
|
|
if (it == clusters_.end()) { |
|
|
|
if (it == clusters_.end()) { |
|
|
|
return nullptr; |
|
|
|
return nullptr; |
|
|
@ -290,14 +312,36 @@ class XdsResolver : public Resolver { |
|
|
|
return it->second; |
|
|
|
return it->second; |
|
|
|
} |
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
RouteEntry* GetRouteForRequest(absl::string_view path, |
|
|
|
|
|
|
|
grpc_metadata_batch* initial_metadata); |
|
|
|
|
|
|
|
|
|
|
|
private: |
|
|
|
private: |
|
|
|
std::map<absl::string_view, RefCountedPtr<ClusterState>> clusters_; |
|
|
|
class RouteListIterator; |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
static absl::StatusOr<RefCountedPtr<ServiceConfig>> CreateMethodConfig( |
|
|
|
|
|
|
|
XdsResolver* resolver, const XdsRouteConfigResource::Route& route, |
|
|
|
|
|
|
|
const XdsRouteConfigResource::Route::RouteAction::ClusterWeight* |
|
|
|
|
|
|
|
cluster_weight); |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
static bool MethodConfigsEqual(const ServiceConfig* sc1, |
|
|
|
|
|
|
|
const ServiceConfig* sc2) { |
|
|
|
|
|
|
|
if (sc1 == nullptr) return sc2 == nullptr; |
|
|
|
|
|
|
|
if (sc2 == nullptr) return false; |
|
|
|
|
|
|
|
return sc1->json_string() == sc2->json_string(); |
|
|
|
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
absl::Status AddRouteEntry(const XdsRouteConfigResource::Route& route, |
|
|
|
|
|
|
|
const Duration& default_max_stream_duration, |
|
|
|
|
|
|
|
XdsResolver* resolver); |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
std::map<absl::string_view, RefCountedPtr<ClusterRef>> clusters_; |
|
|
|
|
|
|
|
std::vector<RouteEntry> routes_; |
|
|
|
}; |
|
|
|
}; |
|
|
|
|
|
|
|
|
|
|
|
class XdsConfigSelector : public ConfigSelector { |
|
|
|
class XdsConfigSelector : public ConfigSelector { |
|
|
|
public: |
|
|
|
public: |
|
|
|
XdsConfigSelector(RefCountedPtr<XdsResolver> resolver, |
|
|
|
XdsConfigSelector(RefCountedPtr<XdsResolver> resolver, |
|
|
|
absl::Status* status); |
|
|
|
RefCountedPtr<RouteConfigData> route_config_data); |
|
|
|
~XdsConfigSelector() override; |
|
|
|
~XdsConfigSelector() override; |
|
|
|
|
|
|
|
|
|
|
|
const char* name() const override { return "XdsConfigSelector"; } |
|
|
|
const char* name() const override { return "XdsConfigSelector"; } |
|
|
@ -305,8 +349,8 @@ class XdsResolver : public Resolver { |
|
|
|
bool Equals(const ConfigSelector* other) const override { |
|
|
|
bool Equals(const ConfigSelector* other) const override { |
|
|
|
const auto* other_xds = static_cast<const XdsConfigSelector*>(other); |
|
|
|
const auto* other_xds = static_cast<const XdsConfigSelector*>(other); |
|
|
|
// Don't need to compare resolver_, since that will always be the same.
|
|
|
|
// Don't need to compare resolver_, since that will always be the same.
|
|
|
|
return route_table_ == other_xds->route_table_ && |
|
|
|
return *route_config_data_ == *other_xds->route_config_data_ && |
|
|
|
*cluster_map_ == *other_xds->cluster_map_; |
|
|
|
filters_ == other_xds->filters_; |
|
|
|
} |
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
absl::Status GetCallConfig(GetCallConfigArgs args) override; |
|
|
|
absl::Status GetCallConfig(GetCallConfigArgs args) override; |
|
|
@ -316,34 +360,28 @@ class XdsResolver : public Resolver { |
|
|
|
} |
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
private: |
|
|
|
private: |
|
|
|
struct Route { |
|
|
|
RefCountedPtr<XdsResolver> resolver_; |
|
|
|
struct ClusterWeightState { |
|
|
|
RefCountedPtr<RouteConfigData> route_config_data_; |
|
|
|
uint32_t range_end; |
|
|
|
std::vector<const grpc_channel_filter*> filters_; |
|
|
|
absl::string_view cluster; |
|
|
|
}; |
|
|
|
RefCountedPtr<ServiceConfig> method_config; |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
bool operator==(const ClusterWeightState& other) const; |
|
|
|
|
|
|
|
}; |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
XdsRouteConfigResource::Route route; |
|
|
|
|
|
|
|
RefCountedPtr<ServiceConfig> method_config; |
|
|
|
|
|
|
|
std::vector<ClusterWeightState> weighted_cluster_state; |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
bool operator==(const Route& other) const; |
|
|
|
class XdsRouteStateAttributeImpl : public XdsRouteStateAttribute { |
|
|
|
}; |
|
|
|
public: |
|
|
|
using RouteTable = std::vector<Route>; |
|
|
|
explicit XdsRouteStateAttributeImpl( |
|
|
|
|
|
|
|
RefCountedPtr<RouteConfigData> route_config_data, |
|
|
|
|
|
|
|
RouteConfigData::RouteEntry* route) |
|
|
|
|
|
|
|
: route_config_data_(std::move(route_config_data)), route_(route) {} |
|
|
|
|
|
|
|
|
|
|
|
class RouteListIterator; |
|
|
|
// This method can be called only once. The first call will release
|
|
|
|
|
|
|
|
// the reference to the cluster map, and subsequent calls will return
|
|
|
|
|
|
|
|
// nullptr.
|
|
|
|
|
|
|
|
RefCountedPtr<ClusterRef> LockAndGetCluster(absl::string_view cluster_name); |
|
|
|
|
|
|
|
|
|
|
|
absl::StatusOr<RefCountedPtr<ServiceConfig>> CreateMethodConfig( |
|
|
|
bool HasClusterForRoute(absl::string_view cluster_name) const override; |
|
|
|
const XdsRouteConfigResource::Route& route, |
|
|
|
|
|
|
|
const XdsRouteConfigResource::Route::RouteAction::ClusterWeight* |
|
|
|
|
|
|
|
cluster_weight); |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
RefCountedPtr<XdsResolver> resolver_; |
|
|
|
private: |
|
|
|
RouteTable route_table_; |
|
|
|
RefCountedPtr<RouteConfigData> route_config_data_; |
|
|
|
RefCountedPtr<XdsClusterMap> cluster_map_; |
|
|
|
RouteConfigData::RouteEntry* route_; |
|
|
|
std::vector<const grpc_channel_filter*> filters_; |
|
|
|
|
|
|
|
}; |
|
|
|
}; |
|
|
|
|
|
|
|
|
|
|
|
class ClusterSelectionFilter : public ChannelFilter { |
|
|
|
class ClusterSelectionFilter : public ChannelFilter { |
|
|
@ -357,29 +395,7 @@ class XdsResolver : public Resolver { |
|
|
|
|
|
|
|
|
|
|
|
// Construct a promise for one call.
|
|
|
|
// Construct a promise for one call.
|
|
|
|
ArenaPromise<ServerMetadataHandle> MakeCallPromise( |
|
|
|
ArenaPromise<ServerMetadataHandle> MakeCallPromise( |
|
|
|
CallArgs call_args, NextPromiseFactory next_promise_factory) override { |
|
|
|
CallArgs call_args, NextPromiseFactory next_promise_factory) override; |
|
|
|
auto* service_config_call_data = |
|
|
|
|
|
|
|
static_cast<ClientChannelServiceConfigCallData*>( |
|
|
|
|
|
|
|
GetContext<grpc_call_context_element>() |
|
|
|
|
|
|
|
[GRPC_CONTEXT_SERVICE_CONFIG_CALL_DATA] |
|
|
|
|
|
|
|
.value); |
|
|
|
|
|
|
|
GPR_ASSERT(service_config_call_data != nullptr); |
|
|
|
|
|
|
|
auto* cluster_data = static_cast<XdsClusterMapAttribute*>( |
|
|
|
|
|
|
|
service_config_call_data->GetCallAttribute( |
|
|
|
|
|
|
|
XdsClusterMapAttribute::TypeName())); |
|
|
|
|
|
|
|
auto* cluster_name_attribute = static_cast<XdsClusterAttribute*>( |
|
|
|
|
|
|
|
service_config_call_data->GetCallAttribute( |
|
|
|
|
|
|
|
XdsClusterAttribute::TypeName())); |
|
|
|
|
|
|
|
if (cluster_data != nullptr && cluster_name_attribute != nullptr) { |
|
|
|
|
|
|
|
auto cluster = |
|
|
|
|
|
|
|
cluster_data->LockAndGetCluster(cluster_name_attribute->cluster()); |
|
|
|
|
|
|
|
if (cluster != nullptr) { |
|
|
|
|
|
|
|
service_config_call_data->SetOnCommit( |
|
|
|
|
|
|
|
[cluster = std::move(cluster)]() mutable { cluster.reset(); }); |
|
|
|
|
|
|
|
} |
|
|
|
|
|
|
|
} |
|
|
|
|
|
|
|
return next_promise_factory(std::move(call_args)); |
|
|
|
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
private: |
|
|
|
private: |
|
|
|
explicit ClusterSelectionFilter(ChannelFilter::Args filter_args) |
|
|
|
explicit ClusterSelectionFilter(ChannelFilter::Args filter_args) |
|
|
@ -388,46 +404,17 @@ class XdsResolver : public Resolver { |
|
|
|
ChannelFilter::Args filter_args_; |
|
|
|
ChannelFilter::Args filter_args_; |
|
|
|
}; |
|
|
|
}; |
|
|
|
|
|
|
|
|
|
|
|
RefCountedPtr<ClusterState> GetOrCreateClusterState( |
|
|
|
RefCountedPtr<ClusterRef> GetOrCreateClusterRef( |
|
|
|
absl::string_view cluster_name) { |
|
|
|
absl::string_view cluster_name) { |
|
|
|
auto it = cluster_state_map_.find(cluster_name); |
|
|
|
auto it = cluster_ref_map_.find(cluster_name); |
|
|
|
if (it == cluster_state_map_.end()) { |
|
|
|
if (it == cluster_ref_map_.end()) { |
|
|
|
auto cluster = MakeRefCounted<ClusterState>(Ref(), cluster_name); |
|
|
|
auto cluster = MakeRefCounted<ClusterRef>(Ref(), cluster_name); |
|
|
|
cluster_state_map_.emplace(cluster->cluster_name(), cluster->WeakRef()); |
|
|
|
cluster_ref_map_.emplace(cluster->cluster_name(), cluster->WeakRef()); |
|
|
|
return cluster; |
|
|
|
return cluster; |
|
|
|
} |
|
|
|
} |
|
|
|
return it->second->Ref(); |
|
|
|
return it->second->Ref(); |
|
|
|
} |
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
class XdsClusterMapAttribute |
|
|
|
|
|
|
|
: public ServiceConfigCallData::CallAttributeInterface { |
|
|
|
|
|
|
|
public: |
|
|
|
|
|
|
|
static UniqueTypeName TypeName() { |
|
|
|
|
|
|
|
static UniqueTypeName::Factory factory("xds_cluster_lb_data"); |
|
|
|
|
|
|
|
return factory.Create(); |
|
|
|
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
explicit XdsClusterMapAttribute(RefCountedPtr<XdsClusterMap> cluster_map) |
|
|
|
|
|
|
|
: cluster_map_(std::move(cluster_map)) {} |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
// This method can be called only once. The first call will release the
|
|
|
|
|
|
|
|
// reference to the cluster map, and subsequent calls will return nullptr.
|
|
|
|
|
|
|
|
RefCountedPtr<ClusterState> LockAndGetCluster( |
|
|
|
|
|
|
|
absl::string_view cluster_name) { |
|
|
|
|
|
|
|
if (cluster_map_ == nullptr) { |
|
|
|
|
|
|
|
return nullptr; |
|
|
|
|
|
|
|
} |
|
|
|
|
|
|
|
auto cluster = cluster_map_->Find(cluster_name); |
|
|
|
|
|
|
|
cluster_map_.reset(); |
|
|
|
|
|
|
|
return cluster; |
|
|
|
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
UniqueTypeName type() const override { return TypeName(); } |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
private: |
|
|
|
|
|
|
|
RefCountedPtr<XdsClusterMap> cluster_map_; |
|
|
|
|
|
|
|
}; |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
void OnListenerUpdate(XdsListenerResource listener); |
|
|
|
void OnListenerUpdate(XdsListenerResource listener); |
|
|
|
void OnRouteConfigUpdate(XdsRouteConfigResource rds_update); |
|
|
|
void OnRouteConfigUpdate(XdsRouteConfigResource rds_update); |
|
|
|
void OnError(absl::string_view context, absl::Status status); |
|
|
|
void OnError(absl::string_view context, absl::Status status); |
|
|
@ -461,188 +448,72 @@ class XdsResolver : public Resolver { |
|
|
|
std::string /*LB policy config*/> |
|
|
|
std::string /*LB policy config*/> |
|
|
|
cluster_specifier_plugin_map_; |
|
|
|
cluster_specifier_plugin_map_; |
|
|
|
|
|
|
|
|
|
|
|
std::map<absl::string_view, WeakRefCountedPtr<ClusterState>> |
|
|
|
std::map<absl::string_view, WeakRefCountedPtr<ClusterRef>> cluster_ref_map_; |
|
|
|
cluster_state_map_; |
|
|
|
|
|
|
|
}; |
|
|
|
}; |
|
|
|
|
|
|
|
|
|
|
|
//
|
|
|
|
//
|
|
|
|
// XdsResolver::XdsConfigSelector::Route
|
|
|
|
// XdsResolver::RouteConfigData::RouteListIterator
|
|
|
|
//
|
|
|
|
//
|
|
|
|
|
|
|
|
|
|
|
|
bool MethodConfigsEqual(const ServiceConfig* sc1, const ServiceConfig* sc2) { |
|
|
|
|
|
|
|
if (sc1 == nullptr) return sc2 == nullptr; |
|
|
|
|
|
|
|
if (sc2 == nullptr) return false; |
|
|
|
|
|
|
|
return sc1->json_string() == sc2->json_string(); |
|
|
|
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
const grpc_channel_filter XdsResolver::ClusterSelectionFilter::kFilter = |
|
|
|
|
|
|
|
MakePromiseBasedFilter<ClusterSelectionFilter, FilterEndpoint::kClient, |
|
|
|
|
|
|
|
kFilterExaminesServerInitialMetadata>( |
|
|
|
|
|
|
|
"cluster_selection_filter"); |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
bool XdsResolver::XdsConfigSelector::Route::ClusterWeightState::operator==( |
|
|
|
|
|
|
|
const ClusterWeightState& other) const { |
|
|
|
|
|
|
|
return range_end == other.range_end && cluster == other.cluster && |
|
|
|
|
|
|
|
MethodConfigsEqual(method_config.get(), other.method_config.get()); |
|
|
|
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
bool XdsResolver::XdsConfigSelector::Route::operator==( |
|
|
|
|
|
|
|
const Route& other) const { |
|
|
|
|
|
|
|
return route == other.route && |
|
|
|
|
|
|
|
weighted_cluster_state == other.weighted_cluster_state && |
|
|
|
|
|
|
|
MethodConfigsEqual(method_config.get(), other.method_config.get()); |
|
|
|
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
// Implementation of XdsRouting::RouteListIterator for getting the matching
|
|
|
|
// Implementation of XdsRouting::RouteListIterator for getting the matching
|
|
|
|
// route for a request.
|
|
|
|
// route for a request.
|
|
|
|
class XdsResolver::XdsConfigSelector::RouteListIterator |
|
|
|
class XdsResolver::RouteConfigData::RouteListIterator |
|
|
|
: public XdsRouting::RouteListIterator { |
|
|
|
: public XdsRouting::RouteListIterator { |
|
|
|
public: |
|
|
|
public: |
|
|
|
explicit RouteListIterator(const RouteTable* route_table) |
|
|
|
explicit RouteListIterator(const RouteConfigData* route_table) |
|
|
|
: route_table_(route_table) {} |
|
|
|
: route_table_(route_table) {} |
|
|
|
|
|
|
|
|
|
|
|
size_t Size() const override { return route_table_->size(); } |
|
|
|
size_t Size() const override { return route_table_->routes_.size(); } |
|
|
|
|
|
|
|
|
|
|
|
const XdsRouteConfigResource::Route::Matchers& GetMatchersForRoute( |
|
|
|
const XdsRouteConfigResource::Route::Matchers& GetMatchersForRoute( |
|
|
|
size_t index) const override { |
|
|
|
size_t index) const override { |
|
|
|
return (*route_table_)[index].route.matchers; |
|
|
|
return route_table_->routes_[index].route.matchers; |
|
|
|
} |
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
private: |
|
|
|
private: |
|
|
|
const RouteTable* route_table_; |
|
|
|
const RouteConfigData* route_table_; |
|
|
|
}; |
|
|
|
}; |
|
|
|
|
|
|
|
|
|
|
|
//
|
|
|
|
//
|
|
|
|
// XdsResolver::XdsConfigSelector
|
|
|
|
// XdsResolver::RouteConfigData
|
|
|
|
//
|
|
|
|
//
|
|
|
|
|
|
|
|
|
|
|
|
XdsResolver::XdsConfigSelector::XdsConfigSelector( |
|
|
|
absl::StatusOr<RefCountedPtr<XdsResolver::RouteConfigData>> |
|
|
|
RefCountedPtr<XdsResolver> resolver, absl::Status* status) |
|
|
|
XdsResolver::RouteConfigData::Create( |
|
|
|
: resolver_(std::move(resolver)) { |
|
|
|
XdsResolver* resolver, |
|
|
|
if (GRPC_TRACE_FLAG_ENABLED(grpc_xds_resolver_trace)) { |
|
|
|
const std::vector<XdsRouteConfigResource::Route>& routes, |
|
|
|
gpr_log(GPR_INFO, "[xds_resolver %p] creating XdsConfigSelector %p", |
|
|
|
const Duration& default_max_stream_duration) { |
|
|
|
resolver_.get(), this); |
|
|
|
auto data = MakeRefCounted<RouteConfigData>(); |
|
|
|
} |
|
|
|
|
|
|
|
// 1. Construct the route table
|
|
|
|
|
|
|
|
// 2 Update resolver's cluster state map
|
|
|
|
|
|
|
|
// 3. Construct cluster list to hold on to entries in the cluster state
|
|
|
|
|
|
|
|
// map.
|
|
|
|
|
|
|
|
// Reserve the necessary entries up-front to avoid reallocation as we add
|
|
|
|
// Reserve the necessary entries up-front to avoid reallocation as we add
|
|
|
|
// elements. This is necessary because the string_view in the entry's
|
|
|
|
// elements. This is necessary because the string_view in the entry's
|
|
|
|
// weighted_cluster_state field points to the memory in the route field, so
|
|
|
|
// weighted_cluster_state field points to the memory in the route field, so
|
|
|
|
// moving the entry in a reallocation will cause the string_view to point to
|
|
|
|
// moving the entry in a reallocation will cause the string_view to point to
|
|
|
|
// invalid data.
|
|
|
|
// invalid data.
|
|
|
|
route_table_.reserve(resolver_->current_virtual_host_->routes.size()); |
|
|
|
data->routes_.reserve(routes.size()); |
|
|
|
std::map<absl::string_view, RefCountedPtr<ClusterState>> clusters; |
|
|
|
for (auto& route : routes) { |
|
|
|
auto maybe_add_cluster = [&](absl::string_view cluster_name) { |
|
|
|
absl::Status status = |
|
|
|
if (clusters.find(cluster_name) != clusters.end()) return; |
|
|
|
data->AddRouteEntry(route, default_max_stream_duration, resolver); |
|
|
|
auto cluster_state = resolver_->GetOrCreateClusterState(cluster_name); |
|
|
|
if (!status.ok()) { |
|
|
|
absl::string_view name = cluster_state->cluster_name(); |
|
|
|
return status; |
|
|
|
clusters.emplace(name, std::move(cluster_state)); |
|
|
|
|
|
|
|
}; |
|
|
|
|
|
|
|
for (auto& route : resolver_->current_virtual_host_->routes) { |
|
|
|
|
|
|
|
if (GRPC_TRACE_FLAG_ENABLED(grpc_xds_resolver_trace)) { |
|
|
|
|
|
|
|
gpr_log(GPR_INFO, "[xds_resolver %p] XdsConfigSelector %p: route: %s", |
|
|
|
|
|
|
|
resolver_.get(), this, route.ToString().c_str()); |
|
|
|
|
|
|
|
} |
|
|
|
|
|
|
|
route_table_.emplace_back(); |
|
|
|
|
|
|
|
auto& route_entry = route_table_.back(); |
|
|
|
|
|
|
|
route_entry.route = route; |
|
|
|
|
|
|
|
auto* route_action = |
|
|
|
|
|
|
|
absl::get_if<XdsRouteConfigResource::Route::RouteAction>( |
|
|
|
|
|
|
|
&route_entry.route.action); |
|
|
|
|
|
|
|
if (route_action != nullptr) { |
|
|
|
|
|
|
|
// If the route doesn't specify a timeout, set its timeout to the global
|
|
|
|
|
|
|
|
// one.
|
|
|
|
|
|
|
|
if (!route_action->max_stream_duration.has_value()) { |
|
|
|
|
|
|
|
route_action->max_stream_duration = |
|
|
|
|
|
|
|
resolver_->current_listener_.http_max_stream_duration; |
|
|
|
|
|
|
|
} |
|
|
|
|
|
|
|
Match( |
|
|
|
|
|
|
|
route_action->action, |
|
|
|
|
|
|
|
// cluster name
|
|
|
|
|
|
|
|
[&](const XdsRouteConfigResource::Route::RouteAction::ClusterName& |
|
|
|
|
|
|
|
cluster_name) { |
|
|
|
|
|
|
|
auto result = CreateMethodConfig(route_entry.route, nullptr); |
|
|
|
|
|
|
|
if (!result.ok()) { |
|
|
|
|
|
|
|
*status = result.status(); |
|
|
|
|
|
|
|
return; |
|
|
|
|
|
|
|
} |
|
|
|
|
|
|
|
route_entry.method_config = std::move(*result); |
|
|
|
|
|
|
|
maybe_add_cluster( |
|
|
|
|
|
|
|
absl::StrCat("cluster:", cluster_name.cluster_name)); |
|
|
|
|
|
|
|
}, |
|
|
|
|
|
|
|
// WeightedClusters
|
|
|
|
|
|
|
|
[&](const std::vector< |
|
|
|
|
|
|
|
XdsRouteConfigResource::Route::RouteAction::ClusterWeight>& |
|
|
|
|
|
|
|
weighted_clusters) { |
|
|
|
|
|
|
|
uint32_t end = 0; |
|
|
|
|
|
|
|
for (const auto& weighted_cluster : weighted_clusters) { |
|
|
|
|
|
|
|
Route::ClusterWeightState cluster_weight_state; |
|
|
|
|
|
|
|
auto result = |
|
|
|
|
|
|
|
CreateMethodConfig(route_entry.route, &weighted_cluster); |
|
|
|
|
|
|
|
if (!result.ok()) { |
|
|
|
|
|
|
|
*status = result.status(); |
|
|
|
|
|
|
|
return; |
|
|
|
|
|
|
|
} |
|
|
|
|
|
|
|
cluster_weight_state.method_config = std::move(*result); |
|
|
|
|
|
|
|
end += weighted_cluster.weight; |
|
|
|
|
|
|
|
cluster_weight_state.range_end = end; |
|
|
|
|
|
|
|
cluster_weight_state.cluster = weighted_cluster.name; |
|
|
|
|
|
|
|
route_entry.weighted_cluster_state.push_back( |
|
|
|
|
|
|
|
std::move(cluster_weight_state)); |
|
|
|
|
|
|
|
maybe_add_cluster( |
|
|
|
|
|
|
|
absl::StrCat("cluster:", weighted_cluster.name)); |
|
|
|
|
|
|
|
} |
|
|
|
|
|
|
|
}, |
|
|
|
|
|
|
|
// ClusterSpecifierPlugin
|
|
|
|
|
|
|
|
[&](const XdsRouteConfigResource::Route::RouteAction:: |
|
|
|
|
|
|
|
ClusterSpecifierPluginName& cluster_specifier_plugin_name) { |
|
|
|
|
|
|
|
auto result = CreateMethodConfig(route_entry.route, nullptr); |
|
|
|
|
|
|
|
if (!result.ok()) { |
|
|
|
|
|
|
|
*status = result.status(); |
|
|
|
|
|
|
|
return; |
|
|
|
|
|
|
|
} |
|
|
|
|
|
|
|
route_entry.method_config = std::move(*result); |
|
|
|
|
|
|
|
maybe_add_cluster(absl::StrCat( |
|
|
|
|
|
|
|
"cluster_specifier_plugin:", |
|
|
|
|
|
|
|
cluster_specifier_plugin_name.cluster_specifier_plugin_name)); |
|
|
|
|
|
|
|
}); |
|
|
|
|
|
|
|
if (!status->ok()) return; |
|
|
|
|
|
|
|
} |
|
|
|
|
|
|
|
} |
|
|
|
|
|
|
|
cluster_map_ = MakeRefCounted<XdsClusterMap>(std::move(clusters)); |
|
|
|
|
|
|
|
// Populate filter list.
|
|
|
|
|
|
|
|
const auto& http_filter_registry = |
|
|
|
|
|
|
|
static_cast<const GrpcXdsBootstrap&>(resolver_->xds_client_->bootstrap()) |
|
|
|
|
|
|
|
.http_filter_registry(); |
|
|
|
|
|
|
|
for (const auto& http_filter : resolver_->current_listener_.http_filters) { |
|
|
|
|
|
|
|
// Find filter. This is guaranteed to succeed, because it's checked
|
|
|
|
|
|
|
|
// at config validation time in the XdsApi code.
|
|
|
|
|
|
|
|
const XdsHttpFilterImpl* filter_impl = |
|
|
|
|
|
|
|
http_filter_registry.GetFilterForType( |
|
|
|
|
|
|
|
http_filter.config.config_proto_type_name); |
|
|
|
|
|
|
|
GPR_ASSERT(filter_impl != nullptr); |
|
|
|
|
|
|
|
// Add C-core filter to list.
|
|
|
|
|
|
|
|
if (filter_impl->channel_filter() != nullptr) { |
|
|
|
|
|
|
|
filters_.push_back(filter_impl->channel_filter()); |
|
|
|
|
|
|
|
} |
|
|
|
} |
|
|
|
} |
|
|
|
} |
|
|
|
filters_.push_back(&ClusterSelectionFilter::kFilter); |
|
|
|
return data; |
|
|
|
} |
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
XdsResolver::XdsConfigSelector::~XdsConfigSelector() { |
|
|
|
XdsResolver::RouteConfigData::RouteEntry* |
|
|
|
if (GRPC_TRACE_FLAG_ENABLED(grpc_xds_resolver_trace)) { |
|
|
|
XdsResolver::RouteConfigData::GetRouteForRequest( |
|
|
|
gpr_log(GPR_INFO, "[xds_resolver %p] destroying XdsConfigSelector %p", |
|
|
|
absl::string_view path, grpc_metadata_batch* initial_metadata) { |
|
|
|
resolver_.get(), this); |
|
|
|
auto route_index = XdsRouting::GetRouteForRequest(RouteListIterator(this), |
|
|
|
|
|
|
|
path, initial_metadata); |
|
|
|
|
|
|
|
if (!route_index.has_value()) { |
|
|
|
|
|
|
|
return nullptr; |
|
|
|
} |
|
|
|
} |
|
|
|
cluster_map_.reset(); |
|
|
|
return &routes_[*route_index]; |
|
|
|
resolver_->MaybeRemoveUnusedClusters(); |
|
|
|
|
|
|
|
} |
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
absl::StatusOr<RefCountedPtr<ServiceConfig>> |
|
|
|
absl::StatusOr<RefCountedPtr<ServiceConfig>> |
|
|
|
XdsResolver::XdsConfigSelector::CreateMethodConfig( |
|
|
|
XdsResolver::RouteConfigData::CreateMethodConfig( |
|
|
|
const XdsRouteConfigResource::Route& route, |
|
|
|
XdsResolver* resolver, const XdsRouteConfigResource::Route& route, |
|
|
|
const XdsRouteConfigResource::Route::RouteAction::ClusterWeight* |
|
|
|
const XdsRouteConfigResource::Route::RouteAction::ClusterWeight* |
|
|
|
cluster_weight) { |
|
|
|
cluster_weight) { |
|
|
|
std::vector<std::string> fields; |
|
|
|
std::vector<std::string> fields; |
|
|
@ -694,11 +565,11 @@ XdsResolver::XdsConfigSelector::CreateMethodConfig( |
|
|
|
} |
|
|
|
} |
|
|
|
// Handle xDS HTTP filters.
|
|
|
|
// Handle xDS HTTP filters.
|
|
|
|
auto result = XdsRouting::GeneratePerHTTPFilterConfigs( |
|
|
|
auto result = XdsRouting::GeneratePerHTTPFilterConfigs( |
|
|
|
static_cast<const GrpcXdsBootstrap&>(resolver_->xds_client_->bootstrap()) |
|
|
|
static_cast<const GrpcXdsBootstrap&>(resolver->xds_client_->bootstrap()) |
|
|
|
.http_filter_registry(), |
|
|
|
.http_filter_registry(), |
|
|
|
resolver_->current_listener_.http_filters, |
|
|
|
resolver->current_listener_.http_filters, |
|
|
|
resolver_->current_virtual_host_.value(), route, cluster_weight, |
|
|
|
resolver->current_virtual_host_.value(), route, cluster_weight, |
|
|
|
resolver_->args_); |
|
|
|
resolver->args_); |
|
|
|
if (!result.ok()) return result.status(); |
|
|
|
if (!result.ok()) return result.status(); |
|
|
|
for (const auto& p : result->per_filter_configs) { |
|
|
|
for (const auto& p : result->per_filter_configs) { |
|
|
|
fields.emplace_back(absl::StrCat(" \"", p.first, "\": [\n", |
|
|
|
fields.emplace_back(absl::StrCat(" \"", p.first, "\": [\n", |
|
|
@ -722,6 +593,128 @@ XdsResolver::XdsConfigSelector::CreateMethodConfig( |
|
|
|
return nullptr; |
|
|
|
return nullptr; |
|
|
|
} |
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
absl::Status XdsResolver::RouteConfigData::AddRouteEntry( |
|
|
|
|
|
|
|
const XdsRouteConfigResource::Route& route, |
|
|
|
|
|
|
|
const Duration& default_max_stream_duration, XdsResolver* resolver) { |
|
|
|
|
|
|
|
if (GRPC_TRACE_FLAG_ENABLED(grpc_xds_resolver_trace)) { |
|
|
|
|
|
|
|
gpr_log(GPR_INFO, "[xds_resolver %p] XdsConfigSelector %p: route: %s", |
|
|
|
|
|
|
|
resolver, this, route.ToString().c_str()); |
|
|
|
|
|
|
|
} |
|
|
|
|
|
|
|
routes_.emplace_back(route); |
|
|
|
|
|
|
|
auto* route_entry = &routes_.back(); |
|
|
|
|
|
|
|
auto maybe_add_cluster = [&](absl::string_view cluster_name) { |
|
|
|
|
|
|
|
if (clusters_.find(cluster_name) != clusters_.end()) return; |
|
|
|
|
|
|
|
auto cluster_state = resolver->GetOrCreateClusterRef(cluster_name); |
|
|
|
|
|
|
|
absl::string_view name = cluster_state->cluster_name(); |
|
|
|
|
|
|
|
clusters_.emplace(name, std::move(cluster_state)); |
|
|
|
|
|
|
|
}; |
|
|
|
|
|
|
|
auto* route_action = absl::get_if<XdsRouteConfigResource::Route::RouteAction>( |
|
|
|
|
|
|
|
&route_entry->route.action); |
|
|
|
|
|
|
|
if (route_action != nullptr) { |
|
|
|
|
|
|
|
// If the route doesn't specify a timeout, set its timeout to the global
|
|
|
|
|
|
|
|
// one.
|
|
|
|
|
|
|
|
if (!route_action->max_stream_duration.has_value()) { |
|
|
|
|
|
|
|
route_action->max_stream_duration = default_max_stream_duration; |
|
|
|
|
|
|
|
} |
|
|
|
|
|
|
|
absl::Status status = Match( |
|
|
|
|
|
|
|
route_action->action, |
|
|
|
|
|
|
|
// cluster name
|
|
|
|
|
|
|
|
[&](const XdsRouteConfigResource::Route::RouteAction::ClusterName& |
|
|
|
|
|
|
|
cluster_name) { |
|
|
|
|
|
|
|
auto result = |
|
|
|
|
|
|
|
CreateMethodConfig(resolver, route_entry->route, nullptr); |
|
|
|
|
|
|
|
if (!result.ok()) { |
|
|
|
|
|
|
|
return result.status(); |
|
|
|
|
|
|
|
} |
|
|
|
|
|
|
|
route_entry->method_config = std::move(*result); |
|
|
|
|
|
|
|
maybe_add_cluster( |
|
|
|
|
|
|
|
absl::StrCat("cluster:", cluster_name.cluster_name)); |
|
|
|
|
|
|
|
return absl::OkStatus(); |
|
|
|
|
|
|
|
}, |
|
|
|
|
|
|
|
// WeightedClusters
|
|
|
|
|
|
|
|
[&](const std::vector< |
|
|
|
|
|
|
|
XdsRouteConfigResource::Route::RouteAction::ClusterWeight>& |
|
|
|
|
|
|
|
weighted_clusters) { |
|
|
|
|
|
|
|
uint32_t end = 0; |
|
|
|
|
|
|
|
for (const auto& weighted_cluster : weighted_clusters) { |
|
|
|
|
|
|
|
auto result = CreateMethodConfig(resolver, route_entry->route, |
|
|
|
|
|
|
|
&weighted_cluster); |
|
|
|
|
|
|
|
if (!result.ok()) { |
|
|
|
|
|
|
|
return result.status(); |
|
|
|
|
|
|
|
} |
|
|
|
|
|
|
|
RouteEntry::ClusterWeightState cluster_weight_state; |
|
|
|
|
|
|
|
cluster_weight_state.method_config = std::move(*result); |
|
|
|
|
|
|
|
end += weighted_cluster.weight; |
|
|
|
|
|
|
|
cluster_weight_state.range_end = end; |
|
|
|
|
|
|
|
cluster_weight_state.cluster = weighted_cluster.name; |
|
|
|
|
|
|
|
route_entry->weighted_cluster_state.push_back( |
|
|
|
|
|
|
|
std::move(cluster_weight_state)); |
|
|
|
|
|
|
|
maybe_add_cluster(absl::StrCat("cluster:", weighted_cluster.name)); |
|
|
|
|
|
|
|
} |
|
|
|
|
|
|
|
return absl::OkStatus(); |
|
|
|
|
|
|
|
}, |
|
|
|
|
|
|
|
// ClusterSpecifierPlugin
|
|
|
|
|
|
|
|
[&](const XdsRouteConfigResource::Route::RouteAction:: |
|
|
|
|
|
|
|
ClusterSpecifierPluginName& cluster_specifier_plugin_name) { |
|
|
|
|
|
|
|
auto result = |
|
|
|
|
|
|
|
CreateMethodConfig(resolver, route_entry->route, nullptr); |
|
|
|
|
|
|
|
if (!result.ok()) { |
|
|
|
|
|
|
|
return result.status(); |
|
|
|
|
|
|
|
} |
|
|
|
|
|
|
|
route_entry->method_config = std::move(*result); |
|
|
|
|
|
|
|
maybe_add_cluster(absl::StrCat( |
|
|
|
|
|
|
|
"cluster_specifier_plugin:", |
|
|
|
|
|
|
|
cluster_specifier_plugin_name.cluster_specifier_plugin_name)); |
|
|
|
|
|
|
|
return absl::OkStatus(); |
|
|
|
|
|
|
|
}); |
|
|
|
|
|
|
|
if (!status.ok()) { |
|
|
|
|
|
|
|
return status; |
|
|
|
|
|
|
|
} |
|
|
|
|
|
|
|
} |
|
|
|
|
|
|
|
return absl::OkStatus(); |
|
|
|
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
//
|
|
|
|
|
|
|
|
// XdsResolver::XdsConfigSelector
|
|
|
|
|
|
|
|
//
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
XdsResolver::XdsConfigSelector::XdsConfigSelector( |
|
|
|
|
|
|
|
RefCountedPtr<XdsResolver> resolver, |
|
|
|
|
|
|
|
RefCountedPtr<RouteConfigData> route_config_data) |
|
|
|
|
|
|
|
: resolver_(std::move(resolver)), |
|
|
|
|
|
|
|
route_config_data_(std::move(route_config_data)) { |
|
|
|
|
|
|
|
if (GRPC_TRACE_FLAG_ENABLED(grpc_xds_resolver_trace)) { |
|
|
|
|
|
|
|
gpr_log(GPR_INFO, "[xds_resolver %p] creating XdsConfigSelector %p", |
|
|
|
|
|
|
|
resolver_.get(), this); |
|
|
|
|
|
|
|
} |
|
|
|
|
|
|
|
// Populate filter list.
|
|
|
|
|
|
|
|
const auto& http_filter_registry = |
|
|
|
|
|
|
|
static_cast<const GrpcXdsBootstrap&>(resolver_->xds_client_->bootstrap()) |
|
|
|
|
|
|
|
.http_filter_registry(); |
|
|
|
|
|
|
|
for (const auto& http_filter : resolver_->current_listener_.http_filters) { |
|
|
|
|
|
|
|
// Find filter. This is guaranteed to succeed, because it's checked
|
|
|
|
|
|
|
|
// at config validation time in the XdsApi code.
|
|
|
|
|
|
|
|
const XdsHttpFilterImpl* filter_impl = |
|
|
|
|
|
|
|
http_filter_registry.GetFilterForType( |
|
|
|
|
|
|
|
http_filter.config.config_proto_type_name); |
|
|
|
|
|
|
|
GPR_ASSERT(filter_impl != nullptr); |
|
|
|
|
|
|
|
// Add C-core filter to list.
|
|
|
|
|
|
|
|
if (filter_impl->channel_filter() != nullptr) { |
|
|
|
|
|
|
|
filters_.push_back(filter_impl->channel_filter()); |
|
|
|
|
|
|
|
} |
|
|
|
|
|
|
|
} |
|
|
|
|
|
|
|
filters_.push_back(&ClusterSelectionFilter::kFilter); |
|
|
|
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
XdsResolver::XdsConfigSelector::~XdsConfigSelector() { |
|
|
|
|
|
|
|
if (GRPC_TRACE_FLAG_ENABLED(grpc_xds_resolver_trace)) { |
|
|
|
|
|
|
|
gpr_log(GPR_INFO, "[xds_resolver %p] destroying XdsConfigSelector %p", |
|
|
|
|
|
|
|
resolver_.get(), this); |
|
|
|
|
|
|
|
} |
|
|
|
|
|
|
|
route_config_data_.reset(); |
|
|
|
|
|
|
|
resolver_->MaybeRemoveUnusedClusters(); |
|
|
|
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
absl::optional<uint64_t> HeaderHashHelper( |
|
|
|
absl::optional<uint64_t> HeaderHashHelper( |
|
|
|
const XdsRouteConfigResource::Route::RouteAction::HashPolicy::Header& |
|
|
|
const XdsRouteConfigResource::Route::RouteAction::HashPolicy::Header& |
|
|
|
header_policy, |
|
|
|
header_policy, |
|
|
@ -747,18 +740,16 @@ absl::Status XdsResolver::XdsConfigSelector::GetCallConfig( |
|
|
|
GetCallConfigArgs args) { |
|
|
|
GetCallConfigArgs args) { |
|
|
|
Slice* path = args.initial_metadata->get_pointer(HttpPathMetadata()); |
|
|
|
Slice* path = args.initial_metadata->get_pointer(HttpPathMetadata()); |
|
|
|
GPR_ASSERT(path != nullptr); |
|
|
|
GPR_ASSERT(path != nullptr); |
|
|
|
auto route_index = XdsRouting::GetRouteForRequest( |
|
|
|
auto* entry = route_config_data_->GetRouteForRequest(path->as_string_view(), |
|
|
|
RouteListIterator(&route_table_), path->as_string_view(), |
|
|
|
args.initial_metadata); |
|
|
|
args.initial_metadata); |
|
|
|
if (entry == nullptr) { |
|
|
|
if (!route_index.has_value()) { |
|
|
|
|
|
|
|
return absl::UnavailableError( |
|
|
|
return absl::UnavailableError( |
|
|
|
"No matching route found in xDS route config"); |
|
|
|
"No matching route found in xDS route config"); |
|
|
|
} |
|
|
|
} |
|
|
|
auto& entry = route_table_[*route_index]; |
|
|
|
|
|
|
|
// Found a route match
|
|
|
|
// Found a route match
|
|
|
|
const auto* route_action = |
|
|
|
const auto* route_action = |
|
|
|
absl::get_if<XdsRouteConfigResource::Route::RouteAction>( |
|
|
|
absl::get_if<XdsRouteConfigResource::Route::RouteAction>( |
|
|
|
&entry.route.action); |
|
|
|
&entry->route.action); |
|
|
|
if (route_action == nullptr) { |
|
|
|
if (route_action == nullptr) { |
|
|
|
return absl::UnavailableError("Matching route has inappropriate action"); |
|
|
|
return absl::UnavailableError("Matching route has inappropriate action"); |
|
|
|
} |
|
|
|
} |
|
|
@ -771,24 +762,24 @@ absl::Status XdsResolver::XdsConfigSelector::GetCallConfig( |
|
|
|
action_cluster_name) { |
|
|
|
action_cluster_name) { |
|
|
|
cluster_name = |
|
|
|
cluster_name = |
|
|
|
absl::StrCat("cluster:", action_cluster_name.cluster_name); |
|
|
|
absl::StrCat("cluster:", action_cluster_name.cluster_name); |
|
|
|
method_config = entry.method_config; |
|
|
|
method_config = entry->method_config; |
|
|
|
}, |
|
|
|
}, |
|
|
|
// WeightedClusters
|
|
|
|
// WeightedClusters
|
|
|
|
[&](const std::vector< |
|
|
|
[&](const std::vector< |
|
|
|
XdsRouteConfigResource::Route::RouteAction::ClusterWeight>& |
|
|
|
XdsRouteConfigResource::Route::RouteAction::ClusterWeight>& |
|
|
|
/*weighted_clusters*/) { |
|
|
|
/*weighted_clusters*/) { |
|
|
|
const uint32_t key = absl::Uniform<uint32_t>( |
|
|
|
const uint32_t key = absl::Uniform<uint32_t>( |
|
|
|
absl::BitGen(), 0, entry.weighted_cluster_state.back().range_end); |
|
|
|
absl::BitGen(), 0, entry->weighted_cluster_state.back().range_end); |
|
|
|
// Find the index in weighted clusters corresponding to key.
|
|
|
|
// Find the index in weighted clusters corresponding to key.
|
|
|
|
size_t mid = 0; |
|
|
|
size_t mid = 0; |
|
|
|
size_t start_index = 0; |
|
|
|
size_t start_index = 0; |
|
|
|
size_t end_index = entry.weighted_cluster_state.size() - 1; |
|
|
|
size_t end_index = entry->weighted_cluster_state.size() - 1; |
|
|
|
size_t index = 0; |
|
|
|
size_t index = 0; |
|
|
|
while (end_index > start_index) { |
|
|
|
while (end_index > start_index) { |
|
|
|
mid = (start_index + end_index) / 2; |
|
|
|
mid = (start_index + end_index) / 2; |
|
|
|
if (entry.weighted_cluster_state[mid].range_end > key) { |
|
|
|
if (entry->weighted_cluster_state[mid].range_end > key) { |
|
|
|
end_index = mid; |
|
|
|
end_index = mid; |
|
|
|
} else if (entry.weighted_cluster_state[mid].range_end < key) { |
|
|
|
} else if (entry->weighted_cluster_state[mid].range_end < key) { |
|
|
|
start_index = mid + 1; |
|
|
|
start_index = mid + 1; |
|
|
|
} else { |
|
|
|
} else { |
|
|
|
index = mid + 1; |
|
|
|
index = mid + 1; |
|
|
@ -796,10 +787,10 @@ absl::Status XdsResolver::XdsConfigSelector::GetCallConfig( |
|
|
|
} |
|
|
|
} |
|
|
|
} |
|
|
|
} |
|
|
|
if (index == 0) index = start_index; |
|
|
|
if (index == 0) index = start_index; |
|
|
|
GPR_ASSERT(entry.weighted_cluster_state[index].range_end > key); |
|
|
|
GPR_ASSERT(entry->weighted_cluster_state[index].range_end > key); |
|
|
|
cluster_name = absl::StrCat( |
|
|
|
cluster_name = absl::StrCat( |
|
|
|
"cluster:", entry.weighted_cluster_state[index].cluster); |
|
|
|
"cluster:", entry->weighted_cluster_state[index].cluster); |
|
|
|
method_config = entry.weighted_cluster_state[index].method_config; |
|
|
|
method_config = entry->weighted_cluster_state[index].method_config; |
|
|
|
}, |
|
|
|
}, |
|
|
|
// ClusterSpecifierPlugin
|
|
|
|
// ClusterSpecifierPlugin
|
|
|
|
[&](const XdsRouteConfigResource::Route::RouteAction:: |
|
|
|
[&](const XdsRouteConfigResource::Route::RouteAction:: |
|
|
@ -807,9 +798,9 @@ absl::Status XdsResolver::XdsConfigSelector::GetCallConfig( |
|
|
|
cluster_name = absl::StrCat( |
|
|
|
cluster_name = absl::StrCat( |
|
|
|
"cluster_specifier_plugin:", |
|
|
|
"cluster_specifier_plugin:", |
|
|
|
cluster_specifier_plugin_name.cluster_specifier_plugin_name); |
|
|
|
cluster_specifier_plugin_name.cluster_specifier_plugin_name); |
|
|
|
method_config = entry.method_config; |
|
|
|
method_config = entry->method_config; |
|
|
|
}); |
|
|
|
}); |
|
|
|
auto cluster = cluster_map_->Find(cluster_name); |
|
|
|
auto cluster = route_config_data_->FindClusterRef(cluster_name); |
|
|
|
GPR_ASSERT(cluster != nullptr); |
|
|
|
GPR_ASSERT(cluster != nullptr); |
|
|
|
// Generate a hash.
|
|
|
|
// Generate a hash.
|
|
|
|
absl::optional<uint64_t> hash; |
|
|
|
absl::optional<uint64_t> hash; |
|
|
@ -857,10 +848,85 @@ absl::Status XdsResolver::XdsConfigSelector::GetCallConfig( |
|
|
|
args.service_config_call_data->SetCallAttribute( |
|
|
|
args.service_config_call_data->SetCallAttribute( |
|
|
|
args.arena->New<RequestHashAttribute>(hash_value)); |
|
|
|
args.arena->New<RequestHashAttribute>(hash_value)); |
|
|
|
args.service_config_call_data->SetCallAttribute( |
|
|
|
args.service_config_call_data->SetCallAttribute( |
|
|
|
args.arena->ManagedNew<XdsClusterMapAttribute>(cluster_map_)); |
|
|
|
args.arena->ManagedNew<XdsRouteStateAttributeImpl>(route_config_data_, |
|
|
|
|
|
|
|
entry)); |
|
|
|
return absl::OkStatus(); |
|
|
|
return absl::OkStatus(); |
|
|
|
} |
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
//
|
|
|
|
|
|
|
|
// XdsResolver::XdsRouteStateAttributeImpl
|
|
|
|
|
|
|
|
//
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
bool XdsResolver::XdsRouteStateAttributeImpl::HasClusterForRoute( |
|
|
|
|
|
|
|
absl::string_view cluster_name) const { |
|
|
|
|
|
|
|
// Found a route match
|
|
|
|
|
|
|
|
const auto* route_action = |
|
|
|
|
|
|
|
absl::get_if<XdsRouteConfigResource::Route::RouteAction>( |
|
|
|
|
|
|
|
&static_cast<RouteConfigData::RouteEntry*>(route_)->route.action); |
|
|
|
|
|
|
|
if (route_action == nullptr) return false; |
|
|
|
|
|
|
|
return Match( |
|
|
|
|
|
|
|
route_action->action, |
|
|
|
|
|
|
|
[&](const XdsRouteConfigResource::Route::RouteAction::ClusterName& name) { |
|
|
|
|
|
|
|
return name.cluster_name == cluster_name; |
|
|
|
|
|
|
|
}, |
|
|
|
|
|
|
|
[&](const std::vector< |
|
|
|
|
|
|
|
XdsRouteConfigResource::Route::RouteAction::ClusterWeight>& |
|
|
|
|
|
|
|
clusters) { |
|
|
|
|
|
|
|
for (const auto& cluster : clusters) { |
|
|
|
|
|
|
|
if (cluster.name == cluster_name) { |
|
|
|
|
|
|
|
return true; |
|
|
|
|
|
|
|
} |
|
|
|
|
|
|
|
} |
|
|
|
|
|
|
|
return false; |
|
|
|
|
|
|
|
}, |
|
|
|
|
|
|
|
[&](const XdsRouteConfigResource::Route::RouteAction:: |
|
|
|
|
|
|
|
ClusterSpecifierPluginName& /* name */) { return false; }); |
|
|
|
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
RefCountedPtr<XdsResolver::ClusterRef> |
|
|
|
|
|
|
|
XdsResolver::XdsRouteStateAttributeImpl::LockAndGetCluster( |
|
|
|
|
|
|
|
absl::string_view cluster_name) { |
|
|
|
|
|
|
|
if (route_config_data_ == nullptr) { |
|
|
|
|
|
|
|
return nullptr; |
|
|
|
|
|
|
|
} |
|
|
|
|
|
|
|
auto cluster = route_config_data_->FindClusterRef(cluster_name); |
|
|
|
|
|
|
|
route_config_data_.reset(); |
|
|
|
|
|
|
|
return cluster; |
|
|
|
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
//
|
|
|
|
|
|
|
|
// XdsResolver::ClusterSelectionFilter
|
|
|
|
|
|
|
|
//
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
const grpc_channel_filter XdsResolver::ClusterSelectionFilter::kFilter = |
|
|
|
|
|
|
|
MakePromiseBasedFilter<ClusterSelectionFilter, FilterEndpoint::kClient, |
|
|
|
|
|
|
|
kFilterExaminesServerInitialMetadata>( |
|
|
|
|
|
|
|
"cluster_selection_filter"); |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
ArenaPromise<ServerMetadataHandle> |
|
|
|
|
|
|
|
XdsResolver::ClusterSelectionFilter::MakeCallPromise( |
|
|
|
|
|
|
|
CallArgs call_args, NextPromiseFactory next_promise_factory) { |
|
|
|
|
|
|
|
auto* service_config_call_data = |
|
|
|
|
|
|
|
static_cast<ClientChannelServiceConfigCallData*>( |
|
|
|
|
|
|
|
GetContext<grpc_call_context_element>() |
|
|
|
|
|
|
|
[GRPC_CONTEXT_SERVICE_CONFIG_CALL_DATA] |
|
|
|
|
|
|
|
.value); |
|
|
|
|
|
|
|
GPR_ASSERT(service_config_call_data != nullptr); |
|
|
|
|
|
|
|
auto* route_state_attribute = static_cast<XdsRouteStateAttributeImpl*>( |
|
|
|
|
|
|
|
service_config_call_data->GetCallAttribute<XdsRouteStateAttribute>()); |
|
|
|
|
|
|
|
auto* cluster_name_attribute = |
|
|
|
|
|
|
|
service_config_call_data->GetCallAttribute<XdsClusterAttribute>(); |
|
|
|
|
|
|
|
if (route_state_attribute != nullptr && cluster_name_attribute != nullptr) { |
|
|
|
|
|
|
|
auto cluster = route_state_attribute->LockAndGetCluster( |
|
|
|
|
|
|
|
cluster_name_attribute->cluster()); |
|
|
|
|
|
|
|
if (cluster != nullptr) { |
|
|
|
|
|
|
|
service_config_call_data->SetOnCommit( |
|
|
|
|
|
|
|
[cluster = std::move(cluster)]() mutable { cluster.reset(); }); |
|
|
|
|
|
|
|
} |
|
|
|
|
|
|
|
} |
|
|
|
|
|
|
|
return next_promise_factory(std::move(call_args)); |
|
|
|
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
//
|
|
|
|
//
|
|
|
|
// XdsResolver
|
|
|
|
// XdsResolver
|
|
|
|
//
|
|
|
|
//
|
|
|
@ -1016,7 +1082,6 @@ void XdsResolver::OnListenerUpdate(XdsListenerResource listener) { |
|
|
|
}); |
|
|
|
}); |
|
|
|
} |
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
namespace { |
|
|
|
|
|
|
|
class VirtualHostListIterator : public XdsRouting::VirtualHostListIterator { |
|
|
|
class VirtualHostListIterator : public XdsRouting::VirtualHostListIterator { |
|
|
|
public: |
|
|
|
public: |
|
|
|
explicit VirtualHostListIterator( |
|
|
|
explicit VirtualHostListIterator( |
|
|
@ -1033,7 +1098,6 @@ class VirtualHostListIterator : public XdsRouting::VirtualHostListIterator { |
|
|
|
private: |
|
|
|
private: |
|
|
|
const std::vector<XdsRouteConfigResource::VirtualHost>* virtual_hosts_; |
|
|
|
const std::vector<XdsRouteConfigResource::VirtualHost>* virtual_hosts_; |
|
|
|
}; |
|
|
|
}; |
|
|
|
} // namespace
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
void XdsResolver::OnRouteConfigUpdate(XdsRouteConfigResource rds_update) { |
|
|
|
void XdsResolver::OnRouteConfigUpdate(XdsRouteConfigResource rds_update) { |
|
|
|
if (GRPC_TRACE_FLAG_ENABLED(grpc_xds_resolver_trace)) { |
|
|
|
if (GRPC_TRACE_FLAG_ENABLED(grpc_xds_resolver_trace)) { |
|
|
@ -1100,7 +1164,7 @@ void XdsResolver::OnResourceDoesNotExist(std::string context) { |
|
|
|
absl::StatusOr<RefCountedPtr<ServiceConfig>> |
|
|
|
absl::StatusOr<RefCountedPtr<ServiceConfig>> |
|
|
|
XdsResolver::CreateServiceConfig() { |
|
|
|
XdsResolver::CreateServiceConfig() { |
|
|
|
std::vector<std::string> clusters; |
|
|
|
std::vector<std::string> clusters; |
|
|
|
for (const auto& cluster : cluster_state_map_) { |
|
|
|
for (const auto& cluster : cluster_ref_map_) { |
|
|
|
absl::string_view child_name = cluster.first; |
|
|
|
absl::string_view child_name = cluster.first; |
|
|
|
if (absl::ConsumePrefix(&child_name, "cluster_specifier_plugin:")) { |
|
|
|
if (absl::ConsumePrefix(&child_name, "cluster_specifier_plugin:")) { |
|
|
|
clusters.push_back(absl::StrFormat( |
|
|
|
clusters.push_back(absl::StrFormat( |
|
|
@ -1142,13 +1206,16 @@ void XdsResolver::GenerateResult() { |
|
|
|
if (!current_virtual_host_.has_value()) return; |
|
|
|
if (!current_virtual_host_.has_value()) return; |
|
|
|
// First create XdsConfigSelector, which may add new entries to the cluster
|
|
|
|
// First create XdsConfigSelector, which may add new entries to the cluster
|
|
|
|
// state map, and then CreateServiceConfig for LB policies.
|
|
|
|
// state map, and then CreateServiceConfig for LB policies.
|
|
|
|
absl::Status status; |
|
|
|
auto route_config_data = |
|
|
|
auto config_selector = MakeRefCounted<XdsConfigSelector>(Ref(), &status); |
|
|
|
RouteConfigData::Create(this, current_virtual_host_->routes, |
|
|
|
if (!status.ok()) { |
|
|
|
current_listener_.http_max_stream_duration); |
|
|
|
|
|
|
|
if (!route_config_data.ok()) { |
|
|
|
OnError("could not create ConfigSelector", |
|
|
|
OnError("could not create ConfigSelector", |
|
|
|
absl::UnavailableError(status.message())); |
|
|
|
absl::UnavailableError(route_config_data.status().message())); |
|
|
|
return; |
|
|
|
return; |
|
|
|
} |
|
|
|
} |
|
|
|
|
|
|
|
auto config_selector = |
|
|
|
|
|
|
|
MakeRefCounted<XdsConfigSelector>(Ref(), std::move(*route_config_data)); |
|
|
|
Result result; |
|
|
|
Result result; |
|
|
|
result.addresses.emplace(); |
|
|
|
result.addresses.emplace(); |
|
|
|
result.service_config = CreateServiceConfig(); |
|
|
|
result.service_config = CreateServiceConfig(); |
|
|
@ -1169,13 +1236,13 @@ void XdsResolver::GenerateResult() { |
|
|
|
|
|
|
|
|
|
|
|
void XdsResolver::MaybeRemoveUnusedClusters() { |
|
|
|
void XdsResolver::MaybeRemoveUnusedClusters() { |
|
|
|
bool update_needed = false; |
|
|
|
bool update_needed = false; |
|
|
|
for (auto it = cluster_state_map_.begin(); it != cluster_state_map_.end();) { |
|
|
|
for (auto it = cluster_ref_map_.begin(); it != cluster_ref_map_.end();) { |
|
|
|
RefCountedPtr<ClusterState> cluster_state = it->second->RefIfNonZero(); |
|
|
|
RefCountedPtr<ClusterRef> cluster_state = it->second->RefIfNonZero(); |
|
|
|
if (cluster_state != nullptr) { |
|
|
|
if (cluster_state != nullptr) { |
|
|
|
++it; |
|
|
|
++it; |
|
|
|
} else { |
|
|
|
} else { |
|
|
|
update_needed = true; |
|
|
|
update_needed = true; |
|
|
|
it = cluster_state_map_.erase(it); |
|
|
|
it = cluster_ref_map_.erase(it); |
|
|
|
} |
|
|
|
} |
|
|
|
} |
|
|
|
} |
|
|
|
if (update_needed && xds_client_ != nullptr) { |
|
|
|
if (update_needed && xds_client_ != nullptr) { |
|
|
@ -1185,7 +1252,7 @@ void XdsResolver::MaybeRemoveUnusedClusters() { |
|
|
|
} |
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
//
|
|
|
|
//
|
|
|
|
// Factory
|
|
|
|
// XdsResolverFactory
|
|
|
|
//
|
|
|
|
//
|
|
|
|
|
|
|
|
|
|
|
|
class XdsResolverFactory : public ResolverFactory { |
|
|
|
class XdsResolverFactory : public ResolverFactory { |
|
|
@ -1210,7 +1277,6 @@ class XdsResolverFactory : public ResolverFactory { |
|
|
|
return MakeOrphanable<XdsResolver>(std::move(args)); |
|
|
|
return MakeOrphanable<XdsResolver>(std::move(args)); |
|
|
|
} |
|
|
|
} |
|
|
|
}; |
|
|
|
}; |
|
|
|
|
|
|
|
|
|
|
|
} // namespace
|
|
|
|
} // namespace
|
|
|
|
|
|
|
|
|
|
|
|
void RegisterXdsResolver(CoreConfiguration::Builder* builder) { |
|
|
|
void RegisterXdsResolver(CoreConfiguration::Builder* builder) { |
|
|
|