@@ -94,14 +94,14 @@ private void ResolverError(Status status)
9494 return null ;
9595 }
9696
97- private int ? FindSubchannel ( List < AddressSubchannel > addressSubchannels , Subchannel subchannel )
97+ private AddressSubchannel ? FindSubchannel ( List < AddressSubchannel > addressSubchannels , Subchannel subchannel )
9898 {
9999 for ( var i = 0 ; i < addressSubchannels . Count ; i ++ )
100100 {
101101 var s = addressSubchannels [ i ] ;
102102 if ( Equals ( s . Subchannel , subchannel ) )
103103 {
104- return i ;
104+ return s ;
105105 }
106106 }
107107
@@ -189,7 +189,7 @@ private void UpdateBalancingState(Status status)
189189 for ( var i = 0 ; i < _addressSubchannels . Count ; i ++ )
190190 {
191191 var addressSubchannel = _addressSubchannels [ i ] ;
192- if ( addressSubchannel . Subchannel . State == ConnectivityState . Ready )
192+ if ( addressSubchannel . LastKnownState == ConnectivityState . Ready )
193193 {
194194 readySubchannels . Add ( addressSubchannel . Subchannel ) ;
195195 }
@@ -201,7 +201,7 @@ private void UpdateBalancingState(Status status)
201201 var isConnecting = false ;
202202 foreach ( var subchannel in _addressSubchannels )
203203 {
204- var state = subchannel . Subchannel . State ;
204+ var state = subchannel . LastKnownState ;
205205
206206 if ( state == ConnectivityState . Connecting || state == ConnectivityState . Idle )
207207 {
@@ -239,13 +239,14 @@ private void UpdateChannelState(ConnectivityState state, SubchannelPicker subcha
239239
240240 private void UpdateSubchannelState ( Subchannel subchannel , SubchannelState state )
241241 {
242- var index = FindSubchannel ( _addressSubchannels , subchannel ) ;
243- if ( index == null )
242+ var addressSubchannel = FindSubchannel ( _addressSubchannels , subchannel ) ;
243+ if ( addressSubchannel == null )
244244 {
245245 SubchannelsLoadBalancerLog . IgnoredSubchannelStateChange ( _logger , subchannel . Id ) ;
246246 return ;
247247 }
248248
249+ addressSubchannel . UpdateKnownState ( state . State ) ;
249250 SubchannelsLoadBalancerLog . ProcessingSubchannelStateChanged ( _logger , subchannel . Id , state . State , state . Status ) ;
250251
251252 UpdateBalancingState ( state . Status ) ;
@@ -297,7 +298,29 @@ protected override void Dispose(bool disposing)
297298 /// <returns>A subchannel picker.</returns>
298299 protected abstract SubchannelPicker CreatePicker ( IReadOnlyList < Subchannel > readySubchannels ) ;
299300
300- private record AddressSubchannel ( Subchannel Subchannel , BalancerAddress Address ) ;
301+ private class AddressSubchannel
302+ {
303+ private ConnectivityState _lastKnownState ;
304+
305+ public AddressSubchannel ( Subchannel subchannel , BalancerAddress address )
306+ {
307+ Subchannel = subchannel ;
308+ Address = address ;
309+ _lastKnownState = ConnectivityState . Idle ;
310+ }
311+
312+ // Track connectivity state that has been updated to load balancer.
313+ // This is used instead of state on subchannel because subchannel state
314+ // can be updated from other threads while load balancer is running.
315+ public ConnectivityState LastKnownState => _lastKnownState ;
316+ public Subchannel Subchannel { get ; }
317+ public BalancerAddress Address { get ; }
318+
319+ public void UpdateKnownState ( ConnectivityState knownState )
320+ {
321+ _lastKnownState = knownState ;
322+ }
323+ }
301324 }
302325
303326 internal static class SubchannelsLoadBalancerLog
0 commit comments