@@ -320,21 +320,16 @@ export class PickFirstLoadBalancer implements LoadBalancer {
320
320
321
321
private removeCurrentPick ( ) {
322
322
if ( this . currentPick !== null ) {
323
- /* Unref can cause a state change, which can cause a change in the value
324
- * of this.currentPick, so we hold a local reference to make sure that
325
- * does not impact this function. */
326
- const currentPick = this . currentPick ;
327
- this . currentPick = null ;
328
- currentPick . unref ( ) ;
329
- currentPick . removeConnectivityStateListener ( this . subchannelStateListener ) ;
323
+ this . currentPick . removeConnectivityStateListener ( this . subchannelStateListener ) ;
330
324
this . channelControlHelper . removeChannelzChild (
331
- currentPick . getChannelzRef ( )
325
+ this . currentPick . getChannelzRef ( )
332
326
) ;
333
- if ( this . reportHealthStatus ) {
334
- currentPick . removeHealthStateWatcher (
335
- this . pickedSubchannelHealthListener
336
- ) ;
337
- }
327
+ this . currentPick . removeHealthStateWatcher (
328
+ this . pickedSubchannelHealthListener
329
+ ) ;
330
+ // Unref last, to avoid triggering listeners
331
+ this . currentPick . unref ( ) ;
332
+ this . currentPick = null ;
338
333
}
339
334
}
340
335
@@ -418,20 +413,25 @@ export class PickFirstLoadBalancer implements LoadBalancer {
418
413
this . connectionDelayTimeout . unref ?.( ) ;
419
414
}
420
415
416
+ /**
417
+ * Declare that the specified subchannel should be used to make requests.
418
+ * This functions the same independent of whether subchannel is a member of
419
+ * this.children and whether it is equal to this.currentPick.
420
+ * Prerequisite: subchannel.getConnectivityState() === READY.
421
+ * @param subchannel
422
+ */
421
423
private pickSubchannel ( subchannel : SubchannelInterface ) {
422
- if ( this . currentPick && subchannel . realSubchannelEquals ( this . currentPick ) ) {
423
- return ;
424
- }
425
424
trace ( 'Pick subchannel with address ' + subchannel . getAddress ( ) ) ;
426
425
this . stickyTransientFailureMode = false ;
427
- this . removeCurrentPick ( ) ;
428
- this . currentPick = subchannel ;
426
+ /* Ref before removeCurrentPick and resetSubchannelList to avoid the
427
+ * refcount dropping to 0 during this process. */
429
428
subchannel . ref ( ) ;
430
- if ( this . reportHealthStatus ) {
431
- subchannel . addHealthStateWatcher ( this . pickedSubchannelHealthListener ) ;
432
- }
433
429
this . channelControlHelper . addChannelzChild ( subchannel . getChannelzRef ( ) ) ;
430
+ this . removeCurrentPick ( ) ;
434
431
this . resetSubchannelList ( ) ;
432
+ subchannel . addConnectivityStateListener ( this . subchannelStateListener ) ;
433
+ subchannel . addHealthStateWatcher ( this . pickedSubchannelHealthListener ) ;
434
+ this . currentPick = subchannel ;
435
435
clearTimeout ( this . connectionDelayTimeout ) ;
436
436
this . calculateAndReportNewState ( ) ;
437
437
}
@@ -448,20 +448,11 @@ export class PickFirstLoadBalancer implements LoadBalancer {
448
448
449
449
private resetSubchannelList ( ) {
450
450
for ( const child of this . children ) {
451
- if (
452
- ! (
453
- this . currentPick &&
454
- child . subchannel . realSubchannelEquals ( this . currentPick )
455
- )
456
- ) {
457
- /* The connectivity state listener is the same whether the subchannel
458
- * is in the list of children or it is the currentPick, so if it is in
459
- * both, removing it here would cause problems. In particular, that
460
- * always happens immediately after the subchannel is picked. */
461
- child . subchannel . removeConnectivityStateListener (
462
- this . subchannelStateListener
463
- ) ;
464
- }
451
+ /* Always remoev the connectivity state listener. If the subchannel is
452
+ getting picked, it will be re-added then. */
453
+ child . subchannel . removeConnectivityStateListener (
454
+ this . subchannelStateListener
455
+ ) ;
465
456
/* Refs are counted independently for the children list and the
466
457
* currentPick, so we call unref whether or not the child is the
467
458
* currentPick. Channelz child references are also refcounted, so
@@ -478,15 +469,13 @@ export class PickFirstLoadBalancer implements LoadBalancer {
478
469
}
479
470
480
471
private connectToAddressList ( addressList : SubchannelAddress [ ] ) {
472
+ trace ( 'connectToAddressList([' + addressList . map ( address => subchannelAddressToString ( address ) ) + '])' ) ;
481
473
const newChildrenList = addressList . map ( address => ( {
482
474
subchannel : this . channelControlHelper . createSubchannel ( address , { } ) ,
483
475
hasReportedTransientFailure : false ,
484
476
} ) ) ;
485
- trace ( 'connectToAddressList([' + addressList . map ( address => subchannelAddressToString ( address ) ) + '])' ) ;
486
477
for ( const { subchannel } of newChildrenList ) {
487
478
if ( subchannel . getConnectivityState ( ) === ConnectivityState . READY ) {
488
- this . channelControlHelper . addChannelzChild ( subchannel . getChannelzRef ( ) ) ;
489
- subchannel . addConnectivityStateListener ( this . subchannelStateListener ) ;
490
479
this . pickSubchannel ( subchannel ) ;
491
480
return ;
492
481
}
@@ -522,6 +511,7 @@ export class PickFirstLoadBalancer implements LoadBalancer {
522
511
if ( ! ( lbConfig instanceof PickFirstLoadBalancingConfig ) ) {
523
512
return ;
524
513
}
514
+ this . requestedResolutionSinceLastUpdate = false ;
525
515
/* Previously, an update would be discarded if it was identical to the
526
516
* previous update, to minimize churn. Now the DNS resolver is
527
517
* rate-limited, so that is less of a concern. */
0 commit comments