@@ -2,8 +2,8 @@ use crate::client::load_balancing::child_manager::{
22 self , ChildManager , ChildUpdate , ResolverUpdateSharder ,
33} ;
44use crate :: client:: load_balancing:: {
5- ChannelController , LbConfig , LbPolicy , LbPolicyBuilder , ParsedJsonLbConfig , Subchannel ,
6- SubchannelState , WorkScheduler , GLOBAL_LB_REGISTRY ,
5+ ChannelController , LbConfig , LbPolicy , LbPolicyBuilder , LbState , ParsedJsonLbConfig ,
6+ Subchannel , SubchannelState , WorkScheduler , GLOBAL_LB_REGISTRY ,
77} ;
88use crate :: client:: name_resolution:: ResolverUpdate ;
99use crate :: client:: ConnectivityState ;
@@ -103,6 +103,7 @@ impl UpdateSharder {
103103#[ derive( Debug ) ]
104104pub ( crate ) struct GracefulSwitchPolicy {
105105 child_manager : ChildManager < ( ) , UpdateSharder > , // Child ID is the name of the child policy.
106+ last_update : LbState , // Saves the last output LbState to determine if an update is needed.
106107}
107108
108109impl LbPolicy for GracefulSwitchPolicy {
@@ -115,7 +116,7 @@ impl LbPolicy for GracefulSwitchPolicy {
115116 let res = self
116117 . child_manager
117118 . resolver_update ( update, config, channel_controller) ?;
118- self . maybe_swap ( channel_controller) ;
119+ self . update_picker ( channel_controller) ;
119120 Ok ( ( ) )
120121 }
121122
@@ -127,17 +128,17 @@ impl LbPolicy for GracefulSwitchPolicy {
127128 ) {
128129 self . child_manager
129130 . subchannel_update ( subchannel, state, channel_controller) ;
130- self . maybe_swap ( channel_controller) ;
131+ self . update_picker ( channel_controller) ;
131132 }
132133
133134 fn work ( & mut self , channel_controller : & mut dyn ChannelController ) {
134135 self . child_manager . work ( channel_controller) ;
135- self . maybe_swap ( channel_controller) ;
136+ self . update_picker ( channel_controller) ;
136137 }
137138
138139 fn exit_idle ( & mut self , channel_controller : & mut dyn ChannelController ) {
139140 self . child_manager . exit_idle ( channel_controller) ;
140- self . maybe_swap ( channel_controller) ;
141+ self . update_picker ( channel_controller) ;
141142 }
142143}
143144
@@ -152,6 +153,7 @@ impl GracefulSwitchPolicy {
152153 pub fn new ( runtime : Arc < dyn Runtime > , work_scheduler : Arc < dyn WorkScheduler > ) -> Self {
153154 GracefulSwitchPolicy {
154155 child_manager : ChildManager :: new ( UpdateSharder :: new ( ) , runtime, work_scheduler) ,
156+ last_update : LbState :: initial ( ) ,
155157 }
156158 }
157159
@@ -191,10 +193,27 @@ impl GracefulSwitchPolicy {
191193 Err ( "no supported policies found in config" . into ( ) )
192194 }
193195
194- fn maybe_swap ( & mut self , channel_controller : & mut dyn ChannelController ) {
195- if !self . child_manager . child_updated ( ) {
196+ fn update_picker ( & mut self , channel_controller : & mut dyn ChannelController ) {
197+ let Some ( update) = self . maybe_swap ( channel_controller) else {
198+ return ;
199+ } ;
200+ if self . last_update . connectivity_state == update. connectivity_state
201+ && std:: ptr:: addr_eq (
202+ Arc :: as_ptr ( & self . last_update . picker ) ,
203+ Arc :: as_ptr ( & update. picker ) ,
204+ )
205+ {
196206 return ;
197207 }
208+ channel_controller. update_picker ( update. clone ( ) ) ;
209+ self . last_update = update;
210+ }
211+
212+ // Determines the appropriate state to output
213+ fn maybe_swap ( & mut self , channel_controller : & mut dyn ChannelController ) -> Option < LbState > {
214+ if !self . child_manager . child_updated ( ) {
215+ return None ;
216+ }
198217
199218 let active_name = self
200219 . child_manager
@@ -203,36 +222,33 @@ impl GracefulSwitchPolicy {
203222 . as_ref ( )
204223 . unwrap ( )
205224 . name ( ) ;
206- let mut could_switch = false ;
207- let mut active_state_if_updated = None ;
208- let mut pending_builder = None ;
209- let mut pending_state = None ;
225+
226+ let mut active_child = None ;
227+ let mut pending_child = None ;
210228 for child in self . child_manager . children ( ) {
211229 if child. builder . name ( ) == active_name {
212- could_switch |= child. state . connectivity_state != ConnectivityState :: Ready ;
213- if child. updated {
214- active_state_if_updated = Some ( child. state . clone ( ) ) ;
215- }
230+ active_child = Some ( child) ;
216231 } else {
217- pending_builder = Some ( child. builder . clone ( ) ) ;
218- pending_state = Some ( child. state . clone ( ) ) ;
219- could_switch |= child. state . connectivity_state != ConnectivityState :: Connecting ;
232+ pending_child = Some ( child) ;
220233 }
221234 }
222- if could_switch && pending_builder. is_some ( ) {
223- self . child_manager
224- . resolver_update (
225- ResolverUpdate :: default ( ) ,
226- Some ( & LbConfig :: new ( GracefulSwitchLbConfig :: Swap (
227- pending_builder. unwrap ( ) ,
228- ) ) ) ,
229- channel_controller,
230- )
231- . expect ( "resolver_update with an empty update should not fail" ) ;
232- channel_controller. update_picker ( pending_state. unwrap ( ) . clone ( ) ) ;
233- } else if active_state_if_updated. is_some ( ) {
234- channel_controller. update_picker ( active_state_if_updated. unwrap ( ) ) ;
235+ let active_child = active_child. expect ( "There should always be an active child policy" ) ;
236+ let Some ( pending_child) = pending_child else {
237+ return Some ( active_child. state . clone ( ) ) ;
238+ } ;
239+
240+ if active_child. state . connectivity_state == ConnectivityState :: Ready
241+ && pending_child. state . connectivity_state == ConnectivityState :: Connecting
242+ {
243+ return Some ( active_child. state . clone ( ) ) ;
235244 }
245+
246+ let config = & LbConfig :: new ( GracefulSwitchLbConfig :: Swap ( pending_child. builder . clone ( ) ) ) ;
247+ let state = pending_child. state . clone ( ) ;
248+ self . child_manager
249+ . resolver_update ( ResolverUpdate :: default ( ) , Some ( config) , channel_controller)
250+ . expect ( "resolver_update with an empty update should not fail" ) ;
251+ return Some ( state) ;
236252 }
237253}
238254
@@ -809,11 +825,8 @@ mod test {
809825 tcc. as_mut ( ) ,
810826 ConnectivityState :: Connecting ,
811827 ) ;
812- verify_correct_picker_from_policy (
813- & mut rx_events,
814- "stub-gracefulswitch_current_leaving_ready-one" ,
815- )
816- . await ;
828+ // This should not produce an update.
829+ assert_channel_empty ( & mut rx_events) . await ;
817830 move_subchannel_to_state (
818831 & mut * graceful_switch,
819832 current_subchannel,
0 commit comments