@@ -255,7 +255,7 @@ public void aggregateSubchannelStates_connectingReadyIdleFailure() {
255255 inOrder .verify (helper ).refreshNameResolution ();
256256 inOrder .verify (helper ).updateBalancingState (eq (CONNECTING ), any ());
257257 }
258- verifyConnection (0 );
258+ verifyConnection (1 );
259259 }
260260
261261 private void verifyConnection (int times ) {
@@ -537,7 +537,7 @@ public void pickWithRandomHash_firstSubchannelInTransientFailure_remainingSubcha
537537 // Bring one subchannel to TRANSIENT_FAILURE.
538538 deliverSubchannelUnreachable (getSubChannel (servers .get (0 )));
539539 verify (helper ).updateBalancingState (eq (CONNECTING ), pickerCaptor .capture ());
540- verifyConnection (0 );
540+ verifyConnection (1 );
541541
542542 // Pick subchannel with random hash does trigger connection by walking the ring
543543 // and choosing the first (at most one) IDLE subchannel along the way.
@@ -583,7 +583,7 @@ public void skipFailingHosts_pickNextNonFailingHost() {
583583 getSubChannel (servers .get (0 )),
584584 ConnectivityStateInfo .forTransientFailure (
585585 Status .UNAVAILABLE .withDescription ("unreachable" )));
586- verify (helper ).updateBalancingState (eq (CONNECTING ), pickerCaptor .capture ());
586+ verify (helper , atLeastOnce () ).updateBalancingState (eq (CONNECTING ), pickerCaptor .capture ());
587587
588588 PickResult result = pickerCaptor .getValue ().pickSubchannel (args );
589589 assertThat (result .getStatus ().isOk ()).isTrue ();
@@ -649,7 +649,7 @@ public void skipFailingHosts_firstTwoHostsFailed_pickNextFirstReady() {
649649 ConnectivityStateInfo .forTransientFailure (
650650 Status .PERMISSION_DENIED .withDescription ("permission denied" )));
651651 verify (helper ).updateBalancingState (eq (TRANSIENT_FAILURE ), pickerCaptor .capture ());
652- verifyConnection (0 );
652+ verifyConnection (2 );
653653 PickResult result = pickerCaptor .getValue ().pickSubchannel (args ); // activate last subchannel
654654 assertThat (result .getStatus ().isOk ()).isTrue ();
655655 int expectedCount = PickFirstLoadBalancerProvider .isEnabledNewPickFirst () ? 0 : 1 ;
@@ -721,7 +721,7 @@ public void allSubchannelsInTransientFailure() {
721721 }
722722 verify (helper , atLeastOnce ())
723723 .updateBalancingState (eq (TRANSIENT_FAILURE ), pickerCaptor .capture ());
724- verifyConnection (0 );
724+ verifyConnection (2 );
725725
726726 // Picking subchannel triggers connection. RPC hash hits server0.
727727 PickSubchannelArgs args = getDefaultPickSubchannelArgsForServer (0 );
@@ -740,12 +740,13 @@ public void firstSubchannelIdle() {
740740 List <EquivalentAddressGroup > servers = createWeightedServerAddrs (1 , 1 , 1 );
741741 initializeLbSubchannels (config , servers );
742742
743- // Go to TF does nothing, though PF will try to reconnect after backoff
743+ // As per gRFC A61, entering TF triggers a proactive connection attempt
744+ // on an IDLE subchannel because no other subchannel is currently CONNECTING.
744745 deliverSubchannelState (getSubchannel (servers , 1 ),
745746 ConnectivityStateInfo .forTransientFailure (
746747 Status .UNAVAILABLE .withDescription ("unreachable" )));
747748 verify (helper ).updateBalancingState (eq (CONNECTING ), pickerCaptor .capture ());
748- verifyConnection (0 );
749+ verifyConnection (1 );
749750
750751 // Picking subchannel triggers connection. RPC hash hits server0.
751752 PickSubchannelArgs args = getDefaultPickSubchannelArgs (hashFunc .hashVoid ());
@@ -796,7 +797,7 @@ public void firstSubchannelFailure() {
796797 ConnectivityStateInfo .forTransientFailure (
797798 Status .UNAVAILABLE .withDescription ("unreachable" )));
798799 verify (helper ).updateBalancingState (eq (CONNECTING ), pickerCaptor .capture ());
799- verifyConnection (0 );
800+ verifyConnection (1 );
800801
801802 // Per GRFC A61 Picking subchannel should no longer request connections that were failing
802803 PickSubchannelArgs args = getDefaultPickSubchannelArgs (hashFunc .hashVoid ());
@@ -805,8 +806,6 @@ public void firstSubchannelFailure() {
805806 assertThat (result .getStatus ().isOk ()).isTrue ();
806807 assertThat (result .getSubchannel ()).isNull ();
807808 verify (subchannelList .get (0 ), never ()).requestConnection (); // In TF
808- verify (subchannelList .get (1 )).requestConnection ();
809- verify (subchannelList .get (2 ), never ()).requestConnection (); // Not one of the first 2
810809 }
811810
812811 @ Test
@@ -824,7 +823,7 @@ public void secondSubchannelConnecting() {
824823
825824 Subchannel firstSubchannel = getSubchannel (servers , 0 );
826825 deliverSubchannelUnreachable (firstSubchannel );
827- verifyConnection (0 );
826+ verifyConnection (1 );
828827
829828 deliverSubchannelState (getSubchannel (servers , 2 ), CSI_CONNECTING );
830829 verify (helper , times (2 )).updateBalancingState (eq (CONNECTING ), pickerCaptor .capture ());
@@ -833,7 +832,7 @@ public void secondSubchannelConnecting() {
833832 // Picking subchannel when idle triggers connection.
834833 deliverSubchannelState (getSubchannel (servers , 2 ),
835834 ConnectivityStateInfo .forNonError (IDLE ));
836- verifyConnection (0 );
835+ verifyConnection (1 );
837836 PickSubchannelArgs args = getDefaultPickSubchannelArgs (hashFunc .hashVoid ());
838837 PickResult result = pickerCaptor .getValue ().pickSubchannel (args );
839838 assertThat (result .getStatus ().isOk ()).isTrue ();
@@ -857,7 +856,7 @@ public void secondSubchannelFailure() {
857856 deliverSubchannelUnreachable (firstSubchannel );
858857 deliverSubchannelUnreachable (getSubchannel (servers , 2 ));
859858 verify (helper ).updateBalancingState (eq (TRANSIENT_FAILURE ), pickerCaptor .capture ());
860- verifyConnection (0 );
859+ verifyConnection (2 );
861860
862861 // Picking subchannel triggers connection.
863862 PickSubchannelArgs args = getDefaultPickSubchannelArgs (hashFunc .hashVoid ());
@@ -887,7 +886,7 @@ public void thirdSubchannelConnecting() {
887886 deliverSubchannelState (getSubchannel (servers , 1 ), CSI_CONNECTING );
888887 verify (helper , atLeastOnce ())
889888 .updateBalancingState (eq (TRANSIENT_FAILURE ), pickerCaptor .capture ());
890- verifyConnection (0 );
889+ verifyConnection (2 );
891890
892891 // Picking subchannel should not trigger connection per gRFC A61.
893892 PickSubchannelArgs args = getDefaultPickSubchannelArgs (hashFunc .hashVoid ());
@@ -909,7 +908,7 @@ public void stickyTransientFailure() {
909908 deliverSubchannelUnreachable (firstSubchannel );
910909
911910 verify (helper ).updateBalancingState (eq (CONNECTING ), pickerCaptor .capture ());
912- verifyConnection (0 );
911+ verifyConnection (1 );
913912
914913 reset (helper );
915914 deliverSubchannelState (firstSubchannel , ConnectivityStateInfo .forNonError (IDLE ));
@@ -1127,6 +1126,39 @@ public void config_equalsTester() {
11271126 .testEquals ();
11281127 }
11291128
1129+ @ Test
1130+ public void tfWithoutConnectingChild_triggersIdleChildConnection () {
1131+ RingHashConfig config = new RingHashConfig (10 , 100 , "" );
1132+ List <EquivalentAddressGroup > servers = createWeightedServerAddrs (1 , 1 );
1133+
1134+ initializeLbSubchannels (config , servers );
1135+
1136+ Subchannel tfSubchannel = getSubchannel (servers , 0 );
1137+ Subchannel idleSubchannel = getSubchannel (servers , 1 );
1138+
1139+ deliverSubchannelUnreachable (tfSubchannel );
1140+
1141+ Subchannel requested = connectionRequestedQueue .poll ();
1142+ assertThat (requested ).isSameInstanceAs (idleSubchannel );
1143+ assertThat (connectionRequestedQueue .poll ()).isNull ();
1144+ }
1145+
1146+ @ Test
1147+ public void tfWithReadyChild_doesNotTriggerIdleChildConnection () {
1148+ RingHashConfig config = new RingHashConfig (10 , 100 , "" );
1149+ List <EquivalentAddressGroup > servers = createWeightedServerAddrs (1 , 1 , 1 );
1150+
1151+ initializeLbSubchannels (config , servers );
1152+
1153+ Subchannel tfSubchannel = getSubchannel (servers , 0 );
1154+ Subchannel readySubchannel = getSubchannel (servers , 1 );
1155+
1156+ deliverSubchannelState (readySubchannel , ConnectivityStateInfo .forNonError (READY ));
1157+ deliverSubchannelUnreachable (tfSubchannel );
1158+
1159+ assertThat (connectionRequestedQueue .poll ()).isNull ();
1160+ }
1161+
11301162 private List <Subchannel > initializeLbSubchannels (RingHashConfig config ,
11311163 List <EquivalentAddressGroup > servers , InitializationFlags ... initFlags ) {
11321164
0 commit comments