|
|
|
@ -128,7 +128,8 @@ class XdsClient::ChannelState::AdsCallState |
|
|
|
|
bool seen_response() const { return seen_response_; } |
|
|
|
|
|
|
|
|
|
void Subscribe(const std::string& type_url, const std::string& name); |
|
|
|
|
void Unsubscribe(const std::string& type_url, const std::string& name); |
|
|
|
|
void Unsubscribe(const std::string& type_url, const std::string& name, |
|
|
|
|
bool delay_unsubscription); |
|
|
|
|
|
|
|
|
|
bool HasSubscribedResources() const; |
|
|
|
|
|
|
|
|
@ -240,8 +241,8 @@ class XdsClient::ChannelState::AdsCallState |
|
|
|
|
|
|
|
|
|
void SendMessageLocked(const std::string& type_url); |
|
|
|
|
|
|
|
|
|
void AcceptLdsUpdate(XdsApi::LdsUpdate lds_update); |
|
|
|
|
void AcceptRdsUpdate(XdsApi::RdsUpdate rds_update); |
|
|
|
|
void AcceptLdsUpdate(absl::optional<XdsApi::LdsUpdate> lds_update); |
|
|
|
|
void AcceptRdsUpdate(absl::optional<XdsApi::RdsUpdate> rds_update); |
|
|
|
|
void AcceptCdsUpdate(XdsApi::CdsUpdateMap cds_update_map); |
|
|
|
|
void AcceptEdsUpdate(XdsApi::EdsUpdateMap eds_update_map); |
|
|
|
|
|
|
|
|
@ -557,9 +558,10 @@ void XdsClient::ChannelState::Subscribe(const std::string& type_url, |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
void XdsClient::ChannelState::Unsubscribe(const std::string& type_url, |
|
|
|
|
const std::string& name) { |
|
|
|
|
const std::string& name, |
|
|
|
|
bool delay_unsubscription) { |
|
|
|
|
if (ads_calld_ != nullptr) { |
|
|
|
|
ads_calld_->calld()->Unsubscribe(type_url, name); |
|
|
|
|
ads_calld_->calld()->Unsubscribe(type_url, name, delay_unsubscription); |
|
|
|
|
if (!ads_calld_->calld()->HasSubscribedResources()) ads_calld_.reset(); |
|
|
|
|
} |
|
|
|
|
} |
|
|
|
@ -862,9 +864,10 @@ void XdsClient::ChannelState::AdsCallState::Subscribe( |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
void XdsClient::ChannelState::AdsCallState::Unsubscribe( |
|
|
|
|
const std::string& type_url, const std::string& name) { |
|
|
|
|
const std::string& type_url, const std::string& name, |
|
|
|
|
bool delay_unsubscription) { |
|
|
|
|
state_map_[type_url].subscribed_resources.erase(name); |
|
|
|
|
SendMessageLocked(type_url); |
|
|
|
|
if (!delay_unsubscription) SendMessageLocked(type_url); |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
bool XdsClient::ChannelState::AdsCallState::HasSubscribedResources() const { |
|
|
|
@ -875,24 +878,32 @@ bool XdsClient::ChannelState::AdsCallState::HasSubscribedResources() const { |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
void XdsClient::ChannelState::AdsCallState::AcceptLdsUpdate( |
|
|
|
|
XdsApi::LdsUpdate lds_update) { |
|
|
|
|
absl::optional<XdsApi::LdsUpdate> lds_update) { |
|
|
|
|
if (!lds_update.has_value()) { |
|
|
|
|
gpr_log(GPR_INFO, |
|
|
|
|
"[xds_client %p] LDS update does not include requested resource", |
|
|
|
|
xds_client()); |
|
|
|
|
xds_client()->service_config_watcher_->OnError( |
|
|
|
|
GRPC_ERROR_CREATE_FROM_STATIC_STRING( |
|
|
|
|
"LDS update does not include requested resource")); |
|
|
|
|
return; |
|
|
|
|
} |
|
|
|
|
const std::string& cluster_name = |
|
|
|
|
lds_update.rds_update.has_value() |
|
|
|
|
? lds_update.rds_update.value().cluster_name |
|
|
|
|
lds_update->rds_update.has_value() |
|
|
|
|
? lds_update->rds_update.value().cluster_name |
|
|
|
|
: ""; |
|
|
|
|
if (GRPC_TRACE_FLAG_ENABLED(grpc_xds_client_trace)) { |
|
|
|
|
gpr_log(GPR_INFO, |
|
|
|
|
"[xds_client %p] LDS update received: " |
|
|
|
|
"route_config_name=%s, " |
|
|
|
|
"[xds_client %p] LDS update received: route_config_name=%s, " |
|
|
|
|
"cluster_name=%s (empty if RDS is needed to obtain it)", |
|
|
|
|
xds_client(), lds_update.route_config_name.c_str(), |
|
|
|
|
xds_client(), lds_update->route_config_name.c_str(), |
|
|
|
|
cluster_name.c_str()); |
|
|
|
|
} |
|
|
|
|
auto& lds_state = state_map_[XdsApi::kLdsTypeUrl]; |
|
|
|
|
auto& state = lds_state.subscribed_resources[xds_client()->server_name_]; |
|
|
|
|
if (state != nullptr) state->Finish(); |
|
|
|
|
// Ignore identical update.
|
|
|
|
|
if (xds_client()->route_config_name_ == lds_update.route_config_name && |
|
|
|
|
if (xds_client()->route_config_name_ == lds_update->route_config_name && |
|
|
|
|
xds_client()->cluster_name_ == cluster_name) { |
|
|
|
|
if (GRPC_TRACE_FLAG_ENABLED(grpc_xds_client_trace)) { |
|
|
|
|
gpr_log(GPR_INFO, |
|
|
|
@ -901,12 +912,17 @@ void XdsClient::ChannelState::AdsCallState::AcceptLdsUpdate( |
|
|
|
|
} |
|
|
|
|
return; |
|
|
|
|
} |
|
|
|
|
xds_client()->route_config_name_ = std::move(lds_update.route_config_name); |
|
|
|
|
if (lds_update.rds_update.has_value()) { |
|
|
|
|
if (!xds_client()->route_config_name_.empty()) { |
|
|
|
|
Unsubscribe( |
|
|
|
|
XdsApi::kRdsTypeUrl, xds_client()->route_config_name_, |
|
|
|
|
/*delay_unsubscription=*/!lds_update->route_config_name.empty()); |
|
|
|
|
} |
|
|
|
|
xds_client()->route_config_name_ = std::move(lds_update->route_config_name); |
|
|
|
|
if (lds_update->rds_update.has_value()) { |
|
|
|
|
// If cluster_name was found inlined in LDS response, notify the watcher
|
|
|
|
|
// immediately.
|
|
|
|
|
xds_client()->cluster_name_ = |
|
|
|
|
std::move(lds_update.rds_update.value().cluster_name); |
|
|
|
|
std::move(lds_update->rds_update.value().cluster_name); |
|
|
|
|
RefCountedPtr<ServiceConfig> service_config; |
|
|
|
|
grpc_error* error = xds_client()->CreateServiceConfig( |
|
|
|
|
xds_client()->cluster_name_, &service_config); |
|
|
|
@ -923,19 +939,26 @@ void XdsClient::ChannelState::AdsCallState::AcceptLdsUpdate( |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
void XdsClient::ChannelState::AdsCallState::AcceptRdsUpdate( |
|
|
|
|
XdsApi::RdsUpdate rds_update) { |
|
|
|
|
if (GRPC_TRACE_FLAG_ENABLED(grpc_xds_client_trace)) { |
|
|
|
|
absl::optional<XdsApi::RdsUpdate> rds_update) { |
|
|
|
|
if (!rds_update.has_value()) { |
|
|
|
|
gpr_log(GPR_INFO, |
|
|
|
|
"[xds_client %p] RDS update received: " |
|
|
|
|
"cluster_name=%s", |
|
|
|
|
xds_client(), rds_update.cluster_name.c_str()); |
|
|
|
|
"[xds_client %p] RDS update does not include requested resource", |
|
|
|
|
xds_client()); |
|
|
|
|
xds_client()->service_config_watcher_->OnError( |
|
|
|
|
GRPC_ERROR_CREATE_FROM_STATIC_STRING( |
|
|
|
|
"RDS update does not include requested resource")); |
|
|
|
|
return; |
|
|
|
|
} |
|
|
|
|
if (GRPC_TRACE_FLAG_ENABLED(grpc_xds_client_trace)) { |
|
|
|
|
gpr_log(GPR_INFO, "[xds_client %p] RDS update received: cluster_name=%s", |
|
|
|
|
xds_client(), rds_update->cluster_name.c_str()); |
|
|
|
|
} |
|
|
|
|
auto& rds_state = state_map_[XdsApi::kRdsTypeUrl]; |
|
|
|
|
auto& state = |
|
|
|
|
rds_state.subscribed_resources[xds_client()->route_config_name_]; |
|
|
|
|
if (state != nullptr) state->Finish(); |
|
|
|
|
// Ignore identical update.
|
|
|
|
|
if (xds_client()->cluster_name_ == rds_update.cluster_name) { |
|
|
|
|
if (xds_client()->cluster_name_ == rds_update->cluster_name) { |
|
|
|
|
if (GRPC_TRACE_FLAG_ENABLED(grpc_xds_client_trace)) { |
|
|
|
|
gpr_log(GPR_INFO, |
|
|
|
|
"[xds_client %p] RDS update identical to current, ignoring.", |
|
|
|
@ -943,7 +966,7 @@ void XdsClient::ChannelState::AdsCallState::AcceptRdsUpdate( |
|
|
|
|
} |
|
|
|
|
return; |
|
|
|
|
} |
|
|
|
|
xds_client()->cluster_name_ = std::move(rds_update.cluster_name); |
|
|
|
|
xds_client()->cluster_name_ = std::move(rds_update->cluster_name); |
|
|
|
|
// Notify the watcher.
|
|
|
|
|
RefCountedPtr<ServiceConfig> service_config; |
|
|
|
|
grpc_error* error = xds_client()->CreateServiceConfig( |
|
|
|
@ -959,6 +982,7 @@ void XdsClient::ChannelState::AdsCallState::AcceptRdsUpdate( |
|
|
|
|
void XdsClient::ChannelState::AdsCallState::AcceptCdsUpdate( |
|
|
|
|
XdsApi::CdsUpdateMap cds_update_map) { |
|
|
|
|
auto& cds_state = state_map_[XdsApi::kCdsTypeUrl]; |
|
|
|
|
std::set<std::string> eds_resource_names_seen; |
|
|
|
|
for (auto& p : cds_update_map) { |
|
|
|
|
const char* cluster_name = p.first.c_str(); |
|
|
|
|
XdsApi::CdsUpdate& cds_update = p.second; |
|
|
|
@ -967,21 +991,22 @@ void XdsClient::ChannelState::AdsCallState::AcceptCdsUpdate( |
|
|
|
|
if (GRPC_TRACE_FLAG_ENABLED(grpc_xds_client_trace)) { |
|
|
|
|
gpr_log(GPR_INFO, |
|
|
|
|
"[xds_client %p] CDS update (cluster=%s) received: " |
|
|
|
|
"eds_service_name=%s, " |
|
|
|
|
"lrs_load_reporting_server_name=%s", |
|
|
|
|
"eds_service_name=%s, lrs_load_reporting_server_name=%s", |
|
|
|
|
xds_client(), cluster_name, cds_update.eds_service_name.c_str(), |
|
|
|
|
cds_update.lrs_load_reporting_server_name.has_value() |
|
|
|
|
? cds_update.lrs_load_reporting_server_name.value().c_str() |
|
|
|
|
: "(N/A)"); |
|
|
|
|
} |
|
|
|
|
ClusterState& cluster_state = xds_client()->cluster_map_[cluster_name]; |
|
|
|
|
// Record the EDS resource names seen.
|
|
|
|
|
eds_resource_names_seen.insert(cds_update.eds_service_name.empty() |
|
|
|
|
? cluster_name |
|
|
|
|
: cds_update.eds_service_name); |
|
|
|
|
// Ignore identical update.
|
|
|
|
|
ClusterState& cluster_state = xds_client()->cluster_map_[cluster_name]; |
|
|
|
|
if (cluster_state.update.has_value() && |
|
|
|
|
cds_update.eds_service_name == |
|
|
|
|
cluster_state.update.value().eds_service_name && |
|
|
|
|
cds_update.lrs_load_reporting_server_name.value() == |
|
|
|
|
cluster_state.update.value() |
|
|
|
|
.lrs_load_reporting_server_name.value()) { |
|
|
|
|
cds_update.eds_service_name == cluster_state.update->eds_service_name && |
|
|
|
|
cds_update.lrs_load_reporting_server_name == |
|
|
|
|
cluster_state.update->lrs_load_reporting_server_name) { |
|
|
|
|
if (GRPC_TRACE_FLAG_ENABLED(grpc_xds_client_trace)) { |
|
|
|
|
gpr_log(GPR_INFO, |
|
|
|
|
"[xds_client %p] CDS update identical to current, ignoring.", |
|
|
|
@ -990,12 +1015,41 @@ void XdsClient::ChannelState::AdsCallState::AcceptCdsUpdate( |
|
|
|
|
continue; |
|
|
|
|
} |
|
|
|
|
// Update the cluster state.
|
|
|
|
|
cluster_state.update.emplace(std::move(cds_update)); |
|
|
|
|
cluster_state.update = std::move(cds_update); |
|
|
|
|
// Notify all watchers.
|
|
|
|
|
for (const auto& p : cluster_state.watchers) { |
|
|
|
|
p.first->OnClusterChanged(cluster_state.update.value()); |
|
|
|
|
} |
|
|
|
|
} |
|
|
|
|
// For any subscribed resource that is not present in the update,
|
|
|
|
|
// remove it from the cache and notify watchers of the error.
|
|
|
|
|
for (const auto& p : cds_state.subscribed_resources) { |
|
|
|
|
const std::string& cluster_name = p.first; |
|
|
|
|
if (cds_update_map.find(cluster_name) == cds_update_map.end()) { |
|
|
|
|
ClusterState& cluster_state = xds_client()->cluster_map_[cluster_name]; |
|
|
|
|
cluster_state.update.reset(); |
|
|
|
|
for (const auto& p : cluster_state.watchers) { |
|
|
|
|
p.first->OnError(GRPC_ERROR_CREATE_FROM_STATIC_STRING( |
|
|
|
|
"Cluster not present in CDS update")); |
|
|
|
|
} |
|
|
|
|
} |
|
|
|
|
} |
|
|
|
|
// Also remove any EDS resources that are no longer referred to by any CDS
|
|
|
|
|
// resources.
|
|
|
|
|
auto& eds_state = state_map_[XdsApi::kEdsTypeUrl]; |
|
|
|
|
for (const auto& p : eds_state.subscribed_resources) { |
|
|
|
|
const std::string& eds_resource_name = p.first; |
|
|
|
|
if (eds_resource_names_seen.find(eds_resource_name) == |
|
|
|
|
eds_resource_names_seen.end()) { |
|
|
|
|
EndpointState& endpoint_state = |
|
|
|
|
xds_client()->endpoint_map_[eds_resource_name]; |
|
|
|
|
endpoint_state.update.reset(); |
|
|
|
|
for (const auto& p : endpoint_state.watchers) { |
|
|
|
|
p.first->OnError(GRPC_ERROR_CREATE_FROM_STATIC_STRING( |
|
|
|
|
"ClusterLoadAssignment resource removed due to CDS update")); |
|
|
|
|
} |
|
|
|
|
} |
|
|
|
|
} |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
void XdsClient::ChannelState::AdsCallState::AcceptEdsUpdate( |
|
|
|
@ -1058,25 +1112,27 @@ void XdsClient::ChannelState::AdsCallState::AcceptEdsUpdate( |
|
|
|
|
EndpointState& endpoint_state = |
|
|
|
|
xds_client()->endpoint_map_[eds_service_name]; |
|
|
|
|
// Ignore identical update.
|
|
|
|
|
const XdsApi::EdsUpdate& prev_update = endpoint_state.update; |
|
|
|
|
const bool priority_list_changed = |
|
|
|
|
prev_update.priority_list_update != eds_update.priority_list_update; |
|
|
|
|
const bool drop_config_changed = |
|
|
|
|
prev_update.drop_config == nullptr || |
|
|
|
|
*prev_update.drop_config != *eds_update.drop_config; |
|
|
|
|
if (!priority_list_changed && !drop_config_changed) { |
|
|
|
|
if (GRPC_TRACE_FLAG_ENABLED(grpc_xds_client_trace)) { |
|
|
|
|
gpr_log(GPR_INFO, |
|
|
|
|
"[xds_client %p] EDS update identical to current, ignoring.", |
|
|
|
|
xds_client()); |
|
|
|
|
if (endpoint_state.update.has_value()) { |
|
|
|
|
const XdsApi::EdsUpdate& prev_update = endpoint_state.update.value(); |
|
|
|
|
const bool priority_list_changed = |
|
|
|
|
prev_update.priority_list_update != eds_update.priority_list_update; |
|
|
|
|
const bool drop_config_changed = |
|
|
|
|
prev_update.drop_config == nullptr || |
|
|
|
|
*prev_update.drop_config != *eds_update.drop_config; |
|
|
|
|
if (!priority_list_changed && !drop_config_changed) { |
|
|
|
|
if (GRPC_TRACE_FLAG_ENABLED(grpc_xds_client_trace)) { |
|
|
|
|
gpr_log(GPR_INFO, |
|
|
|
|
"[xds_client %p] EDS update identical to current, ignoring.", |
|
|
|
|
xds_client()); |
|
|
|
|
} |
|
|
|
|
continue; |
|
|
|
|
} |
|
|
|
|
continue; |
|
|
|
|
} |
|
|
|
|
// Update the cluster state.
|
|
|
|
|
endpoint_state.update = std::move(eds_update); |
|
|
|
|
// Notify all watchers.
|
|
|
|
|
for (const auto& p : endpoint_state.watchers) { |
|
|
|
|
p.first->OnEndpointChanged(endpoint_state.update); |
|
|
|
|
p.first->OnEndpointChanged(endpoint_state.update.value()); |
|
|
|
|
} |
|
|
|
|
} |
|
|
|
|
} |
|
|
|
@ -1150,8 +1206,8 @@ void XdsClient::ChannelState::AdsCallState::OnResponseReceivedLocked( |
|
|
|
|
// mode. We will also need to cancel the timer when we receive a serverlist
|
|
|
|
|
// from the balancer.
|
|
|
|
|
// Parse the response.
|
|
|
|
|
XdsApi::LdsUpdate lds_update; |
|
|
|
|
XdsApi::RdsUpdate rds_update; |
|
|
|
|
absl::optional<XdsApi::LdsUpdate> lds_update; |
|
|
|
|
absl::optional<XdsApi::RdsUpdate> rds_update; |
|
|
|
|
XdsApi::CdsUpdateMap cds_update_map; |
|
|
|
|
XdsApi::EdsUpdateMap eds_update_map; |
|
|
|
|
std::string version; |
|
|
|
@ -1160,6 +1216,7 @@ void XdsClient::ChannelState::AdsCallState::OnResponseReceivedLocked( |
|
|
|
|
// Note that ParseAdsResponse() also validates the response.
|
|
|
|
|
grpc_error* parse_error = xds_client->api_.ParseAdsResponse( |
|
|
|
|
response_slice, xds_client->server_name_, xds_client->route_config_name_, |
|
|
|
|
ads_calld->ClusterNamesForRequest(), |
|
|
|
|
ads_calld->EdsServiceNamesForRequest(), &lds_update, &rds_update, |
|
|
|
|
&cds_update_map, &eds_update_map, &version, &nonce, &type_url); |
|
|
|
|
grpc_slice_unref_internal(response_slice); |
|
|
|
@ -1822,7 +1879,8 @@ void XdsClient::WatchClusterData( |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
void XdsClient::CancelClusterDataWatch(StringView cluster_name, |
|
|
|
|
ClusterWatcherInterface* watcher) { |
|
|
|
|
ClusterWatcherInterface* watcher, |
|
|
|
|
bool delay_unsubscription) { |
|
|
|
|
if (shutting_down_) return; |
|
|
|
|
std::string cluster_name_str = std::string(cluster_name); |
|
|
|
|
ClusterState& cluster_state = cluster_map_[cluster_name_str]; |
|
|
|
@ -1831,7 +1889,8 @@ void XdsClient::CancelClusterDataWatch(StringView cluster_name, |
|
|
|
|
cluster_state.watchers.erase(it); |
|
|
|
|
if (cluster_state.watchers.empty()) { |
|
|
|
|
cluster_map_.erase(cluster_name_str); |
|
|
|
|
chand_->Unsubscribe(XdsApi::kCdsTypeUrl, cluster_name_str); |
|
|
|
|
chand_->Unsubscribe(XdsApi::kCdsTypeUrl, cluster_name_str, |
|
|
|
|
delay_unsubscription); |
|
|
|
|
} |
|
|
|
|
} |
|
|
|
|
} |
|
|
|
@ -1845,18 +1904,19 @@ void XdsClient::WatchEndpointData( |
|
|
|
|
endpoint_state.watchers[w] = std::move(watcher); |
|
|
|
|
// If we've already received an EDS update, notify the new watcher
|
|
|
|
|
// immediately.
|
|
|
|
|
if (!endpoint_state.update.priority_list_update.empty()) { |
|
|
|
|
if (endpoint_state.update.has_value()) { |
|
|
|
|
if (GRPC_TRACE_FLAG_ENABLED(grpc_xds_client_trace)) { |
|
|
|
|
gpr_log(GPR_INFO, "[xds_client %p] returning cached endpoint data for %s", |
|
|
|
|
this, StringViewToCString(eds_service_name).get()); |
|
|
|
|
} |
|
|
|
|
w->OnEndpointChanged(endpoint_state.update); |
|
|
|
|
w->OnEndpointChanged(endpoint_state.update.value()); |
|
|
|
|
} |
|
|
|
|
chand_->Subscribe(XdsApi::kEdsTypeUrl, eds_service_name_str); |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
void XdsClient::CancelEndpointDataWatch(StringView eds_service_name, |
|
|
|
|
EndpointWatcherInterface* watcher) { |
|
|
|
|
EndpointWatcherInterface* watcher, |
|
|
|
|
bool delay_unsubscription) { |
|
|
|
|
if (shutting_down_) return; |
|
|
|
|
std::string eds_service_name_str = std::string(eds_service_name); |
|
|
|
|
EndpointState& endpoint_state = endpoint_map_[eds_service_name_str]; |
|
|
|
@ -1865,7 +1925,8 @@ void XdsClient::CancelEndpointDataWatch(StringView eds_service_name, |
|
|
|
|
endpoint_state.watchers.erase(it); |
|
|
|
|
if (endpoint_state.watchers.empty()) { |
|
|
|
|
endpoint_map_.erase(eds_service_name_str); |
|
|
|
|
chand_->Unsubscribe(XdsApi::kEdsTypeUrl, eds_service_name_str); |
|
|
|
|
chand_->Unsubscribe(XdsApi::kEdsTypeUrl, eds_service_name_str, |
|
|
|
|
delay_unsubscription); |
|
|
|
|
} |
|
|
|
|
} |
|
|
|
|
} |
|
|
|
|