@@ -2156,8 +2156,7 @@ public void run() {
2156
2156
ResourceSubscriber subscriber = ldsResourceSubscribers .get (resourceName );
2157
2157
subscriber .removeWatcher (watcher );
2158
2158
if (!subscriber .isWatched ()) {
2159
- subscriber .stopTimer ();
2160
- logger .log (XdsLogLevel .INFO , "Unsubscribe LDS resource {0}" , resourceName );
2159
+ subscriber .cancelResourceWatch ();
2161
2160
ldsResourceSubscribers .remove (resourceName );
2162
2161
if (subscriber .xdsChannel != null ) {
2163
2162
subscriber .xdsChannel .adjustResourceSubscription (ResourceType .LDS );
@@ -2194,8 +2193,7 @@ public void run() {
2194
2193
ResourceSubscriber subscriber = rdsResourceSubscribers .get (resourceName );
2195
2194
subscriber .removeWatcher (watcher );
2196
2195
if (!subscriber .isWatched ()) {
2197
- subscriber .stopTimer ();
2198
- logger .log (XdsLogLevel .INFO , "Unsubscribe RDS resource {0}" , resourceName );
2196
+ subscriber .cancelResourceWatch ();
2199
2197
rdsResourceSubscribers .remove (resourceName );
2200
2198
if (subscriber .xdsChannel != null ) {
2201
2199
subscriber .xdsChannel .adjustResourceSubscription (ResourceType .RDS );
@@ -2232,8 +2230,7 @@ public void run() {
2232
2230
ResourceSubscriber subscriber = cdsResourceSubscribers .get (resourceName );
2233
2231
subscriber .removeWatcher (watcher );
2234
2232
if (!subscriber .isWatched ()) {
2235
- subscriber .stopTimer ();
2236
- logger .log (XdsLogLevel .INFO , "Unsubscribe CDS resource {0}" , resourceName );
2233
+ subscriber .cancelResourceWatch ();
2237
2234
cdsResourceSubscribers .remove (resourceName );
2238
2235
if (subscriber .xdsChannel != null ) {
2239
2236
subscriber .xdsChannel .adjustResourceSubscription (ResourceType .CDS );
@@ -2270,8 +2267,7 @@ public void run() {
2270
2267
ResourceSubscriber subscriber = edsResourceSubscribers .get (resourceName );
2271
2268
subscriber .removeWatcher (watcher );
2272
2269
if (!subscriber .isWatched ()) {
2273
- subscriber .stopTimer ();
2274
- logger .log (XdsLogLevel .INFO , "Unsubscribe EDS resource {0}" , resourceName );
2270
+ subscriber .cancelResourceWatch ();
2275
2271
edsResourceSubscribers .remove (resourceName );
2276
2272
if (subscriber .xdsChannel != null ) {
2277
2273
subscriber .xdsChannel .adjustResourceSubscription (ResourceType .EDS );
@@ -2320,7 +2316,7 @@ public void run() {
2320
2316
Bootstrapper .BootstrapInfo getBootstrapInfo () {
2321
2317
return bootstrapInfo ;
2322
2318
}
2323
-
2319
+
2324
2320
@ Override
2325
2321
public String toString () {
2326
2322
return logId .toString ();
@@ -2370,29 +2366,17 @@ private void handleResourceUpdate(
2370
2366
} else if (type == ResourceType .LDS || type == ResourceType .CDS ) {
2371
2367
if (subscriber .data != null && invalidResources .contains (resourceName )) {
2372
2368
// 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 );
2390
2370
} else if (invalidResources .contains (resourceName )) {
2391
2371
subscriber .onError (Status .UNAVAILABLE .withDescription (errorDetail ));
2392
2372
} else {
2393
2373
// For State of the World services, notify watchers when their watched resource is missing
2394
2374
// from the ADS update.
2395
2375
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
+ }
2396
2380
}
2397
2381
}
2398
2382
}
@@ -2409,6 +2393,28 @@ private void handleResourceUpdate(
2409
2393
}
2410
2394
}
2411
2395
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
+
2412
2418
private static final class ParsedResource {
2413
2419
private final ResourceUpdate resourceUpdate ;
2414
2420
private final Any rawResource ;
@@ -2431,15 +2437,18 @@ private Any getRawResource() {
2431
2437
* Tracks a single subscribed resource.
2432
2438
*/
2433
2439
private final class ResourceSubscriber {
2434
- private final ServerInfo serverInfo ;
2440
+ @ Nullable private final ServerInfo serverInfo ;
2435
2441
@ Nullable private final AbstractXdsClient xdsChannel ;
2436
2442
private final ResourceType type ;
2437
2443
private final String resource ;
2438
2444
private final Set <ResourceWatcher > watchers = new HashSet <>();
2439
- private ResourceUpdate data ;
2445
+ @ Nullable private ResourceUpdate data ;
2440
2446
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 ;
2443
2452
@ Nullable private String errorDescription ;
2444
2453
2445
2454
ResourceSubscriber (ResourceType type , String resource ) {
@@ -2533,6 +2542,19 @@ void stopTimer() {
2533
2542
}
2534
2543
}
2535
2544
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
+
2536
2558
boolean isWatched () {
2537
2559
return !watchers .isEmpty ();
2538
2560
}
@@ -2547,6 +2569,12 @@ void onData(ParsedResource parsedResource, String version, long updateTime) {
2547
2569
ResourceUpdate oldData = this .data ;
2548
2570
this .data = parsedResource .getResourceUpdate ();
2549
2571
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
+ }
2550
2578
if (!Objects .equals (oldData , data )) {
2551
2579
for (ResourceWatcher watcher : watchers ) {
2552
2580
notifyWatcher (watcher , data );
@@ -2558,6 +2586,18 @@ void onAbsent() {
2558
2586
if (respTimer != null && respTimer .isPending ()) { // too early to conclude absence
2559
2587
return ;
2560
2588
}
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
+
2561
2601
logger .log (XdsLogLevel .INFO , "Conclude {0} resource {1} not exist" , type , resource );
2562
2602
if (!absent ) {
2563
2603
data = null ;
0 commit comments