Skip to content

Commit 6866bf3

Browse files
committed
Implement ignore_resource_deletion resource handling logic
1 parent 54c4b19 commit 6866bf3

File tree

1 file changed

+70
-30
lines changed

1 file changed

+70
-30
lines changed

xds/src/main/java/io/grpc/xds/ClientXdsClient.java

+70-30
Original file line numberDiff line numberDiff line change
@@ -2156,8 +2156,7 @@ public void run() {
21562156
ResourceSubscriber subscriber = ldsResourceSubscribers.get(resourceName);
21572157
subscriber.removeWatcher(watcher);
21582158
if (!subscriber.isWatched()) {
2159-
subscriber.stopTimer();
2160-
logger.log(XdsLogLevel.INFO, "Unsubscribe LDS resource {0}", resourceName);
2159+
subscriber.cancelResourceWatch();
21612160
ldsResourceSubscribers.remove(resourceName);
21622161
if (subscriber.xdsChannel != null) {
21632162
subscriber.xdsChannel.adjustResourceSubscription(ResourceType.LDS);
@@ -2194,8 +2193,7 @@ public void run() {
21942193
ResourceSubscriber subscriber = rdsResourceSubscribers.get(resourceName);
21952194
subscriber.removeWatcher(watcher);
21962195
if (!subscriber.isWatched()) {
2197-
subscriber.stopTimer();
2198-
logger.log(XdsLogLevel.INFO, "Unsubscribe RDS resource {0}", resourceName);
2196+
subscriber.cancelResourceWatch();
21992197
rdsResourceSubscribers.remove(resourceName);
22002198
if (subscriber.xdsChannel != null) {
22012199
subscriber.xdsChannel.adjustResourceSubscription(ResourceType.RDS);
@@ -2232,8 +2230,7 @@ public void run() {
22322230
ResourceSubscriber subscriber = cdsResourceSubscribers.get(resourceName);
22332231
subscriber.removeWatcher(watcher);
22342232
if (!subscriber.isWatched()) {
2235-
subscriber.stopTimer();
2236-
logger.log(XdsLogLevel.INFO, "Unsubscribe CDS resource {0}", resourceName);
2233+
subscriber.cancelResourceWatch();
22372234
cdsResourceSubscribers.remove(resourceName);
22382235
if (subscriber.xdsChannel != null) {
22392236
subscriber.xdsChannel.adjustResourceSubscription(ResourceType.CDS);
@@ -2270,8 +2267,7 @@ public void run() {
22702267
ResourceSubscriber subscriber = edsResourceSubscribers.get(resourceName);
22712268
subscriber.removeWatcher(watcher);
22722269
if (!subscriber.isWatched()) {
2273-
subscriber.stopTimer();
2274-
logger.log(XdsLogLevel.INFO, "Unsubscribe EDS resource {0}", resourceName);
2270+
subscriber.cancelResourceWatch();
22752271
edsResourceSubscribers.remove(resourceName);
22762272
if (subscriber.xdsChannel != null) {
22772273
subscriber.xdsChannel.adjustResourceSubscription(ResourceType.EDS);
@@ -2320,7 +2316,7 @@ public void run() {
23202316
Bootstrapper.BootstrapInfo getBootstrapInfo() {
23212317
return bootstrapInfo;
23222318
}
2323-
2319+
23242320
@Override
23252321
public String toString() {
23262322
return logId.toString();
@@ -2370,29 +2366,17 @@ private void handleResourceUpdate(
23702366
} else if (type == ResourceType.LDS || type == ResourceType.CDS) {
23712367
if (subscriber.data != null && invalidResources.contains(resourceName)) {
23722368
// Update is rejected but keep using the cached data.
2373-
if (type == ResourceType.LDS) {
2374-
LdsUpdate ldsUpdate = (LdsUpdate) subscriber.data;
2375-
io.grpc.xds.HttpConnectionManager hcm = ldsUpdate.httpConnectionManager();
2376-
if (hcm != null) {
2377-
String rdsName = hcm.rdsName();
2378-
if (rdsName != null) {
2379-
retainedResources.add(rdsName);
2380-
}
2381-
}
2382-
} else {
2383-
CdsUpdate cdsUpdate = (CdsUpdate) subscriber.data;
2384-
String edsName = cdsUpdate.edsServiceName();
2385-
if (edsName == null) {
2386-
edsName = cdsUpdate.clusterName();
2387-
}
2388-
retainedResources.add(edsName);
2389-
}
2369+
retainDependentResource(subscriber, retainedResources);
23902370
} else if (invalidResources.contains(resourceName)) {
23912371
subscriber.onError(Status.UNAVAILABLE.withDescription(errorDetail));
23922372
} else {
23932373
// For State of the World services, notify watchers when their watched resource is missing
23942374
// from the ADS update.
23952375
subscriber.onAbsent();
2376+
// Retain any dependent resources if the resource deletion is ignored per server setting.
2377+
if (!subscriber.absent) {
2378+
retainDependentResource(subscriber, retainedResources);
2379+
}
23962380
}
23972381
}
23982382
}
@@ -2409,6 +2393,28 @@ private void handleResourceUpdate(
24092393
}
24102394
}
24112395

2396+
private void retainDependentResource(
2397+
ResourceSubscriber subscriber, Set<String> retainedResources) {
2398+
if (subscriber.data == null) {
2399+
return;
2400+
}
2401+
String resourceName = null;
2402+
if (subscriber.type == ResourceType.LDS) {
2403+
LdsUpdate ldsUpdate = (LdsUpdate) subscriber.data;
2404+
io.grpc.xds.HttpConnectionManager hcm = ldsUpdate.httpConnectionManager();
2405+
if (hcm != null) {
2406+
resourceName = hcm.rdsName();
2407+
}
2408+
} else if (subscriber.type == ResourceType.CDS) {
2409+
CdsUpdate cdsUpdate = (CdsUpdate) subscriber.data;
2410+
resourceName = cdsUpdate.edsServiceName();
2411+
}
2412+
2413+
if (resourceName != null) {
2414+
retainedResources.add(resourceName);
2415+
}
2416+
}
2417+
24122418
private static final class ParsedResource {
24132419
private final ResourceUpdate resourceUpdate;
24142420
private final Any rawResource;
@@ -2431,15 +2437,18 @@ private Any getRawResource() {
24312437
* Tracks a single subscribed resource.
24322438
*/
24332439
private final class ResourceSubscriber {
2434-
private final ServerInfo serverInfo;
2440+
@Nullable private final ServerInfo serverInfo;
24352441
@Nullable private final AbstractXdsClient xdsChannel;
24362442
private final ResourceType type;
24372443
private final String resource;
24382444
private final Set<ResourceWatcher> watchers = new HashSet<>();
2439-
private ResourceUpdate data;
2445+
@Nullable private ResourceUpdate data;
24402446
private boolean absent;
2441-
private ScheduledHandle respTimer;
2442-
private ResourceMetadata metadata;
2447+
// Tracks whether the deletion has been ignored per server request.
2448+
// See https://github.com/grpc/proposal/blob/master/A53-xds-ignore-resource-deletion.md
2449+
private boolean resourceDeletionIgnored;
2450+
@Nullable private ScheduledHandle respTimer;
2451+
@Nullable private ResourceMetadata metadata;
24432452
@Nullable private String errorDescription;
24442453

24452454
ResourceSubscriber(ResourceType type, String resource) {
@@ -2533,6 +2542,19 @@ void stopTimer() {
25332542
}
25342543
}
25352544

2545+
void cancelResourceWatch() {
2546+
if (isWatched()) {
2547+
throw new IllegalStateException("Can't cancel resource watch with active watchers present");
2548+
}
2549+
stopTimer();
2550+
String message = "Unsubscribing {0} resource {1} from server {2}";
2551+
if (resourceDeletionIgnored) {
2552+
message += " for which we previously ignored a deletion";
2553+
}
2554+
logger.log(XdsLogLevel.INFO, message, type, resource,
2555+
serverInfo != null ? serverInfo.target() : "unknown");
2556+
}
2557+
25362558
boolean isWatched() {
25372559
return !watchers.isEmpty();
25382560
}
@@ -2547,6 +2569,12 @@ void onData(ParsedResource parsedResource, String version, long updateTime) {
25472569
ResourceUpdate oldData = this.data;
25482570
this.data = parsedResource.getResourceUpdate();
25492571
absent = false;
2572+
if (resourceDeletionIgnored) {
2573+
logger.log(XdsLogLevel.INFO, "xds server {0}: server returned new version of resource "
2574+
+ "for which we previously ignored a deletion: type {1} name {2}",
2575+
serverInfo != null ? serverInfo.target() : "unknown", type, resource);
2576+
resourceDeletionIgnored = false;
2577+
}
25502578
if (!Objects.equals(oldData, data)) {
25512579
for (ResourceWatcher watcher : watchers) {
25522580
notifyWatcher(watcher, data);
@@ -2558,6 +2586,18 @@ void onAbsent() {
25582586
if (respTimer != null && respTimer.isPending()) { // too early to conclude absence
25592587
return;
25602588
}
2589+
2590+
// Ignore deletion when the server instructs to, and the resource is reusable.
2591+
if (data != null && serverInfo != null && serverInfo.ignoreResourceDeletion()) {
2592+
if (!resourceDeletionIgnored) {
2593+
logger.log(XdsLogLevel.WARNING,
2594+
"xds server {0}: ignoring deletion for resource type {1} name {2}}",
2595+
serverInfo.target(), type, resource);
2596+
resourceDeletionIgnored = true;
2597+
}
2598+
return;
2599+
}
2600+
25612601
logger.log(XdsLogLevel.INFO, "Conclude {0} resource {1} not exist", type, resource);
25622602
if (!absent) {
25632603
data = null;

0 commit comments

Comments
 (0)