/
XdsClient.java
719 lines (616 loc) · 24.5 KB
/
XdsClient.java
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
373
374
375
376
377
378
379
380
381
382
383
384
385
386
387
388
389
390
391
392
393
394
395
396
397
398
399
400
401
402
403
404
405
406
407
408
409
410
411
412
413
414
415
416
417
418
419
420
421
422
423
424
425
426
427
428
429
430
431
432
433
434
435
436
437
438
439
440
441
442
443
444
445
446
447
448
449
450
451
452
453
454
455
456
457
458
459
460
461
462
463
464
465
466
467
468
469
470
471
472
473
474
475
476
477
478
479
480
481
482
483
484
485
486
487
488
489
490
491
492
493
494
495
496
497
498
499
500
501
502
503
504
505
506
507
508
509
510
511
512
513
514
515
516
517
518
519
520
521
522
523
524
525
526
527
528
529
530
531
532
533
534
535
536
537
538
539
540
541
542
543
544
545
546
547
548
549
550
551
552
553
554
555
556
557
558
559
560
561
562
563
564
565
566
567
568
569
570
571
572
573
574
575
576
577
578
579
580
581
582
583
584
585
586
587
588
589
590
591
592
593
594
595
596
597
598
599
600
601
602
603
604
605
606
607
608
609
610
611
612
613
614
615
616
617
618
619
620
621
622
623
624
625
626
627
628
629
630
631
632
633
634
635
636
637
638
639
640
641
642
643
644
645
646
647
648
649
650
651
652
653
654
655
656
657
658
659
660
661
662
663
664
665
666
667
668
669
670
671
672
673
674
675
676
677
678
679
680
681
682
683
684
685
686
687
688
689
690
691
692
693
694
695
696
697
698
699
700
701
702
703
704
705
706
707
708
709
710
711
712
713
714
715
716
717
718
719
/*
* Copyright 2019 The gRPC Authors
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package io.grpc.xds;
import static com.google.common.base.Preconditions.checkNotNull;
import static io.grpc.xds.Bootstrapper.XDSTP_SCHEME;
import com.google.auto.value.AutoValue;
import com.google.common.base.Joiner;
import com.google.common.base.MoreObjects;
import com.google.common.base.Splitter;
import com.google.common.collect.ImmutableList;
import com.google.common.net.UrlEscapers;
import com.google.common.util.concurrent.ListenableFuture;
import com.google.protobuf.Any;
import io.grpc.Status;
import io.grpc.xds.AbstractXdsClient.ResourceType;
import io.grpc.xds.Bootstrapper.ServerInfo;
import io.grpc.xds.Endpoints.DropOverload;
import io.grpc.xds.Endpoints.LocalityLbEndpoints;
import io.grpc.xds.EnvoyServerProtoData.Listener;
import io.grpc.xds.EnvoyServerProtoData.UpstreamTlsContext;
import io.grpc.xds.LoadStatsManager2.ClusterDropStats;
import io.grpc.xds.LoadStatsManager2.ClusterLocalityStats;
import java.net.URI;
import java.net.URISyntaxException;
import java.util.ArrayList;
import java.util.Collection;
import java.util.Collections;
import java.util.LinkedHashMap;
import java.util.List;
import java.util.Map;
import java.util.Objects;
import javax.annotation.Nullable;
/**
* An {@link XdsClient} instance encapsulates all of the logic for communicating with the xDS
* server. It may create multiple RPC streams (or a single ADS stream) for a series of xDS
* protocols (e.g., LDS, RDS, VHDS, CDS and EDS) over a single channel. Watch-based interfaces
* are provided for each set of data needed by gRPC.
*/
abstract class XdsClient {
static boolean isResourceNameValid(String resourceName, String typeUrl) {
checkNotNull(resourceName, "resourceName");
if (!resourceName.startsWith(XDSTP_SCHEME)) {
return true;
}
URI uri;
try {
uri = new URI(resourceName);
} catch (URISyntaxException e) {
return false;
}
String path = uri.getPath();
// path must be in the form of /{resource type}/{id/*}
Splitter slashSplitter = Splitter.on('/').omitEmptyStrings();
if (path == null) {
return false;
}
List<String> pathSegs = slashSplitter.splitToList(path);
if (pathSegs.size() < 2) {
return false;
}
String type = pathSegs.get(0);
if (!type.equals(slashSplitter.splitToList(typeUrl).get(1))) {
return false;
}
return true;
}
static String canonifyResourceName(String resourceName) {
checkNotNull(resourceName, "resourceName");
if (!resourceName.startsWith(XDSTP_SCHEME)) {
return resourceName;
}
URI uri = URI.create(resourceName);
String rawQuery = uri.getRawQuery();
Splitter ampSplitter = Splitter.on('&').omitEmptyStrings();
if (rawQuery == null) {
return resourceName;
}
List<String> queries = ampSplitter.splitToList(rawQuery);
if (queries.size() < 2) {
return resourceName;
}
List<String> canonicalContextParams = new ArrayList<>(queries.size());
for (String query : queries) {
canonicalContextParams.add(query);
}
Collections.sort(canonicalContextParams);
String canonifiedQuery = Joiner.on('&').join(canonicalContextParams);
return resourceName.replace(rawQuery, canonifiedQuery);
}
static String percentEncodePath(String input) {
Iterable<String> pathSegs = Splitter.on('/').split(input);
List<String> encodedSegs = new ArrayList<>();
for (String pathSeg : pathSegs) {
encodedSegs.add(UrlEscapers.urlPathSegmentEscaper().escape(pathSeg));
}
return Joiner.on('/').join(encodedSegs);
}
@AutoValue
abstract static class LdsUpdate implements ResourceUpdate {
// Http level api listener configuration.
@Nullable
abstract HttpConnectionManager httpConnectionManager();
// Tcp level listener configuration.
@Nullable
abstract Listener listener();
static LdsUpdate forApiListener(HttpConnectionManager httpConnectionManager) {
checkNotNull(httpConnectionManager, "httpConnectionManager");
return new AutoValue_XdsClient_LdsUpdate(httpConnectionManager, null);
}
static LdsUpdate forTcpListener(Listener listener) {
checkNotNull(listener, "listener");
return new AutoValue_XdsClient_LdsUpdate(null, listener);
}
}
static final class RdsUpdate implements ResourceUpdate {
// The list virtual hosts that make up the route table.
final List<VirtualHost> virtualHosts;
RdsUpdate(List<VirtualHost> virtualHosts) {
this.virtualHosts = Collections.unmodifiableList(
new ArrayList<>(checkNotNull(virtualHosts, "virtualHosts")));
}
@Override
public String toString() {
return MoreObjects.toStringHelper(this)
.add("virtualHosts", virtualHosts)
.toString();
}
@Override
public int hashCode() {
return Objects.hash(virtualHosts);
}
@Override
public boolean equals(Object o) {
if (this == o) {
return true;
}
if (o == null || getClass() != o.getClass()) {
return false;
}
RdsUpdate that = (RdsUpdate) o;
return Objects.equals(virtualHosts, that.virtualHosts);
}
}
/** xDS resource update for cluster-level configuration. */
@AutoValue
abstract static class CdsUpdate implements ResourceUpdate {
abstract String clusterName();
abstract ClusterType clusterType();
// Endpoint-level load balancing policy.
abstract LbPolicy lbPolicy();
// Only valid if lbPolicy is "ring_hash_experimental".
abstract long minRingSize();
// Only valid if lbPolicy is "ring_hash_experimental".
abstract long maxRingSize();
// Only valid if lbPolicy is "least_request_experimental".
abstract int choiceCount();
// Alternative resource name to be used in EDS requests.
/// Only valid for EDS cluster.
@Nullable
abstract String edsServiceName();
// Corresponding DNS name to be used if upstream endpoints of the cluster is resolvable
// via DNS.
// Only valid for LOGICAL_DNS cluster.
@Nullable
abstract String dnsHostName();
// Load report server info for reporting loads via LRS.
// Only valid for EDS or LOGICAL_DNS cluster.
@Nullable
abstract ServerInfo lrsServerInfo();
// Max number of concurrent requests can be sent to this cluster.
// Only valid for EDS or LOGICAL_DNS cluster.
@Nullable
abstract Long maxConcurrentRequests();
// TLS context used to connect to connect to this cluster.
// Only valid for EDS or LOGICAL_DNS cluster.
@Nullable
abstract UpstreamTlsContext upstreamTlsContext();
// List of underlying clusters making of this aggregate cluster.
// Only valid for AGGREGATE cluster.
@Nullable
abstract ImmutableList<String> prioritizedClusterNames();
static Builder forAggregate(String clusterName, List<String> prioritizedClusterNames) {
checkNotNull(prioritizedClusterNames, "prioritizedClusterNames");
return new AutoValue_XdsClient_CdsUpdate.Builder()
.clusterName(clusterName)
.clusterType(ClusterType.AGGREGATE)
.minRingSize(0)
.maxRingSize(0)
.choiceCount(0)
.prioritizedClusterNames(ImmutableList.copyOf(prioritizedClusterNames));
}
static Builder forEds(String clusterName, @Nullable String edsServiceName,
@Nullable ServerInfo lrsServerInfo, @Nullable Long maxConcurrentRequests,
@Nullable UpstreamTlsContext upstreamTlsContext) {
return new AutoValue_XdsClient_CdsUpdate.Builder()
.clusterName(clusterName)
.clusterType(ClusterType.EDS)
.minRingSize(0)
.maxRingSize(0)
.choiceCount(0)
.edsServiceName(edsServiceName)
.lrsServerInfo(lrsServerInfo)
.maxConcurrentRequests(maxConcurrentRequests)
.upstreamTlsContext(upstreamTlsContext);
}
static Builder forLogicalDns(String clusterName, String dnsHostName,
@Nullable ServerInfo lrsServerInfo, @Nullable Long maxConcurrentRequests,
@Nullable UpstreamTlsContext upstreamTlsContext) {
return new AutoValue_XdsClient_CdsUpdate.Builder()
.clusterName(clusterName)
.clusterType(ClusterType.LOGICAL_DNS)
.minRingSize(0)
.maxRingSize(0)
.choiceCount(0)
.dnsHostName(dnsHostName)
.lrsServerInfo(lrsServerInfo)
.maxConcurrentRequests(maxConcurrentRequests)
.upstreamTlsContext(upstreamTlsContext);
}
enum ClusterType {
EDS, LOGICAL_DNS, AGGREGATE
}
enum LbPolicy {
ROUND_ROBIN, RING_HASH, LEAST_REQUEST
}
// FIXME(chengyuanzhang): delete this after UpstreamTlsContext's toString() is fixed.
@Override
public final String toString() {
return MoreObjects.toStringHelper(this)
.add("clusterName", clusterName())
.add("clusterType", clusterType())
.add("lbPolicy", lbPolicy())
.add("minRingSize", minRingSize())
.add("maxRingSize", maxRingSize())
.add("choiceCount", choiceCount())
.add("edsServiceName", edsServiceName())
.add("dnsHostName", dnsHostName())
.add("lrsServerInfo", lrsServerInfo())
.add("maxConcurrentRequests", maxConcurrentRequests())
// Exclude upstreamTlsContext as its string representation is cumbersome.
.add("prioritizedClusterNames", prioritizedClusterNames())
.toString();
}
@AutoValue.Builder
abstract static class Builder {
// Private, use one of the static factory methods instead.
protected abstract Builder clusterName(String clusterName);
// Private, use one of the static factory methods instead.
protected abstract Builder clusterType(ClusterType clusterType);
// Private, use roundRobinLbPolicy() or ringHashLbPolicy(long, long).
protected abstract Builder lbPolicy(LbPolicy lbPolicy);
Builder roundRobinLbPolicy() {
return this.lbPolicy(LbPolicy.ROUND_ROBIN);
}
Builder ringHashLbPolicy(long minRingSize, long maxRingSize) {
return this.lbPolicy(LbPolicy.RING_HASH).minRingSize(minRingSize).maxRingSize(maxRingSize);
}
Builder leastRequestLbPolicy(int choiceCount) {
return this.lbPolicy(LbPolicy.LEAST_REQUEST).choiceCount(choiceCount);
}
// Private, use leastRequestLbPolicy(int).
protected abstract Builder choiceCount(int choiceCount);
// Private, use ringHashLbPolicy(long, long).
protected abstract Builder minRingSize(long minRingSize);
// Private, use ringHashLbPolicy(long, long).
protected abstract Builder maxRingSize(long maxRingSize);
// Private, use CdsUpdate.forEds() instead.
protected abstract Builder edsServiceName(String edsServiceName);
// Private, use CdsUpdate.forLogicalDns() instead.
protected abstract Builder dnsHostName(String dnsHostName);
// Private, use one of the static factory methods instead.
protected abstract Builder lrsServerInfo(ServerInfo lrsServerInfo);
// Private, use one of the static factory methods instead.
protected abstract Builder maxConcurrentRequests(Long maxConcurrentRequests);
// Private, use one of the static factory methods instead.
protected abstract Builder upstreamTlsContext(UpstreamTlsContext upstreamTlsContext);
// Private, use CdsUpdate.forAggregate() instead.
protected abstract Builder prioritizedClusterNames(List<String> prioritizedClusterNames);
abstract CdsUpdate build();
}
}
static final class EdsUpdate implements ResourceUpdate {
final String clusterName;
final Map<Locality, LocalityLbEndpoints> localityLbEndpointsMap;
final List<DropOverload> dropPolicies;
EdsUpdate(String clusterName, Map<Locality, LocalityLbEndpoints> localityLbEndpoints,
List<DropOverload> dropPolicies) {
this.clusterName = checkNotNull(clusterName, "clusterName");
this.localityLbEndpointsMap = Collections.unmodifiableMap(
new LinkedHashMap<>(checkNotNull(localityLbEndpoints, "localityLbEndpoints")));
this.dropPolicies = Collections.unmodifiableList(
new ArrayList<>(checkNotNull(dropPolicies, "dropPolicies")));
}
@Override
public boolean equals(Object o) {
if (this == o) {
return true;
}
if (o == null || getClass() != o.getClass()) {
return false;
}
EdsUpdate that = (EdsUpdate) o;
return Objects.equals(clusterName, that.clusterName)
&& Objects.equals(localityLbEndpointsMap, that.localityLbEndpointsMap)
&& Objects.equals(dropPolicies, that.dropPolicies);
}
@Override
public int hashCode() {
return Objects.hash(clusterName, localityLbEndpointsMap, dropPolicies);
}
@Override
public String toString() {
return
MoreObjects
.toStringHelper(this)
.add("clusterName", clusterName)
.add("localityLbEndpointsMap", localityLbEndpointsMap)
.add("dropPolicies", dropPolicies)
.toString();
}
}
interface ResourceUpdate {
}
/**
* Watcher interface for a single requested xDS resource.
*/
interface ResourceWatcher {
/**
* Called when the resource discovery RPC encounters some transient error.
*
* <p>Note that we expect that the implementer to:
* - Comply with the guarantee to not generate certain statuses by the library:
* https://grpc.github.io/grpc/core/md_doc_statuscodes.html. If the code needs to be
* propagated to the channel, override it with {@link Status.Code#UNAVAILABLE}.
* - Keep {@link Status} description in one form or another, as it contains valuable debugging
* information.
*/
void onError(Status error);
/**
* Called when the requested resource is not available.
*
* @param resourceName name of the resource requested in discovery request.
*/
void onResourceDoesNotExist(String resourceName);
}
interface LdsResourceWatcher extends ResourceWatcher {
void onChanged(LdsUpdate update);
}
interface RdsResourceWatcher extends ResourceWatcher {
void onChanged(RdsUpdate update);
}
interface CdsResourceWatcher extends ResourceWatcher {
void onChanged(CdsUpdate update);
}
interface EdsResourceWatcher extends ResourceWatcher {
void onChanged(EdsUpdate update);
}
/**
* The metadata of the xDS resource; used by the xDS config dump.
*/
static final class ResourceMetadata {
private final String version;
private final ResourceMetadataStatus status;
private final long updateTimeNanos;
@Nullable private final Any rawResource;
@Nullable private final UpdateFailureState errorState;
private ResourceMetadata(
ResourceMetadataStatus status, String version, long updateTimeNanos,
@Nullable Any rawResource, @Nullable UpdateFailureState errorState) {
this.status = checkNotNull(status, "status");
this.version = checkNotNull(version, "version");
this.updateTimeNanos = updateTimeNanos;
this.rawResource = rawResource;
this.errorState = errorState;
}
static ResourceMetadata newResourceMetadataUnknown() {
return new ResourceMetadata(ResourceMetadataStatus.UNKNOWN, "", 0, null, null);
}
static ResourceMetadata newResourceMetadataRequested() {
return new ResourceMetadata(ResourceMetadataStatus.REQUESTED, "", 0, null, null);
}
static ResourceMetadata newResourceMetadataDoesNotExist() {
return new ResourceMetadata(ResourceMetadataStatus.DOES_NOT_EXIST, "", 0, null, null);
}
static ResourceMetadata newResourceMetadataAcked(
Any rawResource, String version, long updateTimeNanos) {
checkNotNull(rawResource, "rawResource");
return new ResourceMetadata(
ResourceMetadataStatus.ACKED, version, updateTimeNanos, rawResource, null);
}
static ResourceMetadata newResourceMetadataNacked(
ResourceMetadata metadata, String failedVersion, long failedUpdateTime,
String failedDetails) {
checkNotNull(metadata, "metadata");
return new ResourceMetadata(ResourceMetadataStatus.NACKED,
metadata.getVersion(), metadata.getUpdateTimeNanos(), metadata.getRawResource(),
new UpdateFailureState(failedVersion, failedUpdateTime, failedDetails));
}
/** The last successfully updated version of the resource. */
String getVersion() {
return version;
}
/** The client status of this resource. */
ResourceMetadataStatus getStatus() {
return status;
}
/** The timestamp when the resource was last successfully updated. */
long getUpdateTimeNanos() {
return updateTimeNanos;
}
/** The last successfully updated xDS resource as it was returned by the server. */
@Nullable
Any getRawResource() {
return rawResource;
}
/** The metadata capturing the error details of the last rejected update of the resource. */
@Nullable
UpdateFailureState getErrorState() {
return errorState;
}
/**
* Resource status from the view of a xDS client, which tells the synchronization
* status between the xDS client and the xDS server.
*
* <p>This is a native representation of xDS ConfigDump ClientResourceStatus, see
* <a href="https://github.com/envoyproxy/envoy/blob/main/api/envoy/admin/v3/config_dump.proto">
* config_dump.proto</a>
*/
enum ResourceMetadataStatus {
UNKNOWN, REQUESTED, DOES_NOT_EXIST, ACKED, NACKED
}
/**
* Captures error metadata of failed resource updates.
*
* <p>This is a native representation of xDS ConfigDump UpdateFailureState, see
* <a href="https://github.com/envoyproxy/envoy/blob/main/api/envoy/admin/v3/config_dump.proto">
* config_dump.proto</a>
*/
static final class UpdateFailureState {
private final String failedVersion;
private final long failedUpdateTimeNanos;
private final String failedDetails;
private UpdateFailureState(
String failedVersion, long failedUpdateTimeNanos, String failedDetails) {
this.failedVersion = checkNotNull(failedVersion, "failedVersion");
this.failedUpdateTimeNanos = failedUpdateTimeNanos;
this.failedDetails = checkNotNull(failedDetails, "failedDetails");
}
/** The rejected version string of the last failed update attempt. */
String getFailedVersion() {
return failedVersion;
}
/** Details about the last failed update attempt. */
long getFailedUpdateTimeNanos() {
return failedUpdateTimeNanos;
}
/** Timestamp of the last failed update attempt. */
String getFailedDetails() {
return failedDetails;
}
}
}
/**
* Shutdown this {@link XdsClient} and release resources.
*/
void shutdown() {
throw new UnsupportedOperationException();
}
/**
* Returns {@code true} if {@link #shutdown()} has been called.
*/
boolean isShutDown() {
throw new UnsupportedOperationException();
}
/**
* Returns the config used to bootstrap this XdsClient {@link Bootstrapper.BootstrapInfo}.
*/
Bootstrapper.BootstrapInfo getBootstrapInfo() {
throw new UnsupportedOperationException();
}
/**
* Returns the {@link TlsContextManager} used in this XdsClient.
*/
TlsContextManager getTlsContextManager() {
throw new UnsupportedOperationException();
}
/**
* Returns a {@link ListenableFuture} to the snapshot of the subscribed resources as
* they are at the moment of the call.
*
* <p>The snapshot is a map from the "resource type" to
* a map ("resource name": "resource metadata").
*/
// Must be synchronized.
ListenableFuture<Map<ResourceType, Map<String, ResourceMetadata>>>
getSubscribedResourcesMetadataSnapshot() {
throw new UnsupportedOperationException();
}
/**
* Registers a data watcher for the given LDS resource.
*/
void watchLdsResource(String resourceName, LdsResourceWatcher watcher) {
throw new UnsupportedOperationException();
}
/**
* Unregisters the given LDS resource watcher.
*/
void cancelLdsResourceWatch(String resourceName, LdsResourceWatcher watcher) {
throw new UnsupportedOperationException();
}
/**
* Registers a data watcher for the given RDS resource.
*/
void watchRdsResource(String resourceName, RdsResourceWatcher watcher) {
throw new UnsupportedOperationException();
}
/**
* Unregisters the given RDS resource watcher.
*/
void cancelRdsResourceWatch(String resourceName, RdsResourceWatcher watcher) {
throw new UnsupportedOperationException();
}
/**
* Registers a data watcher for the given CDS resource.
*/
void watchCdsResource(String resourceName, CdsResourceWatcher watcher) {
throw new UnsupportedOperationException();
}
/**
* Unregisters the given CDS resource watcher.
*/
void cancelCdsResourceWatch(String resourceName, CdsResourceWatcher watcher) {
throw new UnsupportedOperationException();
}
/**
* Registers a data watcher for the given EDS resource.
*/
void watchEdsResource(String resourceName, EdsResourceWatcher watcher) {
throw new UnsupportedOperationException();
}
/**
* Unregisters the given EDS resource watcher.
*/
void cancelEdsResourceWatch(String resourceName, EdsResourceWatcher watcher) {
throw new UnsupportedOperationException();
}
/**
* Adds drop stats for the specified cluster with edsServiceName by using the returned object
* to record dropped requests. Drop stats recorded with the returned object will be reported
* to the load reporting server. The returned object is reference counted and the caller should
* use {@link ClusterDropStats#release} to release its <i>hard</i> reference when it is safe to
* stop reporting dropped RPCs for the specified cluster in the future.
*/
ClusterDropStats addClusterDropStats(
ServerInfo serverInfo, String clusterName, @Nullable String edsServiceName) {
throw new UnsupportedOperationException();
}
/**
* Adds load stats for the specified locality (in the specified cluster with edsServiceName) by
* using the returned object to record RPCs. Load stats recorded with the returned object will
* be reported to the load reporting server. The returned object is reference counted and the
* caller should use {@link ClusterLocalityStats#release} to release its <i>hard</i>
* reference when it is safe to stop reporting RPC loads for the specified locality in the
* future.
*/
ClusterLocalityStats addClusterLocalityStats(
ServerInfo serverInfo, String clusterName, @Nullable String edsServiceName,
Locality locality) {
throw new UnsupportedOperationException();
}
interface XdsResponseHandler {
/** Called when an LDS response is received. */
void handleLdsResponse(
ServerInfo serverInfo, String versionInfo, List<Any> resources, String nonce);
/** Called when an RDS response is received. */
void handleRdsResponse(
ServerInfo serverInfo, String versionInfo, List<Any> resources, String nonce);
/** Called when an CDS response is received. */
void handleCdsResponse(
ServerInfo serverInfo, String versionInfo, List<Any> resources, String nonce);
/** Called when an EDS response is received. */
void handleEdsResponse(
ServerInfo serverInfo, String versionInfo, List<Any> resources, String nonce);
/** Called when the ADS stream is closed passively. */
// Must be synchronized.
void handleStreamClosed(Status error);
/** Called when the ADS stream has been recreated. */
// Must be synchronized.
void handleStreamRestarted(ServerInfo serverInfo);
}
interface ResourceStore {
/**
* Returns the collection of resources currently subscribing to or {@code null} if not
* subscribing to any resources for the given type.
*
* <p>Note an empty collection indicates subscribing to resources of the given type with
* wildcard mode.
*/
// Must be synchronized.
@Nullable
Collection<String> getSubscribedResources(ServerInfo serverInfo, ResourceType type);
}
}