Skip to content

Commit ee3ffef

Browse files
committed
core: In PF, disjoint update while READY should transition to IDLE
This is the same as if we received a GOAWAY. We wait for the next RPC to begin connecting again. This is InternalSubchannel's behavior.
1 parent f20167d commit ee3ffef

File tree

2 files changed

+22
-15
lines changed

2 files changed

+22
-15
lines changed

core/src/main/java/io/grpc/internal/PickFirstLeafLoadBalancer.java

Lines changed: 8 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -152,20 +152,18 @@ public Status acceptResolvedAddresses(ResolvedAddresses resolvedAddresses) {
152152
}
153153
}
154154

155-
if (oldAddrs.size() == 0 || rawConnectivityState == CONNECTING
156-
|| rawConnectivityState == READY) {
157-
// start connection attempt at first address
155+
if (oldAddrs.size() == 0) {
156+
// Make tests happy; they don't properly assume starting in CONNECTING
158157
rawConnectivityState = CONNECTING;
159158
updateBalancingState(CONNECTING, new Picker(PickResult.withNoResult()));
160-
cancelScheduleTask();
161-
requestConnection();
159+
}
162160

163-
} else if (rawConnectivityState == IDLE) {
164-
// start connection attempt at first address when requested
165-
SubchannelPicker picker = new RequestConnectionPicker(this);
166-
updateBalancingState(IDLE, picker);
161+
if (rawConnectivityState == READY) {
162+
// connect from beginning when prompted
163+
rawConnectivityState = IDLE;
164+
updateBalancingState(IDLE, new RequestConnectionPicker(this));
167165

168-
} else if (rawConnectivityState == TRANSIENT_FAILURE) {
166+
} else if (rawConnectivityState == CONNECTING || rawConnectivityState == TRANSIENT_FAILURE) {
169167
// start connection attempt at first address
170168
cancelScheduleTask();
171169
requestConnection();

core/src/test/java/io/grpc/internal/PickFirstLeafLoadBalancerTest.java

Lines changed: 14 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -1121,10 +1121,17 @@ public void updateAddresses_disjoint_ready_twice() {
11211121
loadBalancer.acceptResolvedAddresses(
11221122
ResolvedAddresses.newBuilder().setAddresses(newServers).setAttributes(affinity).build());
11231123
inOrder.verify(mockSubchannel1).shutdown();
1124-
inOrder.verify(mockHelper).updateBalancingState(eq(CONNECTING), pickerCaptor.capture());
1124+
inOrder.verify(mockHelper).updateBalancingState(eq(IDLE), pickerCaptor.capture());
1125+
inOrder.verify(mockSubchannel3, never()).start(stateListenerCaptor.capture());
1126+
1127+
// Trigger connection creation
1128+
picker = pickerCaptor.getValue();
1129+
assertEquals(PickResult.withNoResult(), picker.pickSubchannel(mockArgs));
11251130
inOrder.verify(mockSubchannel3).start(stateListenerCaptor.capture());
11261131
SubchannelStateListener stateListener3 = stateListenerCaptor.getValue();
11271132
inOrder.verify(mockSubchannel3).requestConnection();
1133+
stateListener3.onSubchannelState(ConnectivityStateInfo.forNonError(CONNECTING));
1134+
inOrder.verify(mockHelper).updateBalancingState(eq(CONNECTING), pickerCaptor.capture());
11281135

11291136
if (enableHappyEyeballs) {
11301137
forwardTimeByConnectionDelay();
@@ -1171,17 +1178,19 @@ public void updateAddresses_disjoint_ready_twice() {
11711178
loadBalancer.acceptResolvedAddresses(
11721179
ResolvedAddresses.newBuilder().setAddresses(newestServers).setAttributes(affinity).build());
11731180
inOrder.verify(mockSubchannel3).shutdown();
1174-
inOrder.verify(mockHelper).updateBalancingState(eq(CONNECTING), pickerCaptor.capture());
1175-
inOrder.verify(mockSubchannel1n2).start(stateListenerCaptor.capture());
1176-
stateListener = stateListenerCaptor.getValue();
1177-
assertEquals(CONNECTING, loadBalancer.getConcludedConnectivityState());
1181+
inOrder.verify(mockHelper).updateBalancingState(eq(IDLE), pickerCaptor.capture());
1182+
assertEquals(IDLE, loadBalancer.getConcludedConnectivityState());
11781183
picker = pickerCaptor.getValue();
11791184

11801185
// Calling pickSubchannel() twice gave the same result
11811186
assertEquals(picker.pickSubchannel(mockArgs), picker.pickSubchannel(mockArgs));
11821187

11831188
// But the picker calls requestConnection() only once
1189+
inOrder.verify(mockSubchannel1n2).start(stateListenerCaptor.capture());
1190+
stateListener = stateListenerCaptor.getValue();
11841191
inOrder.verify(mockSubchannel1n2).requestConnection();
1192+
stateListener.onSubchannelState(ConnectivityStateInfo.forNonError(CONNECTING));
1193+
inOrder.verify(mockHelper).updateBalancingState(eq(CONNECTING), pickerCaptor.capture());
11851194
assertEquals(PickResult.withNoResult(), pickerCaptor.getValue().pickSubchannel(mockArgs));
11861195
assertEquals(CONNECTING, loadBalancer.getConcludedConnectivityState());
11871196

0 commit comments

Comments
 (0)