grpc 1.28.0.pre2 → 1.28.0
Sign up to get free protection for your applications and to get access to all the features.
Potentially problematic release.
This version of grpc might be problematic. Click here for more details.
- checksums.yaml +4 -4
- data/Makefile +8 -2
- data/src/core/ext/filters/client_channel/client_channel.cc +27 -3
- data/src/core/ext/filters/client_channel/lb_policy/child_policy_handler.cc +291 -0
- data/src/core/ext/filters/client_channel/lb_policy/child_policy_handler.h +83 -0
- data/src/core/ext/filters/client_channel/lb_policy/grpclb/grpclb.cc +37 -178
- data/src/core/ext/filters/client_channel/lb_policy/xds/cds.cc +38 -9
- data/src/core/ext/filters/client_channel/lb_policy/xds/xds.cc +242 -396
- data/src/core/ext/filters/client_channel/resolver/xds/xds_resolver.cc +27 -5
- data/src/core/ext/filters/client_channel/resolving_lb_policy.cc +27 -165
- data/src/core/ext/filters/client_channel/resolving_lb_policy.h +2 -4
- data/src/core/ext/filters/client_channel/xds/xds_api.cc +679 -56
- data/src/core/ext/filters/client_channel/xds/xds_api.h +30 -9
- data/src/core/ext/filters/client_channel/xds/xds_bootstrap.cc +82 -5
- data/src/core/ext/filters/client_channel/xds/xds_bootstrap.h +5 -1
- data/src/core/ext/filters/client_channel/xds/xds_client.cc +273 -137
- data/src/core/ext/filters/client_channel/xds/xds_client.h +28 -12
- data/src/core/lib/gprpp/sync.h +9 -0
- data/src/ruby/lib/grpc/version.rb +1 -1
- metadata +32 -30
@@ -25,15 +25,18 @@
|
|
25
25
|
|
26
26
|
#include <set>
|
27
27
|
|
28
|
+
#include "absl/types/optional.h"
|
29
|
+
|
28
30
|
#include <grpc/slice_buffer.h>
|
29
31
|
|
30
32
|
#include "src/core/ext/filters/client_channel/server_address.h"
|
31
33
|
#include "src/core/ext/filters/client_channel/xds/xds_bootstrap.h"
|
32
34
|
#include "src/core/ext/filters/client_channel/xds/xds_client_stats.h"
|
33
|
-
#include "src/core/lib/gprpp/optional.h"
|
34
35
|
|
35
36
|
namespace grpc_core {
|
36
37
|
|
38
|
+
class XdsClient;
|
39
|
+
|
37
40
|
class XdsApi {
|
38
41
|
public:
|
39
42
|
static const char* kLdsTypeUrl;
|
@@ -44,14 +47,25 @@ class XdsApi {
|
|
44
47
|
struct RdsUpdate {
|
45
48
|
// The name to use in the CDS request.
|
46
49
|
std::string cluster_name;
|
50
|
+
|
51
|
+
bool operator==(const RdsUpdate& other) const {
|
52
|
+
return cluster_name == other.cluster_name;
|
53
|
+
}
|
47
54
|
};
|
48
55
|
|
56
|
+
// TODO(roth): When we can use absl::variant<>, consider using that
|
57
|
+
// here, to enforce the fact that only one of the two fields can be set.
|
49
58
|
struct LdsUpdate {
|
50
59
|
// The name to use in the RDS request.
|
51
60
|
std::string route_config_name;
|
52
61
|
// The name to use in the CDS request. Present if the LDS response has it
|
53
62
|
// inlined.
|
54
|
-
|
63
|
+
absl::optional<RdsUpdate> rds_update;
|
64
|
+
|
65
|
+
bool operator==(const LdsUpdate& other) const {
|
66
|
+
return route_config_name == other.route_config_name &&
|
67
|
+
rds_update == other.rds_update;
|
68
|
+
}
|
55
69
|
};
|
56
70
|
|
57
71
|
using LdsUpdateMap = std::map<std::string /*server_name*/, LdsUpdate>;
|
@@ -66,7 +80,7 @@ class XdsApi {
|
|
66
80
|
// If not set, load reporting will be disabled.
|
67
81
|
// If set to the empty string, will use the same server we obtained the CDS
|
68
82
|
// data from.
|
69
|
-
|
83
|
+
absl::optional<std::string> lrs_load_reporting_server_name;
|
70
84
|
};
|
71
85
|
|
72
86
|
using CdsUpdateMap = std::map<std::string /*cluster_name*/, CdsUpdate>;
|
@@ -150,6 +164,7 @@ class XdsApi {
|
|
150
164
|
void AddCategory(std::string name, uint32_t parts_per_million) {
|
151
165
|
drop_category_list_.emplace_back(
|
152
166
|
DropCategory{std::move(name), parts_per_million});
|
167
|
+
if (parts_per_million == 1000000) drop_all_ = true;
|
153
168
|
}
|
154
169
|
|
155
170
|
// The only method invoked from the data plane combiner.
|
@@ -159,6 +174,8 @@ class XdsApi {
|
|
159
174
|
return drop_category_list_;
|
160
175
|
}
|
161
176
|
|
177
|
+
bool drop_all() const { return drop_all_; }
|
178
|
+
|
162
179
|
bool operator==(const DropConfig& other) const {
|
163
180
|
return drop_category_list_ == other.drop_category_list_;
|
164
181
|
}
|
@@ -166,19 +183,19 @@ class XdsApi {
|
|
166
183
|
|
167
184
|
private:
|
168
185
|
DropCategoryList drop_category_list_;
|
186
|
+
bool drop_all_ = false;
|
169
187
|
};
|
170
188
|
|
171
189
|
struct EdsUpdate {
|
172
190
|
PriorityListUpdate priority_list_update;
|
173
191
|
RefCountedPtr<DropConfig> drop_config;
|
174
|
-
bool drop_all = false;
|
175
192
|
};
|
176
193
|
|
177
194
|
using EdsUpdateMap = std::map<std::string /*eds_service_name*/, EdsUpdate>;
|
178
195
|
|
179
196
|
struct ClusterLoadReport {
|
180
197
|
XdsClusterDropStats::DroppedRequestsMap dropped_requests;
|
181
|
-
std::map<XdsLocalityName
|
198
|
+
std::map<RefCountedPtr<XdsLocalityName>, XdsClusterLocalityStats::Snapshot,
|
182
199
|
XdsLocalityName::Less>
|
183
200
|
locality_stats;
|
184
201
|
grpc_millis load_report_interval;
|
@@ -187,7 +204,7 @@ class XdsApi {
|
|
187
204
|
std::pair<std::string /*cluster_name*/, std::string /*eds_service_name*/>,
|
188
205
|
ClusterLoadReport>;
|
189
206
|
|
190
|
-
|
207
|
+
XdsApi(XdsClient* client, TraceFlag* tracer, const XdsBootstrap::Node* node);
|
191
208
|
|
192
209
|
// Creates a request to nack an unsupported resource type.
|
193
210
|
// Takes ownership of \a error.
|
@@ -230,10 +247,12 @@ class XdsApi {
|
|
230
247
|
const grpc_slice& encoded_response,
|
231
248
|
const std::string& expected_server_name,
|
232
249
|
const std::string& expected_route_config_name,
|
250
|
+
const std::set<StringView>& expected_cluster_names,
|
233
251
|
const std::set<StringView>& expected_eds_service_names,
|
234
|
-
LdsUpdate
|
235
|
-
|
236
|
-
|
252
|
+
absl::optional<LdsUpdate>* lds_update,
|
253
|
+
absl::optional<RdsUpdate>* rds_update, CdsUpdateMap* cds_update_map,
|
254
|
+
EdsUpdateMap* eds_update_map, std::string* version, std::string* nonce,
|
255
|
+
std::string* type_url);
|
237
256
|
|
238
257
|
// Creates an LRS request querying \a server_name.
|
239
258
|
grpc_slice CreateLrsInitialRequest(const std::string& server_name);
|
@@ -249,6 +268,8 @@ class XdsApi {
|
|
249
268
|
grpc_millis* load_reporting_interval);
|
250
269
|
|
251
270
|
private:
|
271
|
+
XdsClient* client_;
|
272
|
+
TraceFlag* tracer_;
|
252
273
|
const XdsBootstrap::Node* node_;
|
253
274
|
const std::string build_version_;
|
254
275
|
const std::string user_agent_name_;
|
@@ -29,20 +29,97 @@
|
|
29
29
|
|
30
30
|
namespace grpc_core {
|
31
31
|
|
32
|
-
|
32
|
+
namespace {
|
33
|
+
|
34
|
+
UniquePtr<char> BootstrapString(const XdsBootstrap& bootstrap) {
|
35
|
+
gpr_strvec v;
|
36
|
+
gpr_strvec_init(&v);
|
37
|
+
char* tmp;
|
38
|
+
if (bootstrap.node() != nullptr) {
|
39
|
+
gpr_asprintf(&tmp,
|
40
|
+
"node={\n"
|
41
|
+
" id=\"%s\",\n"
|
42
|
+
" cluster=\"%s\",\n"
|
43
|
+
" locality={\n"
|
44
|
+
" region=\"%s\",\n"
|
45
|
+
" zone=\"%s\",\n"
|
46
|
+
" subzone=\"%s\"\n"
|
47
|
+
" },\n"
|
48
|
+
" metadata=%s,\n"
|
49
|
+
"},\n",
|
50
|
+
bootstrap.node()->id.c_str(),
|
51
|
+
bootstrap.node()->cluster.c_str(),
|
52
|
+
bootstrap.node()->locality_region.c_str(),
|
53
|
+
bootstrap.node()->locality_zone.c_str(),
|
54
|
+
bootstrap.node()->locality_subzone.c_str(),
|
55
|
+
bootstrap.node()->metadata.Dump().c_str());
|
56
|
+
gpr_strvec_add(&v, tmp);
|
57
|
+
}
|
58
|
+
gpr_asprintf(&tmp,
|
59
|
+
"servers=[\n"
|
60
|
+
" {\n"
|
61
|
+
" uri=\"%s\",\n"
|
62
|
+
" creds=[\n",
|
63
|
+
bootstrap.server().server_uri.c_str());
|
64
|
+
gpr_strvec_add(&v, tmp);
|
65
|
+
for (size_t i = 0; i < bootstrap.server().channel_creds.size(); ++i) {
|
66
|
+
const auto& creds = bootstrap.server().channel_creds[i];
|
67
|
+
gpr_asprintf(&tmp, " {type=\"%s\", config=%s},\n", creds.type.c_str(),
|
68
|
+
creds.config.Dump().c_str());
|
69
|
+
gpr_strvec_add(&v, tmp);
|
70
|
+
}
|
71
|
+
gpr_strvec_add(&v, gpr_strdup(" ]\n }\n]"));
|
72
|
+
UniquePtr<char> result(gpr_strvec_flatten(&v, nullptr));
|
73
|
+
gpr_strvec_destroy(&v);
|
74
|
+
return result;
|
75
|
+
}
|
76
|
+
|
77
|
+
} // namespace
|
78
|
+
|
79
|
+
std::unique_ptr<XdsBootstrap> XdsBootstrap::ReadFromFile(XdsClient* client,
|
80
|
+
TraceFlag* tracer,
|
81
|
+
grpc_error** error) {
|
33
82
|
grpc_core::UniquePtr<char> path(gpr_getenv("GRPC_XDS_BOOTSTRAP"));
|
34
83
|
if (path == nullptr) {
|
35
84
|
*error = GRPC_ERROR_CREATE_FROM_STATIC_STRING(
|
36
|
-
"
|
85
|
+
"Environment variable GRPC_XDS_BOOTSTRAP not defined");
|
37
86
|
return nullptr;
|
38
87
|
}
|
88
|
+
if (GRPC_TRACE_FLAG_ENABLED(*tracer)) {
|
89
|
+
gpr_log(GPR_INFO,
|
90
|
+
"[xds_client %p] Got bootstrap file location from "
|
91
|
+
"GRPC_XDS_BOOTSTRAP environment variable: %s",
|
92
|
+
client, path.get());
|
93
|
+
}
|
39
94
|
grpc_slice contents;
|
40
95
|
*error = grpc_load_file(path.get(), /*add_null_terminator=*/true, &contents);
|
41
96
|
if (*error != GRPC_ERROR_NONE) return nullptr;
|
42
|
-
|
97
|
+
StringView contents_str_view = StringViewFromSlice(contents);
|
98
|
+
if (GRPC_TRACE_FLAG_ENABLED(*tracer)) {
|
99
|
+
UniquePtr<char> str = StringViewToCString(contents_str_view);
|
100
|
+
gpr_log(GPR_DEBUG, "[xds_client %p] Bootstrap file contents: %s", client,
|
101
|
+
str.get());
|
102
|
+
}
|
103
|
+
Json json = Json::Parse(contents_str_view, error);
|
43
104
|
grpc_slice_unref_internal(contents);
|
44
|
-
if (*error != GRPC_ERROR_NONE)
|
45
|
-
|
105
|
+
if (*error != GRPC_ERROR_NONE) {
|
106
|
+
char* msg;
|
107
|
+
gpr_asprintf(&msg, "Failed to parse bootstrap file %s", path.get());
|
108
|
+
grpc_error* error_out =
|
109
|
+
GRPC_ERROR_CREATE_REFERENCING_FROM_COPIED_STRING(msg, error, 1);
|
110
|
+
gpr_free(msg);
|
111
|
+
GRPC_ERROR_UNREF(*error);
|
112
|
+
*error = error_out;
|
113
|
+
return nullptr;
|
114
|
+
}
|
115
|
+
std::unique_ptr<XdsBootstrap> result =
|
116
|
+
absl::make_unique<XdsBootstrap>(std::move(json), error);
|
117
|
+
if (*error == GRPC_ERROR_NONE && GRPC_TRACE_FLAG_ENABLED(*tracer)) {
|
118
|
+
gpr_log(GPR_INFO,
|
119
|
+
"[xds_client %p] Bootstrap config for creating xds client:\n%s",
|
120
|
+
client, BootstrapString(*result).get());
|
121
|
+
}
|
122
|
+
return result;
|
46
123
|
}
|
47
124
|
|
48
125
|
XdsBootstrap::XdsBootstrap(Json json, grpc_error** error) {
|
@@ -33,6 +33,8 @@
|
|
33
33
|
|
34
34
|
namespace grpc_core {
|
35
35
|
|
36
|
+
class XdsClient;
|
37
|
+
|
36
38
|
class XdsBootstrap {
|
37
39
|
public:
|
38
40
|
struct Node {
|
@@ -56,7 +58,9 @@ class XdsBootstrap {
|
|
56
58
|
|
57
59
|
// If *error is not GRPC_ERROR_NONE after returning, then there was an
|
58
60
|
// error reading the file.
|
59
|
-
static std::unique_ptr<XdsBootstrap> ReadFromFile(
|
61
|
+
static std::unique_ptr<XdsBootstrap> ReadFromFile(XdsClient* client,
|
62
|
+
TraceFlag* tracer,
|
63
|
+
grpc_error** error);
|
60
64
|
|
61
65
|
// Do not instantiate directly -- use ReadFromFile() above instead.
|
62
66
|
XdsBootstrap(Json json, grpc_error** error);
|
@@ -22,6 +22,8 @@
|
|
22
22
|
#include <limits.h>
|
23
23
|
#include <string.h>
|
24
24
|
|
25
|
+
#include "absl/strings/str_join.h"
|
26
|
+
|
25
27
|
#include <grpc/byte_buffer_reader.h>
|
26
28
|
#include <grpc/grpc.h>
|
27
29
|
#include <grpc/support/alloc.h>
|
@@ -126,7 +128,8 @@ class XdsClient::ChannelState::AdsCallState
|
|
126
128
|
bool seen_response() const { return seen_response_; }
|
127
129
|
|
128
130
|
void Subscribe(const std::string& type_url, const std::string& name);
|
129
|
-
void Unsubscribe(const std::string& type_url, const std::string& name
|
131
|
+
void Unsubscribe(const std::string& type_url, const std::string& name,
|
132
|
+
bool delay_unsubscription);
|
130
133
|
|
131
134
|
bool HasSubscribedResources() const;
|
132
135
|
|
@@ -238,8 +241,8 @@ class XdsClient::ChannelState::AdsCallState
|
|
238
241
|
|
239
242
|
void SendMessageLocked(const std::string& type_url);
|
240
243
|
|
241
|
-
void AcceptLdsUpdate(XdsApi::LdsUpdate lds_update);
|
242
|
-
void AcceptRdsUpdate(XdsApi::RdsUpdate rds_update);
|
244
|
+
void AcceptLdsUpdate(absl::optional<XdsApi::LdsUpdate> lds_update);
|
245
|
+
void AcceptRdsUpdate(absl::optional<XdsApi::RdsUpdate> rds_update);
|
243
246
|
void AcceptCdsUpdate(XdsApi::CdsUpdateMap cds_update_map);
|
244
247
|
void AcceptEdsUpdate(XdsApi::EdsUpdateMap eds_update_map);
|
245
248
|
|
@@ -299,7 +302,6 @@ class XdsClient::ChannelState::LrsCallState
|
|
299
302
|
void Orphan() override;
|
300
303
|
|
301
304
|
void MaybeStartReportingLocked();
|
302
|
-
bool ShouldSendLoadReports(const StringView& cluster_name) const;
|
303
305
|
|
304
306
|
RetryableCall<LrsCallState>* parent() { return parent_.get(); }
|
305
307
|
ChannelState* chand() const { return parent_->chand(); }
|
@@ -555,9 +557,10 @@ void XdsClient::ChannelState::Subscribe(const std::string& type_url,
|
|
555
557
|
}
|
556
558
|
|
557
559
|
void XdsClient::ChannelState::Unsubscribe(const std::string& type_url,
|
558
|
-
const std::string& name
|
560
|
+
const std::string& name,
|
561
|
+
bool delay_unsubscription) {
|
559
562
|
if (ads_calld_ != nullptr) {
|
560
|
-
ads_calld_->calld()->Unsubscribe(type_url, name);
|
563
|
+
ads_calld_->calld()->Unsubscribe(type_url, name, delay_unsubscription);
|
561
564
|
if (!ads_calld_->calld()->HasSubscribedResources()) ads_calld_.reset();
|
562
565
|
}
|
563
566
|
}
|
@@ -701,7 +704,8 @@ XdsClient::ChannelState::AdsCallState::AdsCallState(
|
|
701
704
|
grpc_op* op = ops;
|
702
705
|
op->op = GRPC_OP_SEND_INITIAL_METADATA;
|
703
706
|
op->data.send_initial_metadata.count = 0;
|
704
|
-
op->flags =
|
707
|
+
op->flags = GRPC_INITIAL_METADATA_WAIT_FOR_READY |
|
708
|
+
GRPC_INITIAL_METADATA_WAIT_FOR_READY_EXPLICITLY_SET;
|
705
709
|
op->reserved = nullptr;
|
706
710
|
op++;
|
707
711
|
call_error = grpc_call_start_batch_and_execute(call_, ops, (size_t)(op - ops),
|
@@ -712,6 +716,11 @@ XdsClient::ChannelState::AdsCallState::AdsCallState(
|
|
712
716
|
grpc_schedule_on_exec_ctx);
|
713
717
|
if (xds_client()->service_config_watcher_ != nullptr) {
|
714
718
|
Subscribe(XdsApi::kLdsTypeUrl, xds_client()->server_name_);
|
719
|
+
if (xds_client()->lds_result_.has_value() &&
|
720
|
+
!xds_client()->lds_result_->route_config_name.empty()) {
|
721
|
+
Subscribe(XdsApi::kRdsTypeUrl,
|
722
|
+
xds_client()->lds_result_->route_config_name);
|
723
|
+
}
|
715
724
|
}
|
716
725
|
for (const auto& p : xds_client()->cluster_map_) {
|
717
726
|
Subscribe(XdsApi::kCdsTypeUrl, std::string(p.first));
|
@@ -788,33 +797,47 @@ void XdsClient::ChannelState::AdsCallState::SendMessageLocked(
|
|
788
797
|
return;
|
789
798
|
}
|
790
799
|
auto& state = state_map_[type_url];
|
791
|
-
grpc_error* error = state.error;
|
792
|
-
state.error = GRPC_ERROR_NONE;
|
793
800
|
grpc_slice request_payload_slice;
|
801
|
+
std::set<StringView> resource_names;
|
794
802
|
if (type_url == XdsApi::kLdsTypeUrl) {
|
803
|
+
resource_names.insert(xds_client()->server_name_);
|
795
804
|
request_payload_slice = xds_client()->api_.CreateLdsRequest(
|
796
|
-
xds_client()->server_name_, state.version, state.nonce,
|
797
|
-
!sent_initial_message_);
|
805
|
+
xds_client()->server_name_, state.version, state.nonce,
|
806
|
+
GRPC_ERROR_REF(state.error), !sent_initial_message_);
|
798
807
|
state.subscribed_resources[xds_client()->server_name_]->Start(Ref());
|
799
808
|
} else if (type_url == XdsApi::kRdsTypeUrl) {
|
809
|
+
resource_names.insert(xds_client()->lds_result_->route_config_name);
|
800
810
|
request_payload_slice = xds_client()->api_.CreateRdsRequest(
|
801
|
-
xds_client()->
|
802
|
-
!sent_initial_message_);
|
803
|
-
state.subscribed_resources[xds_client()->
|
811
|
+
xds_client()->lds_result_->route_config_name, state.version,
|
812
|
+
state.nonce, GRPC_ERROR_REF(state.error), !sent_initial_message_);
|
813
|
+
state.subscribed_resources[xds_client()->lds_result_->route_config_name]
|
814
|
+
->Start(Ref());
|
804
815
|
} else if (type_url == XdsApi::kCdsTypeUrl) {
|
816
|
+
resource_names = ClusterNamesForRequest();
|
805
817
|
request_payload_slice = xds_client()->api_.CreateCdsRequest(
|
806
|
-
|
818
|
+
resource_names, state.version, state.nonce, GRPC_ERROR_REF(state.error),
|
807
819
|
!sent_initial_message_);
|
808
820
|
} else if (type_url == XdsApi::kEdsTypeUrl) {
|
821
|
+
resource_names = EdsServiceNamesForRequest();
|
809
822
|
request_payload_slice = xds_client()->api_.CreateEdsRequest(
|
810
|
-
|
823
|
+
resource_names, state.version, state.nonce, GRPC_ERROR_REF(state.error),
|
811
824
|
!sent_initial_message_);
|
812
825
|
} else {
|
813
826
|
request_payload_slice = xds_client()->api_.CreateUnsupportedTypeNackRequest(
|
814
|
-
type_url, state.nonce, state.error);
|
827
|
+
type_url, state.nonce, GRPC_ERROR_REF(state.error));
|
815
828
|
state_map_.erase(type_url);
|
816
829
|
}
|
817
830
|
sent_initial_message_ = true;
|
831
|
+
if (GRPC_TRACE_FLAG_ENABLED(grpc_xds_client_trace)) {
|
832
|
+
gpr_log(GPR_INFO,
|
833
|
+
"[xds_client %p] sending ADS request: type=%s version=%s nonce=%s "
|
834
|
+
"error=%s resources=%s",
|
835
|
+
xds_client(), type_url.c_str(), state.version.c_str(),
|
836
|
+
state.nonce.c_str(), grpc_error_string(state.error),
|
837
|
+
absl::StrJoin(resource_names, " ").c_str());
|
838
|
+
}
|
839
|
+
GRPC_ERROR_UNREF(state.error);
|
840
|
+
state.error = GRPC_ERROR_NONE;
|
818
841
|
// Create message payload.
|
819
842
|
send_message_payload_ =
|
820
843
|
grpc_raw_byte_buffer_create(&request_payload_slice, 1);
|
@@ -847,9 +870,10 @@ void XdsClient::ChannelState::AdsCallState::Subscribe(
|
|
847
870
|
}
|
848
871
|
|
849
872
|
void XdsClient::ChannelState::AdsCallState::Unsubscribe(
|
850
|
-
const std::string& type_url, const std::string& name
|
873
|
+
const std::string& type_url, const std::string& name,
|
874
|
+
bool delay_unsubscription) {
|
851
875
|
state_map_[type_url].subscribed_resources.erase(name);
|
852
|
-
SendMessageLocked(type_url);
|
876
|
+
if (!delay_unsubscription) SendMessageLocked(type_url);
|
853
877
|
}
|
854
878
|
|
855
879
|
bool XdsClient::ChannelState::AdsCallState::HasSubscribedResources() const {
|
@@ -860,25 +884,33 @@ bool XdsClient::ChannelState::AdsCallState::HasSubscribedResources() const {
|
|
860
884
|
}
|
861
885
|
|
862
886
|
void XdsClient::ChannelState::AdsCallState::AcceptLdsUpdate(
|
863
|
-
XdsApi::LdsUpdate lds_update) {
|
864
|
-
|
865
|
-
|
866
|
-
|
867
|
-
|
887
|
+
absl::optional<XdsApi::LdsUpdate> lds_update) {
|
888
|
+
if (!lds_update.has_value()) {
|
889
|
+
gpr_log(GPR_INFO,
|
890
|
+
"[xds_client %p] LDS update does not include requested resource",
|
891
|
+
xds_client());
|
892
|
+
xds_client()->service_config_watcher_->OnError(
|
893
|
+
GRPC_ERROR_CREATE_FROM_STATIC_STRING(
|
894
|
+
"LDS update does not include requested resource"));
|
895
|
+
return;
|
896
|
+
}
|
868
897
|
if (GRPC_TRACE_FLAG_ENABLED(grpc_xds_client_trace)) {
|
869
898
|
gpr_log(GPR_INFO,
|
870
|
-
"[xds_client %p] LDS update received: "
|
871
|
-
"
|
872
|
-
|
873
|
-
|
874
|
-
|
899
|
+
"[xds_client %p] LDS update received: route_config_name=%s, "
|
900
|
+
"cluster_name=%s",
|
901
|
+
xds_client(),
|
902
|
+
(!lds_update->route_config_name.empty()
|
903
|
+
? lds_update->route_config_name.c_str()
|
904
|
+
: "<inlined>"),
|
905
|
+
(lds_update->rds_update.has_value()
|
906
|
+
? lds_update->rds_update->cluster_name.c_str()
|
907
|
+
: "<to be obtained via RDS>"));
|
875
908
|
}
|
876
909
|
auto& lds_state = state_map_[XdsApi::kLdsTypeUrl];
|
877
910
|
auto& state = lds_state.subscribed_resources[xds_client()->server_name_];
|
878
911
|
if (state != nullptr) state->Finish();
|
879
912
|
// Ignore identical update.
|
880
|
-
if (xds_client()->
|
881
|
-
xds_client()->cluster_name_ == cluster_name) {
|
913
|
+
if (xds_client()->lds_result_ == lds_update) {
|
882
914
|
if (GRPC_TRACE_FLAG_ENABLED(grpc_xds_client_trace)) {
|
883
915
|
gpr_log(GPR_INFO,
|
884
916
|
"[xds_client %p] LDS update identical to current, ignoring.",
|
@@ -886,15 +918,19 @@ void XdsClient::ChannelState::AdsCallState::AcceptLdsUpdate(
|
|
886
918
|
}
|
887
919
|
return;
|
888
920
|
}
|
889
|
-
xds_client()->
|
890
|
-
|
891
|
-
|
892
|
-
|
893
|
-
|
894
|
-
|
921
|
+
if (xds_client()->lds_result_.has_value() &&
|
922
|
+
!xds_client()->lds_result_->route_config_name.empty()) {
|
923
|
+
Unsubscribe(
|
924
|
+
XdsApi::kRdsTypeUrl, xds_client()->lds_result_->route_config_name,
|
925
|
+
/*delay_unsubscription=*/!lds_update->route_config_name.empty());
|
926
|
+
}
|
927
|
+
xds_client()->lds_result_ = std::move(lds_update);
|
928
|
+
if (xds_client()->lds_result_->rds_update.has_value()) {
|
929
|
+
// If the RouteConfiguration was found inlined in LDS response, notify
|
930
|
+
// the watcher immediately.
|
895
931
|
RefCountedPtr<ServiceConfig> service_config;
|
896
932
|
grpc_error* error = xds_client()->CreateServiceConfig(
|
897
|
-
xds_client()->
|
933
|
+
xds_client()->lds_result_->rds_update->cluster_name, &service_config);
|
898
934
|
if (error == GRPC_ERROR_NONE) {
|
899
935
|
xds_client()->service_config_watcher_->OnServiceConfigChanged(
|
900
936
|
std::move(service_config));
|
@@ -903,24 +939,33 @@ void XdsClient::ChannelState::AdsCallState::AcceptLdsUpdate(
|
|
903
939
|
}
|
904
940
|
} else {
|
905
941
|
// Send RDS request for dynamic resolution.
|
906
|
-
Subscribe(XdsApi::kRdsTypeUrl,
|
942
|
+
Subscribe(XdsApi::kRdsTypeUrl,
|
943
|
+
xds_client()->lds_result_->route_config_name);
|
907
944
|
}
|
908
945
|
}
|
909
946
|
|
910
947
|
void XdsClient::ChannelState::AdsCallState::AcceptRdsUpdate(
|
911
|
-
XdsApi::RdsUpdate rds_update) {
|
912
|
-
if (
|
948
|
+
absl::optional<XdsApi::RdsUpdate> rds_update) {
|
949
|
+
if (!rds_update.has_value()) {
|
913
950
|
gpr_log(GPR_INFO,
|
914
|
-
"[xds_client %p] RDS update
|
915
|
-
|
916
|
-
|
951
|
+
"[xds_client %p] RDS update does not include requested resource",
|
952
|
+
xds_client());
|
953
|
+
xds_client()->service_config_watcher_->OnError(
|
954
|
+
GRPC_ERROR_CREATE_FROM_STATIC_STRING(
|
955
|
+
"RDS update does not include requested resource"));
|
956
|
+
return;
|
957
|
+
}
|
958
|
+
if (GRPC_TRACE_FLAG_ENABLED(grpc_xds_client_trace)) {
|
959
|
+
gpr_log(GPR_INFO, "[xds_client %p] RDS update received: cluster_name=%s",
|
960
|
+
xds_client(), rds_update->cluster_name.c_str());
|
917
961
|
}
|
918
962
|
auto& rds_state = state_map_[XdsApi::kRdsTypeUrl];
|
919
963
|
auto& state =
|
920
|
-
rds_state
|
964
|
+
rds_state
|
965
|
+
.subscribed_resources[xds_client()->lds_result_->route_config_name];
|
921
966
|
if (state != nullptr) state->Finish();
|
922
967
|
// Ignore identical update.
|
923
|
-
if (xds_client()->
|
968
|
+
if (xds_client()->rds_result_ == rds_update) {
|
924
969
|
if (GRPC_TRACE_FLAG_ENABLED(grpc_xds_client_trace)) {
|
925
970
|
gpr_log(GPR_INFO,
|
926
971
|
"[xds_client %p] RDS update identical to current, ignoring.",
|
@@ -928,11 +973,11 @@ void XdsClient::ChannelState::AdsCallState::AcceptRdsUpdate(
|
|
928
973
|
}
|
929
974
|
return;
|
930
975
|
}
|
931
|
-
xds_client()->
|
976
|
+
xds_client()->rds_result_ = std::move(rds_update);
|
932
977
|
// Notify the watcher.
|
933
978
|
RefCountedPtr<ServiceConfig> service_config;
|
934
979
|
grpc_error* error = xds_client()->CreateServiceConfig(
|
935
|
-
xds_client()->
|
980
|
+
xds_client()->rds_result_->cluster_name, &service_config);
|
936
981
|
if (error == GRPC_ERROR_NONE) {
|
937
982
|
xds_client()->service_config_watcher_->OnServiceConfigChanged(
|
938
983
|
std::move(service_config));
|
@@ -944,6 +989,7 @@ void XdsClient::ChannelState::AdsCallState::AcceptRdsUpdate(
|
|
944
989
|
void XdsClient::ChannelState::AdsCallState::AcceptCdsUpdate(
|
945
990
|
XdsApi::CdsUpdateMap cds_update_map) {
|
946
991
|
auto& cds_state = state_map_[XdsApi::kCdsTypeUrl];
|
992
|
+
std::set<std::string> eds_resource_names_seen;
|
947
993
|
for (auto& p : cds_update_map) {
|
948
994
|
const char* cluster_name = p.first.c_str();
|
949
995
|
XdsApi::CdsUpdate& cds_update = p.second;
|
@@ -952,21 +998,22 @@ void XdsClient::ChannelState::AdsCallState::AcceptCdsUpdate(
|
|
952
998
|
if (GRPC_TRACE_FLAG_ENABLED(grpc_xds_client_trace)) {
|
953
999
|
gpr_log(GPR_INFO,
|
954
1000
|
"[xds_client %p] CDS update (cluster=%s) received: "
|
955
|
-
"eds_service_name=%s, "
|
956
|
-
"lrs_load_reporting_server_name=%s",
|
1001
|
+
"eds_service_name=%s, lrs_load_reporting_server_name=%s",
|
957
1002
|
xds_client(), cluster_name, cds_update.eds_service_name.c_str(),
|
958
1003
|
cds_update.lrs_load_reporting_server_name.has_value()
|
959
1004
|
? cds_update.lrs_load_reporting_server_name.value().c_str()
|
960
1005
|
: "(N/A)");
|
961
1006
|
}
|
962
|
-
|
1007
|
+
// Record the EDS resource names seen.
|
1008
|
+
eds_resource_names_seen.insert(cds_update.eds_service_name.empty()
|
1009
|
+
? cluster_name
|
1010
|
+
: cds_update.eds_service_name);
|
963
1011
|
// Ignore identical update.
|
1012
|
+
ClusterState& cluster_state = xds_client()->cluster_map_[cluster_name];
|
964
1013
|
if (cluster_state.update.has_value() &&
|
965
|
-
cds_update.eds_service_name ==
|
966
|
-
|
967
|
-
|
968
|
-
cluster_state.update.value()
|
969
|
-
.lrs_load_reporting_server_name.value()) {
|
1014
|
+
cds_update.eds_service_name == cluster_state.update->eds_service_name &&
|
1015
|
+
cds_update.lrs_load_reporting_server_name ==
|
1016
|
+
cluster_state.update->lrs_load_reporting_server_name) {
|
970
1017
|
if (GRPC_TRACE_FLAG_ENABLED(grpc_xds_client_trace)) {
|
971
1018
|
gpr_log(GPR_INFO,
|
972
1019
|
"[xds_client %p] CDS update identical to current, ignoring.",
|
@@ -975,12 +1022,41 @@ void XdsClient::ChannelState::AdsCallState::AcceptCdsUpdate(
|
|
975
1022
|
continue;
|
976
1023
|
}
|
977
1024
|
// Update the cluster state.
|
978
|
-
cluster_state.update
|
1025
|
+
cluster_state.update = std::move(cds_update);
|
979
1026
|
// Notify all watchers.
|
980
1027
|
for (const auto& p : cluster_state.watchers) {
|
981
1028
|
p.first->OnClusterChanged(cluster_state.update.value());
|
982
1029
|
}
|
983
1030
|
}
|
1031
|
+
// For any subscribed resource that is not present in the update,
|
1032
|
+
// remove it from the cache and notify watchers of the error.
|
1033
|
+
for (const auto& p : cds_state.subscribed_resources) {
|
1034
|
+
const std::string& cluster_name = p.first;
|
1035
|
+
if (cds_update_map.find(cluster_name) == cds_update_map.end()) {
|
1036
|
+
ClusterState& cluster_state = xds_client()->cluster_map_[cluster_name];
|
1037
|
+
cluster_state.update.reset();
|
1038
|
+
for (const auto& p : cluster_state.watchers) {
|
1039
|
+
p.first->OnError(GRPC_ERROR_CREATE_FROM_STATIC_STRING(
|
1040
|
+
"Cluster not present in CDS update"));
|
1041
|
+
}
|
1042
|
+
}
|
1043
|
+
}
|
1044
|
+
// Also remove any EDS resources that are no longer referred to by any CDS
|
1045
|
+
// resources.
|
1046
|
+
auto& eds_state = state_map_[XdsApi::kEdsTypeUrl];
|
1047
|
+
for (const auto& p : eds_state.subscribed_resources) {
|
1048
|
+
const std::string& eds_resource_name = p.first;
|
1049
|
+
if (eds_resource_names_seen.find(eds_resource_name) ==
|
1050
|
+
eds_resource_names_seen.end()) {
|
1051
|
+
EndpointState& endpoint_state =
|
1052
|
+
xds_client()->endpoint_map_[eds_resource_name];
|
1053
|
+
endpoint_state.update.reset();
|
1054
|
+
for (const auto& p : endpoint_state.watchers) {
|
1055
|
+
p.first->OnError(GRPC_ERROR_CREATE_FROM_STATIC_STRING(
|
1056
|
+
"ClusterLoadAssignment resource removed due to CDS update"));
|
1057
|
+
}
|
1058
|
+
}
|
1059
|
+
}
|
984
1060
|
}
|
985
1061
|
|
986
1062
|
void XdsClient::ChannelState::AdsCallState::AcceptEdsUpdate(
|
@@ -998,7 +1074,7 @@ void XdsClient::ChannelState::AdsCallState::AcceptEdsUpdate(
|
|
998
1074
|
" drop categories received (drop_all=%d)",
|
999
1075
|
xds_client(), eds_update.priority_list_update.size(),
|
1000
1076
|
eds_update.drop_config->drop_category_list().size(),
|
1001
|
-
eds_update.drop_all);
|
1077
|
+
eds_update.drop_config->drop_all());
|
1002
1078
|
for (size_t priority = 0;
|
1003
1079
|
priority < eds_update.priority_list_update.size(); ++priority) {
|
1004
1080
|
const auto* locality_map_update = eds_update.priority_list_update.Find(
|
@@ -1043,25 +1119,27 @@ void XdsClient::ChannelState::AdsCallState::AcceptEdsUpdate(
|
|
1043
1119
|
EndpointState& endpoint_state =
|
1044
1120
|
xds_client()->endpoint_map_[eds_service_name];
|
1045
1121
|
// Ignore identical update.
|
1046
|
-
|
1047
|
-
|
1048
|
-
|
1049
|
-
|
1050
|
-
|
1051
|
-
|
1052
|
-
|
1053
|
-
if (
|
1054
|
-
|
1055
|
-
|
1056
|
-
|
1122
|
+
if (endpoint_state.update.has_value()) {
|
1123
|
+
const XdsApi::EdsUpdate& prev_update = endpoint_state.update.value();
|
1124
|
+
const bool priority_list_changed =
|
1125
|
+
prev_update.priority_list_update != eds_update.priority_list_update;
|
1126
|
+
const bool drop_config_changed =
|
1127
|
+
prev_update.drop_config == nullptr ||
|
1128
|
+
*prev_update.drop_config != *eds_update.drop_config;
|
1129
|
+
if (!priority_list_changed && !drop_config_changed) {
|
1130
|
+
if (GRPC_TRACE_FLAG_ENABLED(grpc_xds_client_trace)) {
|
1131
|
+
gpr_log(GPR_INFO,
|
1132
|
+
"[xds_client %p] EDS update identical to current, ignoring.",
|
1133
|
+
xds_client());
|
1134
|
+
}
|
1135
|
+
continue;
|
1057
1136
|
}
|
1058
|
-
continue;
|
1059
1137
|
}
|
1060
1138
|
// Update the cluster state.
|
1061
1139
|
endpoint_state.update = std::move(eds_update);
|
1062
1140
|
// Notify all watchers.
|
1063
1141
|
for (const auto& p : endpoint_state.watchers) {
|
1064
|
-
p.first->OnEndpointChanged(endpoint_state.update);
|
1142
|
+
p.first->OnEndpointChanged(endpoint_state.update.value());
|
1065
1143
|
}
|
1066
1144
|
}
|
1067
1145
|
}
|
@@ -1135,8 +1213,8 @@ void XdsClient::ChannelState::AdsCallState::OnResponseReceivedLocked(
|
|
1135
1213
|
// mode. We will also need to cancel the timer when we receive a serverlist
|
1136
1214
|
// from the balancer.
|
1137
1215
|
// Parse the response.
|
1138
|
-
XdsApi::LdsUpdate lds_update;
|
1139
|
-
XdsApi::RdsUpdate rds_update;
|
1216
|
+
absl::optional<XdsApi::LdsUpdate> lds_update;
|
1217
|
+
absl::optional<XdsApi::RdsUpdate> rds_update;
|
1140
1218
|
XdsApi::CdsUpdateMap cds_update_map;
|
1141
1219
|
XdsApi::EdsUpdateMap eds_update_map;
|
1142
1220
|
std::string version;
|
@@ -1144,13 +1222,18 @@ void XdsClient::ChannelState::AdsCallState::OnResponseReceivedLocked(
|
|
1144
1222
|
std::string type_url;
|
1145
1223
|
// Note that ParseAdsResponse() also validates the response.
|
1146
1224
|
grpc_error* parse_error = xds_client->api_.ParseAdsResponse(
|
1147
|
-
response_slice, xds_client->server_name_,
|
1225
|
+
response_slice, xds_client->server_name_,
|
1226
|
+
(xds_client->lds_result_.has_value()
|
1227
|
+
? xds_client->lds_result_->route_config_name
|
1228
|
+
: ""),
|
1229
|
+
ads_calld->ClusterNamesForRequest(),
|
1148
1230
|
ads_calld->EdsServiceNamesForRequest(), &lds_update, &rds_update,
|
1149
1231
|
&cds_update_map, &eds_update_map, &version, &nonce, &type_url);
|
1150
1232
|
grpc_slice_unref_internal(response_slice);
|
1151
1233
|
if (type_url.empty()) {
|
1152
1234
|
// Ignore unparsable response.
|
1153
|
-
gpr_log(GPR_ERROR,
|
1235
|
+
gpr_log(GPR_ERROR,
|
1236
|
+
"[xds_client %p] Error parsing ADS response (%s) -- ignoring",
|
1154
1237
|
xds_client, grpc_error_string(parse_error));
|
1155
1238
|
GRPC_ERROR_UNREF(parse_error);
|
1156
1239
|
} else {
|
@@ -1162,10 +1245,11 @@ void XdsClient::ChannelState::AdsCallState::OnResponseReceivedLocked(
|
|
1162
1245
|
GRPC_ERROR_UNREF(state.error);
|
1163
1246
|
state.error = parse_error;
|
1164
1247
|
// NACK unacceptable update.
|
1165
|
-
gpr_log(
|
1166
|
-
|
1167
|
-
|
1168
|
-
|
1248
|
+
gpr_log(GPR_ERROR,
|
1249
|
+
"[xds_client %p] ADS response invalid for resource type %s "
|
1250
|
+
"version %s, will NACK: nonce=%s error=%s",
|
1251
|
+
xds_client, type_url.c_str(), version.c_str(),
|
1252
|
+
state.nonce.c_str(), grpc_error_string(parse_error));
|
1169
1253
|
ads_calld->SendMessageLocked(type_url);
|
1170
1254
|
} else {
|
1171
1255
|
ads_calld->seen_response_ = true;
|
@@ -1335,7 +1419,7 @@ bool LoadReportCountersAreZero(const XdsApi::ClusterLoadReportMap& snapshot) {
|
|
1335
1419
|
void XdsClient::ChannelState::LrsCallState::Reporter::SendReportLocked() {
|
1336
1420
|
// Construct snapshot from all reported stats.
|
1337
1421
|
XdsApi::ClusterLoadReportMap snapshot =
|
1338
|
-
xds_client()->BuildLoadReportSnapshot();
|
1422
|
+
xds_client()->BuildLoadReportSnapshot(parent_->cluster_names_);
|
1339
1423
|
// Skip client load report if the counters were all zero in the last
|
1340
1424
|
// report and they are still zero in this one.
|
1341
1425
|
const bool old_val = last_report_counters_were_zero_;
|
@@ -1381,6 +1465,12 @@ void XdsClient::ChannelState::LrsCallState::Reporter::OnReportDoneLocked(
|
|
1381
1465
|
Reporter* self = static_cast<Reporter*>(arg);
|
1382
1466
|
grpc_byte_buffer_destroy(self->parent_->send_message_payload_);
|
1383
1467
|
self->parent_->send_message_payload_ = nullptr;
|
1468
|
+
// If there are no more registered stats to report, cancel the call.
|
1469
|
+
if (self->xds_client()->load_report_map_.empty()) {
|
1470
|
+
self->parent_->chand()->StopLrsCall();
|
1471
|
+
self->Unref(DEBUG_LOCATION, "Reporter+report_done+no_more_reporters");
|
1472
|
+
return;
|
1473
|
+
}
|
1384
1474
|
if (error != GRPC_ERROR_NONE || !self->IsCurrentReporterOnCall()) {
|
1385
1475
|
// If this reporter is no longer the current one on the call, the reason
|
1386
1476
|
// might be that it was orphaned for a new one due to config update.
|
@@ -1436,7 +1526,8 @@ XdsClient::ChannelState::LrsCallState::LrsCallState(
|
|
1436
1526
|
grpc_op* op = ops;
|
1437
1527
|
op->op = GRPC_OP_SEND_INITIAL_METADATA;
|
1438
1528
|
op->data.send_initial_metadata.count = 0;
|
1439
|
-
op->flags =
|
1529
|
+
op->flags = GRPC_INITIAL_METADATA_WAIT_FOR_READY |
|
1530
|
+
GRPC_INITIAL_METADATA_WAIT_FOR_READY_EXPLICITLY_SET;
|
1440
1531
|
op->reserved = nullptr;
|
1441
1532
|
op++;
|
1442
1533
|
// Op: send request message.
|
@@ -1524,20 +1615,16 @@ void XdsClient::ChannelState::LrsCallState::MaybeStartReportingLocked() {
|
|
1524
1615
|
// Don't start if the ADS call hasn't received any valid response. Note that
|
1525
1616
|
// this must be the first channel because it is the current channel but its
|
1526
1617
|
// ADS call hasn't seen any response.
|
1527
|
-
|
1528
|
-
|
1618
|
+
if (chand()->ads_calld_ == nullptr ||
|
1619
|
+
chand()->ads_calld_->calld() == nullptr ||
|
1620
|
+
!chand()->ads_calld_->calld()->seen_response()) {
|
1621
|
+
return;
|
1622
|
+
}
|
1529
1623
|
// Start reporting.
|
1530
1624
|
reporter_ = MakeOrphanable<Reporter>(
|
1531
1625
|
Ref(DEBUG_LOCATION, "LRS+load_report+start"), load_reporting_interval_);
|
1532
1626
|
}
|
1533
1627
|
|
1534
|
-
bool XdsClient::ChannelState::LrsCallState::ShouldSendLoadReports(
|
1535
|
-
const StringView& cluster_name) const {
|
1536
|
-
// Only send load reports for the clusters that are asked for by the LRS
|
1537
|
-
// server.
|
1538
|
-
return cluster_names_.find(std::string(cluster_name)) != cluster_names_.end();
|
1539
|
-
}
|
1540
|
-
|
1541
1628
|
void XdsClient::ChannelState::LrsCallState::OnInitialRequestSent(
|
1542
1629
|
void* arg, grpc_error* error) {
|
1543
1630
|
LrsCallState* lrs_calld = static_cast<LrsCallState*>(arg);
|
@@ -1724,10 +1811,15 @@ XdsClient::XdsClient(Combiner* combiner, grpc_pollset_set* interested_parties,
|
|
1724
1811
|
request_timeout_(GetRequestTimeout(channel_args)),
|
1725
1812
|
combiner_(GRPC_COMBINER_REF(combiner, "xds_client")),
|
1726
1813
|
interested_parties_(interested_parties),
|
1727
|
-
bootstrap_(
|
1728
|
-
|
1814
|
+
bootstrap_(
|
1815
|
+
XdsBootstrap::ReadFromFile(this, &grpc_xds_client_trace, error)),
|
1816
|
+
api_(this, &grpc_xds_client_trace,
|
1817
|
+
bootstrap_ == nullptr ? nullptr : bootstrap_->node()),
|
1729
1818
|
server_name_(server_name),
|
1730
1819
|
service_config_watcher_(std::move(watcher)) {
|
1820
|
+
if (GRPC_TRACE_FLAG_ENABLED(grpc_xds_client_trace)) {
|
1821
|
+
gpr_log(GPR_INFO, "[xds_client %p] creating xds client", this);
|
1822
|
+
}
|
1731
1823
|
if (*error != GRPC_ERROR_NONE) {
|
1732
1824
|
gpr_log(GPR_ERROR, "[xds_client %p] failed to read bootstrap file: %s",
|
1733
1825
|
this, grpc_error_string(*error));
|
@@ -1752,9 +1844,17 @@ XdsClient::XdsClient(Combiner* combiner, grpc_pollset_set* interested_parties,
|
|
1752
1844
|
}
|
1753
1845
|
}
|
1754
1846
|
|
1755
|
-
XdsClient::~XdsClient() {
|
1847
|
+
XdsClient::~XdsClient() {
|
1848
|
+
if (GRPC_TRACE_FLAG_ENABLED(grpc_xds_client_trace)) {
|
1849
|
+
gpr_log(GPR_INFO, "[xds_client %p] destroying xds client", this);
|
1850
|
+
}
|
1851
|
+
GRPC_COMBINER_UNREF(combiner_, "xds_client");
|
1852
|
+
}
|
1756
1853
|
|
1757
1854
|
void XdsClient::Orphan() {
|
1855
|
+
if (GRPC_TRACE_FLAG_ENABLED(grpc_xds_client_trace)) {
|
1856
|
+
gpr_log(GPR_INFO, "[xds_client %p] shutting down xds client", this);
|
1857
|
+
}
|
1758
1858
|
shutting_down_ = true;
|
1759
1859
|
chand_.reset();
|
1760
1860
|
// We do not clear cluster_map_ and endpoint_map_ if the xds client was
|
@@ -1779,13 +1879,18 @@ void XdsClient::WatchClusterData(
|
|
1779
1879
|
// If we've already received an CDS update, notify the new watcher
|
1780
1880
|
// immediately.
|
1781
1881
|
if (cluster_state.update.has_value()) {
|
1882
|
+
if (GRPC_TRACE_FLAG_ENABLED(grpc_xds_client_trace)) {
|
1883
|
+
gpr_log(GPR_INFO, "[xds_client %p] returning cached cluster data for %s",
|
1884
|
+
this, StringViewToCString(cluster_name).get());
|
1885
|
+
}
|
1782
1886
|
w->OnClusterChanged(cluster_state.update.value());
|
1783
1887
|
}
|
1784
1888
|
chand_->Subscribe(XdsApi::kCdsTypeUrl, cluster_name_str);
|
1785
1889
|
}
|
1786
1890
|
|
1787
1891
|
void XdsClient::CancelClusterDataWatch(StringView cluster_name,
|
1788
|
-
ClusterWatcherInterface* watcher
|
1892
|
+
ClusterWatcherInterface* watcher,
|
1893
|
+
bool delay_unsubscription) {
|
1789
1894
|
if (shutting_down_) return;
|
1790
1895
|
std::string cluster_name_str = std::string(cluster_name);
|
1791
1896
|
ClusterState& cluster_state = cluster_map_[cluster_name_str];
|
@@ -1794,7 +1899,8 @@ void XdsClient::CancelClusterDataWatch(StringView cluster_name,
|
|
1794
1899
|
cluster_state.watchers.erase(it);
|
1795
1900
|
if (cluster_state.watchers.empty()) {
|
1796
1901
|
cluster_map_.erase(cluster_name_str);
|
1797
|
-
chand_->Unsubscribe(XdsApi::kCdsTypeUrl, cluster_name_str
|
1902
|
+
chand_->Unsubscribe(XdsApi::kCdsTypeUrl, cluster_name_str,
|
1903
|
+
delay_unsubscription);
|
1798
1904
|
}
|
1799
1905
|
}
|
1800
1906
|
}
|
@@ -1808,14 +1914,19 @@ void XdsClient::WatchEndpointData(
|
|
1808
1914
|
endpoint_state.watchers[w] = std::move(watcher);
|
1809
1915
|
// If we've already received an EDS update, notify the new watcher
|
1810
1916
|
// immediately.
|
1811
|
-
if (
|
1812
|
-
|
1917
|
+
if (endpoint_state.update.has_value()) {
|
1918
|
+
if (GRPC_TRACE_FLAG_ENABLED(grpc_xds_client_trace)) {
|
1919
|
+
gpr_log(GPR_INFO, "[xds_client %p] returning cached endpoint data for %s",
|
1920
|
+
this, StringViewToCString(eds_service_name).get());
|
1921
|
+
}
|
1922
|
+
w->OnEndpointChanged(endpoint_state.update.value());
|
1813
1923
|
}
|
1814
1924
|
chand_->Subscribe(XdsApi::kEdsTypeUrl, eds_service_name_str);
|
1815
1925
|
}
|
1816
1926
|
|
1817
1927
|
void XdsClient::CancelEndpointDataWatch(StringView eds_service_name,
|
1818
|
-
EndpointWatcherInterface* watcher
|
1928
|
+
EndpointWatcherInterface* watcher,
|
1929
|
+
bool delay_unsubscription) {
|
1819
1930
|
if (shutting_down_) return;
|
1820
1931
|
std::string eds_service_name_str = std::string(eds_service_name);
|
1821
1932
|
EndpointState& endpoint_state = endpoint_map_[eds_service_name_str];
|
@@ -1824,7 +1935,8 @@ void XdsClient::CancelEndpointDataWatch(StringView eds_service_name,
|
|
1824
1935
|
endpoint_state.watchers.erase(it);
|
1825
1936
|
if (endpoint_state.watchers.empty()) {
|
1826
1937
|
endpoint_map_.erase(eds_service_name_str);
|
1827
|
-
chand_->Unsubscribe(XdsApi::kEdsTypeUrl, eds_service_name_str
|
1938
|
+
chand_->Unsubscribe(XdsApi::kEdsTypeUrl, eds_service_name_str,
|
1939
|
+
delay_unsubscription);
|
1828
1940
|
}
|
1829
1941
|
}
|
1830
1942
|
}
|
@@ -1859,19 +1971,14 @@ void XdsClient::RemoveClusterDropStats(
|
|
1859
1971
|
LoadReportState& load_report_state = load_report_it->second;
|
1860
1972
|
// TODO(roth): When we add support for direct federation, use the
|
1861
1973
|
// server name specified in lrs_server.
|
1862
|
-
// TODO(roth): In principle, we should try to send a final load report
|
1863
|
-
// containing whatever final stats have been accumulated since the
|
1864
|
-
// last load report.
|
1865
1974
|
auto it = load_report_state.drop_stats.find(cluster_drop_stats);
|
1866
1975
|
if (it != load_report_state.drop_stats.end()) {
|
1867
|
-
|
1868
|
-
|
1869
|
-
|
1870
|
-
|
1871
|
-
if (chand_ != nullptr && load_report_map_.empty()) {
|
1872
|
-
chand_->StopLrsCall();
|
1873
|
-
}
|
1976
|
+
// Record final drop stats in deleted_drop_stats, which will be
|
1977
|
+
// added to the next load report.
|
1978
|
+
for (const auto& p : cluster_drop_stats->GetSnapshotAndReset()) {
|
1979
|
+
load_report_state.deleted_drop_stats[p.first] += p.second;
|
1874
1980
|
}
|
1981
|
+
load_report_state.drop_stats.erase(it);
|
1875
1982
|
}
|
1876
1983
|
}
|
1877
1984
|
|
@@ -1892,7 +1999,7 @@ RefCountedPtr<XdsClusterLocalityStats> XdsClient::AddClusterLocalityStats(
|
|
1892
1999
|
Ref(DEBUG_LOCATION, "LocalityStats"), lrs_server,
|
1893
2000
|
it->first.first /*cluster_name*/, it->first.second /*eds_service_name*/,
|
1894
2001
|
locality);
|
1895
|
-
it->second.locality_stats[std::move(locality)].insert(
|
2002
|
+
it->second.locality_stats[std::move(locality)].locality_stats.insert(
|
1896
2003
|
cluster_locality_stats.get());
|
1897
2004
|
chand_->MaybeStartLrsCall();
|
1898
2005
|
return cluster_locality_stats;
|
@@ -1908,25 +2015,16 @@ void XdsClient::RemoveClusterLocalityStats(
|
|
1908
2015
|
LoadReportState& load_report_state = load_report_it->second;
|
1909
2016
|
// TODO(roth): When we add support for direct federation, use the
|
1910
2017
|
// server name specified in lrs_server.
|
1911
|
-
// TODO(roth): In principle, we should try to send a final load report
|
1912
|
-
// containing whatever final stats have been accumulated since the
|
1913
|
-
// last load report.
|
1914
2018
|
auto locality_it = load_report_state.locality_stats.find(locality);
|
1915
2019
|
if (locality_it == load_report_state.locality_stats.end()) return;
|
1916
|
-
auto& locality_set = locality_it->second;
|
2020
|
+
auto& locality_set = locality_it->second.locality_stats;
|
1917
2021
|
auto it = locality_set.find(cluster_locality_stats);
|
1918
2022
|
if (it != locality_set.end()) {
|
2023
|
+
// Record final snapshot in deleted_locality_stats, which will be
|
2024
|
+
// added to the next load report.
|
2025
|
+
locality_it->second.deleted_locality_stats.emplace_back(
|
2026
|
+
cluster_locality_stats->GetSnapshotAndReset());
|
1919
2027
|
locality_set.erase(it);
|
1920
|
-
if (locality_set.empty()) {
|
1921
|
-
load_report_state.locality_stats.erase(locality_it);
|
1922
|
-
if (load_report_state.locality_stats.empty() &&
|
1923
|
-
load_report_state.drop_stats.empty()) {
|
1924
|
-
load_report_map_.erase(load_report_it);
|
1925
|
-
if (chand_ != nullptr && load_report_map_.empty()) {
|
1926
|
-
chand_->StopLrsCall();
|
1927
|
-
}
|
1928
|
-
}
|
1929
|
-
}
|
1930
2028
|
}
|
1931
2029
|
}
|
1932
2030
|
|
@@ -1955,32 +2053,70 @@ grpc_error* XdsClient::CreateServiceConfig(
|
|
1955
2053
|
return error;
|
1956
2054
|
}
|
1957
2055
|
|
1958
|
-
XdsApi::ClusterLoadReportMap XdsClient::BuildLoadReportSnapshot(
|
2056
|
+
XdsApi::ClusterLoadReportMap XdsClient::BuildLoadReportSnapshot(
|
2057
|
+
const std::set<std::string>& clusters) {
|
1959
2058
|
XdsApi::ClusterLoadReportMap snapshot_map;
|
1960
|
-
for (auto
|
1961
|
-
|
1962
|
-
|
1963
|
-
|
2059
|
+
for (auto load_report_it = load_report_map_.begin();
|
2060
|
+
load_report_it != load_report_map_.end();) {
|
2061
|
+
// Cluster key is cluster and EDS service name.
|
2062
|
+
const auto& cluster_key = load_report_it->first;
|
2063
|
+
LoadReportState& load_report = load_report_it->second;
|
2064
|
+
// If the CDS response for a cluster indicates to use LRS but the
|
2065
|
+
// LRS server does not say that it wants reports for this cluster,
|
2066
|
+
// then we'll have stats objects here whose data we're not going to
|
2067
|
+
// include in the load report. However, we still need to clear out
|
2068
|
+
// the data from the stats objects, so that if the LRS server starts
|
2069
|
+
// asking for the data in the future, we don't incorrectly include
|
2070
|
+
// data from previous reporting intervals in that future report.
|
2071
|
+
const bool record_stats =
|
2072
|
+
clusters.find(cluster_key.first) != clusters.end();
|
2073
|
+
XdsApi::ClusterLoadReport snapshot;
|
1964
2074
|
// Aggregate drop stats.
|
2075
|
+
snapshot.dropped_requests = std::move(load_report.deleted_drop_stats);
|
1965
2076
|
for (auto& drop_stats : load_report.drop_stats) {
|
1966
2077
|
for (const auto& p : drop_stats->GetSnapshotAndReset()) {
|
1967
2078
|
snapshot.dropped_requests[p.first] += p.second;
|
1968
2079
|
}
|
1969
2080
|
}
|
1970
2081
|
// Aggregate locality stats.
|
1971
|
-
for (auto
|
1972
|
-
|
1973
|
-
|
2082
|
+
for (auto it = load_report.locality_stats.begin();
|
2083
|
+
it != load_report.locality_stats.end();) {
|
2084
|
+
const RefCountedPtr<XdsLocalityName>& locality_name = it->first;
|
2085
|
+
auto& locality_state = it->second;
|
1974
2086
|
XdsClusterLocalityStats::Snapshot& locality_snapshot =
|
1975
2087
|
snapshot.locality_stats[locality_name];
|
1976
|
-
for (auto& locality_stats :
|
2088
|
+
for (auto& locality_stats : locality_state.locality_stats) {
|
1977
2089
|
locality_snapshot += locality_stats->GetSnapshotAndReset();
|
1978
2090
|
}
|
2091
|
+
// Add final snapshots from recently deleted locality stats objects.
|
2092
|
+
for (auto& deleted_locality_stats :
|
2093
|
+
locality_state.deleted_locality_stats) {
|
2094
|
+
locality_snapshot += deleted_locality_stats;
|
2095
|
+
}
|
2096
|
+
locality_state.deleted_locality_stats.clear();
|
2097
|
+
// If the only thing left in this entry was final snapshots from
|
2098
|
+
// deleted locality stats objects, remove the entry.
|
2099
|
+
if (locality_state.locality_stats.empty()) {
|
2100
|
+
it = load_report.locality_stats.erase(it);
|
2101
|
+
} else {
|
2102
|
+
++it;
|
2103
|
+
}
|
2104
|
+
}
|
2105
|
+
if (record_stats) {
|
2106
|
+
// Compute load report interval.
|
2107
|
+
const grpc_millis now = ExecCtx::Get()->Now();
|
2108
|
+
snapshot.load_report_interval = now - load_report.last_report_time;
|
2109
|
+
load_report.last_report_time = now;
|
2110
|
+
// Record snapshot.
|
2111
|
+
snapshot_map[cluster_key] = std::move(snapshot);
|
2112
|
+
}
|
2113
|
+
// If the only thing left in this entry was final snapshots from
|
2114
|
+
// deleted stats objects, remove the entry.
|
2115
|
+
if (load_report.locality_stats.empty() && load_report.drop_stats.empty()) {
|
2116
|
+
load_report_it = load_report_map_.erase(load_report_it);
|
2117
|
+
} else {
|
2118
|
+
++load_report_it;
|
1979
2119
|
}
|
1980
|
-
// Compute load report interval.
|
1981
|
-
const grpc_millis now = ExecCtx::Get()->Now();
|
1982
|
-
snapshot.load_report_interval = now - load_report.last_report_time;
|
1983
|
-
load_report.last_report_time = now;
|
1984
2120
|
}
|
1985
2121
|
return snapshot_map;
|
1986
2122
|
}
|