| 
					
				 | 
			
			
				@@ -99,26 +99,13 @@ typedef struct pending_pick { 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				   grpc_closure *on_complete; 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				 } pending_pick; 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				  
			 | 
		
	
		
			
				 | 
				 | 
			
			
				-/** List of subchannels in a connectivity READY state */ 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				-typedef struct ready_list { 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				-  grpc_subchannel *subchannel; 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				-  /* references namesake entry in subchannel_data */ 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				-  void *user_data; 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				-  struct ready_list *next; 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				-  struct ready_list *prev; 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				-} ready_list; 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				- 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				 typedef struct { 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				-  /** index within policy->subchannels */ 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				-  size_t index; 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				   /** backpointer to owning policy */ 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				   round_robin_lb_policy *policy; 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				   /** subchannel itself */ 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				   grpc_subchannel *subchannel; 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				   /** notification that connectivity has changed on subchannel */ 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				   grpc_closure connectivity_changed_closure; 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				-  /** this subchannels current position in subchannel->ready_list */ 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				-  ready_list *ready_list_node; 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				   /** last observed connectivity. Not updated by 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				    * \a grpc_subchannel_notify_on_state_change. Used to determine the previous 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				    * state while processing the new state in \a rr_connectivity_changed */ 
			 | 
		
	
	
		
			
				| 
					
				 | 
			
			
				@@ -126,6 +113,10 @@ typedef struct { 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				   /** current connectivity state. Updated by \a 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				    * grpc_subchannel_notify_on_state_change */ 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				   grpc_connectivity_state curr_connectivity_state; 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+  /** connectivity state to be updated by the watcher, not guarded by 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+   * the combiner.  Will be moved to curr_connectivity_state inside of 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+   * the combiner by rr_connectivity_changed_locked(). */ 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+  grpc_connectivity_state pending_connectivity_state_unsafe; 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				   /** the subchannel's target user data */ 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				   void *user_data; 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				   /** vtable to operate over \a user_data */ 
			 | 
		
	
	
		
			
				| 
					
				 | 
			
			
				@@ -141,182 +132,105 @@ struct round_robin_lb_policy { 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				  
			 | 
		
	
		
			
				 | 
				 | 
			
			
				   /** all our subchannels */ 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				   size_t num_subchannels; 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				-  subchannel_data **subchannels; 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+  subchannel_data *subchannels; 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				  
			 | 
		
	
		
			
				 | 
				 | 
			
			
				-  /** how many subchannels are in TRANSIENT_FAILURE */ 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+  /** how many subchannels are in state READY */ 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+  size_t num_ready; 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+  /** how many subchannels are in state TRANSIENT_FAILURE */ 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				   size_t num_transient_failures; 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				-  /** how many subchannels are IDLE */ 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+  /** how many subchannels are in state IDLE */ 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				   size_t num_idle; 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				  
			 | 
		
	
		
			
				 | 
				 | 
			
			
				   /** have we started picking? */ 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				-  int started_picking; 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+  bool started_picking; 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				   /** are we shutting down? */ 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				-  int shutdown; 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+  bool shutdown; 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				   /** List of picks that are waiting on connectivity */ 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				   pending_pick *pending_picks; 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				  
			 | 
		
	
		
			
				 | 
				 | 
			
			
				   /** our connectivity state tracker */ 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				   grpc_connectivity_state_tracker state_tracker; 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				  
			 | 
		
	
		
			
				 | 
				 | 
			
			
				-  /** (Dummy) root of the doubly linked list containing READY subchannels */ 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				-  ready_list ready_list; 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				-  /** Last pick from the ready list. */ 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				-  ready_list *ready_list_last_pick; 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+  // Index into subchannels for last pick. 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+  size_t last_ready_subchannel_index; 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				 }; 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				  
			 | 
		
	
		
			
				 | 
				 | 
			
			
				-/** Returns the next subchannel from the connected list or NULL if the list is 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				- * empty. 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+/** Returns the index into p->subchannels of the next subchannel in 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+ * READY state, or p->num_subchannels if no subchannel is READY. 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				  * 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				- * Note that this function does *not* advance p->ready_list_last_pick. Use \a 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				- * advance_last_picked_locked() for that. */ 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				-static ready_list *peek_next_connected_locked(const round_robin_lb_policy *p) { 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				-  ready_list *selected; 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				-  selected = p->ready_list_last_pick->next; 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				- 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				-  while (selected != NULL) { 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				-    if (selected == &p->ready_list) { 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				-      GPR_ASSERT(selected->subchannel == NULL); 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				-      /* skip dummy root */ 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				-      selected = selected->next; 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				-    } else { 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				-      GPR_ASSERT(selected->subchannel != NULL); 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				-      return selected; 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				-    } 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+ * Note that this function does *not* update p->last_ready_subchannel_index. 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+ * The caller must do that if it returns a pick. */ 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+static size_t get_next_ready_subchannel_index_locked( 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+    const round_robin_lb_policy *p) { 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+  if (GRPC_TRACER_ON(grpc_lb_round_robin_trace)) { 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+    gpr_log(GPR_INFO, 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+            "[RR: %p] getting next ready subchannel, " 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+            "last_ready_subchannel_index=%zu", 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+            p, p->last_ready_subchannel_index); 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				   } 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				-  return NULL; 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				-} 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				- 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				-/** Advance the \a ready_list picking head. */ 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				-static void advance_last_picked_locked(round_robin_lb_policy *p) { 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				-  if (p->ready_list_last_pick->next != NULL) { /* non-empty list */ 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				-    p->ready_list_last_pick = p->ready_list_last_pick->next; 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				-    if (p->ready_list_last_pick == &p->ready_list) { 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				-      /* skip dummy root */ 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				-      p->ready_list_last_pick = p->ready_list_last_pick->next; 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+  for (size_t i = 0; i < p->num_subchannels; ++i) { 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+    const size_t index = 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+        (i + p->last_ready_subchannel_index + 1) % p->num_subchannels; 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+    if (GRPC_TRACER_ON(grpc_lb_round_robin_trace)) { 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+      gpr_log(GPR_DEBUG, "[RR %p] checking index %zu: state=%d", p, index, 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+              p->subchannels[index].curr_connectivity_state); 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+    } 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+    if (p->subchannels[index].curr_connectivity_state == GRPC_CHANNEL_READY) { 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+      if (GRPC_TRACER_ON(grpc_lb_round_robin_trace)) { 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+        gpr_log(GPR_DEBUG, "[RR %p] found next ready subchannel at index %zu", 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+                p, index); 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+      } 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+      return index; 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				     } 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				-  } else { /* should be an empty list */ 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				-    GPR_ASSERT(p->ready_list_last_pick == &p->ready_list); 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				   } 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				- 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				   if (GRPC_TRACER_ON(grpc_lb_round_robin_trace)) { 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				-    gpr_log(GPR_DEBUG, 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				-            "[READYLIST, RR: %p] ADVANCED LAST PICK. NOW AT NODE %p (SC %p, " 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				-            "CSC %p)", 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				-            (void *)p, (void *)p->ready_list_last_pick, 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				-            (void *)p->ready_list_last_pick->subchannel, 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				-            (void *)grpc_subchannel_get_connected_subchannel( 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				-                p->ready_list_last_pick->subchannel)); 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+    gpr_log(GPR_DEBUG, "[RR %p] no subchannels in ready state", p); 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				   } 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+  return p->num_subchannels; 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				 } 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				  
			 | 
		
	
		
			
				 | 
				 | 
			
			
				-/** Prepends (relative to the root at p->ready_list) the connected subchannel \a 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				- * csc to the list of ready subchannels. */ 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				-static ready_list *add_connected_sc_locked(round_robin_lb_policy *p, 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				-                                           subchannel_data *sd) { 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				-  ready_list *new_elem = gpr_zalloc(sizeof(ready_list)); 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				-  new_elem->subchannel = sd->subchannel; 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				-  new_elem->user_data = sd->user_data; 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				-  if (p->ready_list.prev == NULL) { 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				-    /* first element */ 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				-    new_elem->next = &p->ready_list; 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				-    new_elem->prev = &p->ready_list; 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				-    p->ready_list.next = new_elem; 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				-    p->ready_list.prev = new_elem; 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				-  } else { 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				-    new_elem->next = &p->ready_list; 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				-    new_elem->prev = p->ready_list.prev; 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				-    p->ready_list.prev->next = new_elem; 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				-    p->ready_list.prev = new_elem; 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				-  } 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+// Sets p->last_ready_subchannel_index to last_ready_index. 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+static void update_last_ready_subchannel_index_locked(round_robin_lb_policy *p, 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+                                                      size_t last_ready_index) { 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+  GPR_ASSERT(last_ready_index < p->num_subchannels); 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+  p->last_ready_subchannel_index = last_ready_index; 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				   if (GRPC_TRACER_ON(grpc_lb_round_robin_trace)) { 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				-    gpr_log(GPR_DEBUG, "[READYLIST] ADDING NODE %p (Conn. SC %p)", 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				-            (void *)new_elem, (void *)sd->subchannel); 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				-  } 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				-  return new_elem; 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				-} 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				- 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				-/** Removes \a node from the list of connected subchannels */ 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				-static void remove_disconnected_sc_locked(round_robin_lb_policy *p, 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				-                                          ready_list *node) { 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				-  if (node == NULL) { 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				-    return; 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				-  } 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				-  if (node == p->ready_list_last_pick) { 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				-    p->ready_list_last_pick = p->ready_list_last_pick->prev; 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				-  } 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				- 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				-  /* removing last item */ 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				-  if (node->next == &p->ready_list && node->prev == &p->ready_list) { 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				-    GPR_ASSERT(p->ready_list.next == node); 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				-    GPR_ASSERT(p->ready_list.prev == node); 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				-    p->ready_list.next = NULL; 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				-    p->ready_list.prev = NULL; 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				-  } else { 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				-    node->prev->next = node->next; 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				-    node->next->prev = node->prev; 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				-  } 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				- 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				-  if (GRPC_TRACER_ON(grpc_lb_round_robin_trace)) { 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				-    gpr_log(GPR_DEBUG, "[READYLIST] REMOVED NODE %p (SC %p)", (void *)node, 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				-            (void *)node->subchannel); 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+    gpr_log(GPR_DEBUG, 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+            "[RR: %p] setting last_ready_subchannel_index=%zu (SC %p, CSC %p)", 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+            (void *)p, last_ready_index, 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+            (void *)p->subchannels[last_ready_index].subchannel, 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+            (void *)grpc_subchannel_get_connected_subchannel( 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+                p->subchannels[last_ready_index].subchannel)); 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				   } 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				- 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				-  node->next = NULL; 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				-  node->prev = NULL; 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				-  node->subchannel = NULL; 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				- 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				-  gpr_free(node); 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				-} 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				- 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				-static bool is_ready_list_empty(round_robin_lb_policy *p) { 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				-  return p->ready_list.prev == NULL; 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				 } 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				  
			 | 
		
	
		
			
				 | 
				 | 
			
			
				 static void rr_destroy(grpc_exec_ctx *exec_ctx, grpc_lb_policy *pol) { 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				   round_robin_lb_policy *p = (round_robin_lb_policy *)pol; 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				-  ready_list *elem; 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				- 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				   if (GRPC_TRACER_ON(grpc_lb_round_robin_trace)) { 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				     gpr_log(GPR_DEBUG, "Destroying Round Robin policy at %p", (void *)pol); 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				   } 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				- 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				   for (size_t i = 0; i < p->num_subchannels; i++) { 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				-    subchannel_data *sd = p->subchannels[i]; 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				-    GRPC_SUBCHANNEL_UNREF(exec_ctx, sd->subchannel, "rr_destroy"); 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				-    if (sd->user_data != NULL) { 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				-      GPR_ASSERT(sd->user_data_vtable != NULL); 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				-      sd->user_data_vtable->destroy(exec_ctx, sd->user_data); 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+    subchannel_data *sd = &p->subchannels[i]; 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+    if (sd->subchannel != NULL) { 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+      GRPC_SUBCHANNEL_UNREF(exec_ctx, sd->subchannel, "rr_destroy"); 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+      if (sd->user_data != NULL) { 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+        GPR_ASSERT(sd->user_data_vtable != NULL); 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+        sd->user_data_vtable->destroy(exec_ctx, sd->user_data); 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+      } 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				     } 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				-    gpr_free(sd); 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				   } 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				- 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				   grpc_connectivity_state_destroy(exec_ctx, &p->state_tracker); 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				   gpr_free(p->subchannels); 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				- 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				-  elem = p->ready_list.next; 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				-  while (elem != NULL && elem != &p->ready_list) { 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				-    ready_list *tmp; 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				-    tmp = elem->next; 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				-    elem->next = NULL; 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				-    elem->prev = NULL; 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				-    elem->subchannel = NULL; 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				-    gpr_free(elem); 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				-    elem = tmp; 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				-  } 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				- 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				   gpr_free(p); 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				 } 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				  
			 | 
		
	
		
			
				 | 
				 | 
			
			
				 static void rr_shutdown_locked(grpc_exec_ctx *exec_ctx, grpc_lb_policy *pol) { 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				   round_robin_lb_policy *p = (round_robin_lb_policy *)pol; 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				-  pending_pick *pp; 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				-  size_t i; 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				- 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				   if (GRPC_TRACER_ON(grpc_lb_round_robin_trace)) { 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				     gpr_log(GPR_DEBUG, "Shutting down Round Robin policy at %p", (void *)pol); 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				   } 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				- 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				-  p->shutdown = 1; 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+  p->shutdown = true; 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+  pending_pick *pp; 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				   while ((pp = p->pending_picks)) { 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				     p->pending_picks = pp->next; 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				     *pp->target = NULL; 
			 | 
		
	
	
		
			
				| 
					
				 | 
			
			
				@@ -328,10 +242,13 @@ static void rr_shutdown_locked(grpc_exec_ctx *exec_ctx, grpc_lb_policy *pol) { 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				   grpc_connectivity_state_set( 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				       exec_ctx, &p->state_tracker, GRPC_CHANNEL_SHUTDOWN, 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				       GRPC_ERROR_CREATE_FROM_STATIC_STRING("Channel Shutdown"), "rr_shutdown"); 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				-  for (i = 0; i < p->num_subchannels; i++) { 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				-    subchannel_data *sd = p->subchannels[i]; 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				-    grpc_subchannel_notify_on_state_change(exec_ctx, sd->subchannel, NULL, NULL, 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				-                                           &sd->connectivity_changed_closure); 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+  for (size_t i = 0; i < p->num_subchannels; i++) { 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+    subchannel_data *sd = &p->subchannels[i]; 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+    if (sd->subchannel != NULL) { 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+      grpc_subchannel_notify_on_state_change(exec_ctx, sd->subchannel, NULL, 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+                                             NULL, 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+                                             &sd->connectivity_changed_closure); 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+    } 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				   } 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				 } 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				  
			 | 
		
	
	
		
			
				| 
					
				 | 
			
			
				@@ -339,8 +256,7 @@ static void rr_cancel_pick_locked(grpc_exec_ctx *exec_ctx, grpc_lb_policy *pol, 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				                                   grpc_connected_subchannel **target, 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				                                   grpc_error *error) { 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				   round_robin_lb_policy *p = (round_robin_lb_policy *)pol; 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				-  pending_pick *pp; 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				-  pp = p->pending_picks; 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+  pending_pick *pp = p->pending_picks; 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				   p->pending_picks = NULL; 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				   while (pp != NULL) { 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				     pending_pick *next = pp->next; 
			 | 
		
	
	
		
			
				| 
					
				 | 
			
			
				@@ -364,8 +280,7 @@ static void rr_cancel_picks_locked(grpc_exec_ctx *exec_ctx, grpc_lb_policy *pol, 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				                                    uint32_t initial_metadata_flags_eq, 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				                                    grpc_error *error) { 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				   round_robin_lb_policy *p = (round_robin_lb_policy *)pol; 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				-  pending_pick *pp; 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				-  pp = p->pending_picks; 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+  pending_pick *pp = p->pending_picks; 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				   p->pending_picks = NULL; 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				   while (pp != NULL) { 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				     pending_pick *next = pp->next; 
			 | 
		
	
	
		
			
				| 
					
				 | 
			
			
				@@ -387,21 +302,16 @@ static void rr_cancel_picks_locked(grpc_exec_ctx *exec_ctx, grpc_lb_policy *pol, 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				  
			 | 
		
	
		
			
				 | 
				 | 
			
			
				 static void start_picking_locked(grpc_exec_ctx *exec_ctx, 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				                                  round_robin_lb_policy *p) { 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				-  size_t i; 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				-  p->started_picking = 1; 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				- 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				-  for (i = 0; i < p->num_subchannels; i++) { 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				-    subchannel_data *sd = p->subchannels[i]; 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				-    /* use some sentinel value outside of the range of grpc_connectivity_state 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				-     * to signal an undefined previous state. We won't be referring to this 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				-     * value again and it'll be overwritten after the first call to 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				-     * rr_connectivity_changed */ 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				-    sd->prev_connectivity_state = GRPC_CHANNEL_INIT; 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				-    sd->curr_connectivity_state = GRPC_CHANNEL_IDLE; 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				-    GRPC_LB_POLICY_WEAK_REF(&p->base, "rr_connectivity"); 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				-    grpc_subchannel_notify_on_state_change( 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				-        exec_ctx, sd->subchannel, p->base.interested_parties, 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				-        &sd->curr_connectivity_state, &sd->connectivity_changed_closure); 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+  p->started_picking = true; 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+  for (size_t i = 0; i < p->num_subchannels; i++) { 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+    subchannel_data *sd = &p->subchannels[i]; 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+    if (sd->subchannel != NULL) { 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+      GRPC_LB_POLICY_WEAK_REF(&p->base, "rr_connectivity"); 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+      grpc_subchannel_notify_on_state_change( 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+          exec_ctx, sd->subchannel, p->base.interested_parties, 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+          &sd->pending_connectivity_state_unsafe, 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+          &sd->connectivity_changed_closure); 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+    } 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				   } 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				 } 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				  
			 | 
		
	
	
		
			
				| 
					
				 | 
			
			
				@@ -418,36 +328,32 @@ static int rr_pick_locked(grpc_exec_ctx *exec_ctx, grpc_lb_policy *pol, 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				                           grpc_call_context_element *context, void **user_data, 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				                           grpc_closure *on_complete) { 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				   round_robin_lb_policy *p = (round_robin_lb_policy *)pol; 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				-  pending_pick *pp; 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				-  ready_list *selected; 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				- 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				   if (GRPC_TRACER_ON(grpc_lb_round_robin_trace)) { 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				     gpr_log(GPR_INFO, "Round Robin %p trying to pick", (void *)pol); 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				   } 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				- 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				-  if ((selected = peek_next_connected_locked(p))) { 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+  const size_t next_ready_index = get_next_ready_subchannel_index_locked(p); 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+  if (next_ready_index < p->num_subchannels) { 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				     /* readily available, report right away */ 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+    subchannel_data *sd = &p->subchannels[next_ready_index]; 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				     *target = GRPC_CONNECTED_SUBCHANNEL_REF( 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				-        grpc_subchannel_get_connected_subchannel(selected->subchannel), 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				-        "rr_picked"); 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				- 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+        grpc_subchannel_get_connected_subchannel(sd->subchannel), "rr_picked"); 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				     if (user_data != NULL) { 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				-      *user_data = selected->user_data; 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+      *user_data = sd->user_data; 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				     } 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				     if (GRPC_TRACER_ON(grpc_lb_round_robin_trace)) { 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				       gpr_log(GPR_DEBUG, 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				-              "[RR PICK] TARGET <-- CONNECTED SUBCHANNEL %p (NODE %p)", 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				-              (void *)*target, (void *)selected); 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+              "[RR PICK] TARGET <-- CONNECTED SUBCHANNEL %p (INDEX %zu)", 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+              (void *)*target, next_ready_index); 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				     } 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				     /* only advance the last picked pointer if the selection was used */ 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				-    advance_last_picked_locked(p); 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+    update_last_ready_subchannel_index_locked(p, next_ready_index); 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				     return 1; 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				   } else { 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				     /* no pick currently available. Save for later in list of pending picks */ 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				     if (!p->started_picking) { 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				       start_picking_locked(exec_ctx, p); 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				     } 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				-    pp = gpr_malloc(sizeof(*pp)); 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+    pending_pick *pp = gpr_malloc(sizeof(*pp)); 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				     pp->next = p->pending_picks; 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				     pp->target = target; 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				     pp->on_complete = on_complete; 
			 | 
		
	
	
		
			
				| 
					
				 | 
			
			
				@@ -458,25 +364,31 @@ static int rr_pick_locked(grpc_exec_ctx *exec_ctx, grpc_lb_policy *pol, 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				   } 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				 } 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				  
			 | 
		
	
		
			
				 | 
				 | 
			
			
				-static void update_state_counters(subchannel_data *sd) { 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+static void update_state_counters_locked(subchannel_data *sd) { 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				   round_robin_lb_policy *p = sd->policy; 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				- 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				-  /* update p->num_transient_failures (resp. p->num_idle): if the previous 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				-   * state was TRANSIENT_FAILURE (resp. IDLE), decrement 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				-   * p->num_transient_failures (resp. p->num_idle). */ 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				-  if (sd->prev_connectivity_state == GRPC_CHANNEL_TRANSIENT_FAILURE) { 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+  if (sd->prev_connectivity_state == GRPC_CHANNEL_READY) { 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+    GPR_ASSERT(p->num_ready > 0); 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+    --p->num_ready; 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+  } else if (sd->prev_connectivity_state == GRPC_CHANNEL_TRANSIENT_FAILURE) { 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				     GPR_ASSERT(p->num_transient_failures > 0); 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				     --p->num_transient_failures; 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				   } else if (sd->prev_connectivity_state == GRPC_CHANNEL_IDLE) { 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				     GPR_ASSERT(p->num_idle > 0); 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				     --p->num_idle; 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				   } 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+  if (sd->curr_connectivity_state == GRPC_CHANNEL_READY) { 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+    ++p->num_ready; 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+  } else if (sd->curr_connectivity_state == GRPC_CHANNEL_TRANSIENT_FAILURE) { 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+    ++p->num_transient_failures; 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+  } else if (sd->curr_connectivity_state == GRPC_CHANNEL_IDLE) { 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+    ++p->num_idle; 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+  } 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				 } 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				  
			 | 
		
	
		
			
				 | 
				 | 
			
			
				 /* sd is the subchannel_data associted with the updated subchannel. 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				  * shutdown_error will only be used upon policy transition to TRANSIENT_FAILURE 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				  * or SHUTDOWN */ 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				-static grpc_connectivity_state update_lb_connectivity_status( 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+static grpc_connectivity_state update_lb_connectivity_status_locked( 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				     grpc_exec_ctx *exec_ctx, subchannel_data *sd, grpc_error *error) { 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				   /* In priority order. The first rule to match terminates the search (ie, if we 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				    * are on rule n, all previous rules were unfulfilled). 
			 | 
		
	
	
		
			
				| 
					
				 | 
			
			
				@@ -498,7 +410,7 @@ static grpc_connectivity_state update_lb_connectivity_status( 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				    *    CHECK: p->num_idle == p->num_subchannels. 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				    */ 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				   round_robin_lb_policy *p = sd->policy; 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				-  if (!is_ready_list_empty(p)) { /* 1) READY */ 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+  if (p->num_ready > 0) { /* 1) READY */ 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				     grpc_connectivity_state_set(exec_ctx, &p->state_tracker, GRPC_CHANNEL_READY, 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				                                 GRPC_ERROR_NONE, "rr_ready"); 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				     return GRPC_CHANNEL_READY; 
			 | 
		
	
	
		
			
				| 
					
				 | 
			
			
				@@ -532,32 +444,62 @@ static void rr_connectivity_changed_locked(grpc_exec_ctx *exec_ctx, void *arg, 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				                                            grpc_error *error) { 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				   subchannel_data *sd = arg; 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				   round_robin_lb_policy *p = sd->policy; 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				-  pending_pick *pp; 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				- 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				-  GRPC_ERROR_REF(error); 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				- 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+  // Now that we're inside the combiner, copy the pending connectivity 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+  // state (which was set by the connectivity state watcher) to 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+  // curr_connectivity_state, which is what we use inside of the combiner. 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+  sd->curr_connectivity_state = sd->pending_connectivity_state_unsafe; 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+  if (GRPC_TRACER_ON(grpc_lb_round_robin_trace)) { 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+    gpr_log(GPR_DEBUG, 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+            "[RR %p] connectivity changed for subchannel %p: " 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+            "prev_state=%d new_state=%d", 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+            p, sd->subchannel, sd->prev_connectivity_state, 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+            sd->curr_connectivity_state); 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+  } 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+  // If we're shutting down, unref and return. 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				   if (p->shutdown) { 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				     GRPC_LB_POLICY_WEAK_UNREF(exec_ctx, &p->base, "rr_connectivity"); 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				-    GRPC_ERROR_UNREF(error); 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				     return; 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				   } 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				-  switch (sd->curr_connectivity_state) { 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				-    case GRPC_CHANNEL_INIT: 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				-      GPR_UNREACHABLE_CODE(return ); 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				-    case GRPC_CHANNEL_READY: 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				-      /* add the newly connected subchannel to the list of connected ones. 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				-       * Note that it goes to the "end of the line". */ 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				-      sd->ready_list_node = add_connected_sc_locked(p, sd); 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+  // Update state counters and determine new overall state. 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+  update_state_counters_locked(sd); 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+  sd->prev_connectivity_state = sd->curr_connectivity_state; 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+  grpc_connectivity_state new_connectivity_state = 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+      update_lb_connectivity_status_locked(exec_ctx, sd, GRPC_ERROR_REF(error)); 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+  // If the new state is SHUTDOWN, unref the subchannel, and if the new 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+  // overall state is SHUTDOWN, clean up. 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+  if (sd->curr_connectivity_state == GRPC_CHANNEL_SHUTDOWN) { 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+    GRPC_SUBCHANNEL_UNREF(exec_ctx, sd->subchannel, "rr_subchannel_shutdown"); 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+    sd->subchannel = NULL; 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+    if (sd->user_data != NULL) { 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+      GPR_ASSERT(sd->user_data_vtable != NULL); 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+      sd->user_data_vtable->destroy(exec_ctx, sd->user_data); 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+    } 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+    if (new_connectivity_state == GRPC_CHANNEL_SHUTDOWN) { 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+      /* the policy is shutting down. Flush all the pending picks... */ 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+      pending_pick *pp; 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+      while ((pp = p->pending_picks)) { 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+        p->pending_picks = pp->next; 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+        *pp->target = NULL; 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+        grpc_closure_sched(exec_ctx, pp->on_complete, GRPC_ERROR_NONE); 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+        gpr_free(pp); 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+      } 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+    } 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+    /* unref the "rr_connectivity" weak ref from start_picking */ 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+    GRPC_LB_POLICY_WEAK_UNREF(exec_ctx, &p->base, "rr_connectivity"); 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+  } else { 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+    if (sd->curr_connectivity_state == GRPC_CHANNEL_READY) { 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				       /* at this point we know there's at least one suitable subchannel. Go 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				        * ahead and pick one and notify the pending suitors in 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				        * p->pending_picks. This preemtively replicates rr_pick()'s actions. */ 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				-      ready_list *selected = peek_next_connected_locked(p); 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				-      GPR_ASSERT(selected != NULL); 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+      const size_t next_ready_index = get_next_ready_subchannel_index_locked(p); 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+      GPR_ASSERT(next_ready_index < p->num_subchannels); 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+      subchannel_data *selected = &p->subchannels[next_ready_index]; 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				       if (p->pending_picks != NULL) { 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				         /* if the selected subchannel is going to be used for the pending 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				          * picks, update the last picked pointer */ 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				-        advance_last_picked_locked(p); 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+        update_last_ready_subchannel_index_locked(p, next_ready_index); 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				       } 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+      pending_pick *pp; 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				       while ((pp = p->pending_picks)) { 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				         p->pending_picks = pp->next; 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				         *pp->target = GRPC_CONNECTED_SUBCHANNEL_REF( 
			 | 
		
	
	
		
			
				| 
					
				 | 
			
			
				@@ -568,72 +510,19 @@ static void rr_connectivity_changed_locked(grpc_exec_ctx *exec_ctx, void *arg, 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				         } 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				         if (GRPC_TRACER_ON(grpc_lb_round_robin_trace)) { 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				           gpr_log(GPR_DEBUG, 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				-                  "[RR CONN CHANGED] TARGET <-- SUBCHANNEL %p (NODE %p)", 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				-                  (void *)selected->subchannel, (void *)selected); 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+                  "[RR CONN CHANGED] TARGET <-- SUBCHANNEL %p (INDEX %zu)", 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+                  (void *)selected->subchannel, next_ready_index); 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				         } 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				         grpc_closure_sched(exec_ctx, pp->on_complete, GRPC_ERROR_NONE); 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				         gpr_free(pp); 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				       } 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				-      update_lb_connectivity_status(exec_ctx, sd, error); 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				-      sd->prev_connectivity_state = sd->curr_connectivity_state; 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				-      /* renew notification: reuses the "rr_connectivity" weak ref */ 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				-      grpc_subchannel_notify_on_state_change( 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				-          exec_ctx, sd->subchannel, p->base.interested_parties, 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				-          &sd->curr_connectivity_state, &sd->connectivity_changed_closure); 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				-      break; 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				-    case GRPC_CHANNEL_IDLE: 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				-      ++p->num_idle; 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				-    /* fallthrough */ 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				-    case GRPC_CHANNEL_CONNECTING: 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				-      update_state_counters(sd); 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				-      update_lb_connectivity_status(exec_ctx, sd, error); 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				-      sd->prev_connectivity_state = sd->curr_connectivity_state; 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				-      /* renew notification: reuses the "rr_connectivity" weak ref */ 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				-      grpc_subchannel_notify_on_state_change( 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				-          exec_ctx, sd->subchannel, p->base.interested_parties, 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				-          &sd->curr_connectivity_state, &sd->connectivity_changed_closure); 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				-      break; 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				-    case GRPC_CHANNEL_TRANSIENT_FAILURE: 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				-      ++p->num_transient_failures; 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				-      /* remove from ready list if still present */ 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				-      if (sd->ready_list_node != NULL) { 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				-        remove_disconnected_sc_locked(p, sd->ready_list_node); 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				-        sd->ready_list_node = NULL; 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				-      } 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				-      update_lb_connectivity_status(exec_ctx, sd, error); 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				-      sd->prev_connectivity_state = sd->curr_connectivity_state; 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				-      /* renew notification: reuses the "rr_connectivity" weak ref */ 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				-      grpc_subchannel_notify_on_state_change( 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				-          exec_ctx, sd->subchannel, p->base.interested_parties, 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				-          &sd->curr_connectivity_state, &sd->connectivity_changed_closure); 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				-      break; 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				-    case GRPC_CHANNEL_SHUTDOWN: 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				-      update_state_counters(sd); 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				-      if (sd->ready_list_node != NULL) { 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				-        remove_disconnected_sc_locked(p, sd->ready_list_node); 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				-        sd->ready_list_node = NULL; 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				-      } 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				-      --p->num_subchannels; 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				-      GPR_SWAP(subchannel_data *, p->subchannels[sd->index], 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				-               p->subchannels[p->num_subchannels]); 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				-      GRPC_SUBCHANNEL_UNREF(exec_ctx, sd->subchannel, "rr_subchannel_shutdown"); 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				-      p->subchannels[sd->index]->index = sd->index; 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				-      if (update_lb_connectivity_status(exec_ctx, sd, error) == 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				-          GRPC_CHANNEL_SHUTDOWN) { 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				-        /* the policy is shutting down. Flush all the pending picks... */ 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				-        while ((pp = p->pending_picks)) { 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				-          p->pending_picks = pp->next; 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				-          *pp->target = NULL; 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				-          grpc_closure_sched(exec_ctx, pp->on_complete, GRPC_ERROR_NONE); 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				-          gpr_free(pp); 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				-        } 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				-      } 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				-      gpr_free(sd); 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				-      /* unref the "rr_connectivity" weak ref from start_picking */ 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				-      GRPC_LB_POLICY_WEAK_UNREF(exec_ctx, &p->base, "rr_connectivity"); 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				-      break; 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+    } 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+    /* renew notification: reuses the "rr_connectivity" weak ref */ 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+    grpc_subchannel_notify_on_state_change( 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+        exec_ctx, sd->subchannel, p->base.interested_parties, 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+        &sd->pending_connectivity_state_unsafe, 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+        &sd->connectivity_changed_closure); 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				   } 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				-  GRPC_ERROR_UNREF(error); 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				 } 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				  
			 | 
		
	
		
			
				 | 
				 | 
			
			
				 static grpc_connectivity_state rr_check_connectivity_locked( 
			 | 
		
	
	
		
			
				| 
					
				 | 
			
			
				@@ -654,10 +543,10 @@ static void rr_notify_on_state_change_locked(grpc_exec_ctx *exec_ctx, 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				 static void rr_ping_one_locked(grpc_exec_ctx *exec_ctx, grpc_lb_policy *pol, 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				                                grpc_closure *closure) { 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				   round_robin_lb_policy *p = (round_robin_lb_policy *)pol; 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				-  ready_list *selected; 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				-  grpc_connected_subchannel *target; 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				-  if ((selected = peek_next_connected_locked(p))) { 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				-    target = GRPC_CONNECTED_SUBCHANNEL_REF( 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+  const size_t next_ready_index = get_next_ready_subchannel_index_locked(p); 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+  if (next_ready_index < p->num_subchannels) { 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+    subchannel_data *selected = &p->subchannels[next_ready_index]; 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+    grpc_connected_subchannel *target = GRPC_CONNECTED_SUBCHANNEL_REF( 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				         grpc_subchannel_get_connected_subchannel(selected->subchannel), 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				         "rr_picked"); 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				     grpc_connected_subchannel_ping(exec_ctx, target, closure); 
			 | 
		
	
	
		
			
				| 
					
				 | 
			
			
				@@ -708,7 +597,7 @@ static grpc_lb_policy *round_robin_create(grpc_exec_ctx *exec_ctx, 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				   p->subchannels = gpr_zalloc(sizeof(*p->subchannels) * num_addrs); 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				  
			 | 
		
	
		
			
				 | 
				 | 
			
			
				   grpc_subchannel_args sc_args; 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				-  size_t subchannel_idx = 0; 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+  size_t subchannel_index = 0; 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				   for (size_t i = 0; i < addresses->num_addresses; i++) { 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				     /* Skip balancer addresses, since we only know how to handle backends. */ 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				     if (addresses->addresses[i].is_balancer) continue; 
			 | 
		
	
	
		
			
				| 
					
				 | 
			
			
				@@ -727,42 +616,44 @@ static grpc_lb_policy *round_robin_create(grpc_exec_ctx *exec_ctx, 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				     if (GRPC_TRACER_ON(grpc_lb_round_robin_trace)) { 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				       char *address_uri = 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				           grpc_sockaddr_to_uri(&addresses->addresses[i].address); 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				-      gpr_log(GPR_DEBUG, "Created subchannel %p for address uri %s", 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				-              (void *)subchannel, address_uri); 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+      gpr_log(GPR_DEBUG, "index %zu: Created subchannel %p for address uri %s", 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+              subchannel_index, (void *)subchannel, address_uri); 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				       gpr_free(address_uri); 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				     } 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				     grpc_channel_args_destroy(exec_ctx, new_args); 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				  
			 | 
		
	
		
			
				 | 
				 | 
			
			
				     if (subchannel != NULL) { 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				-      subchannel_data *sd = gpr_zalloc(sizeof(*sd)); 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				-      p->subchannels[subchannel_idx] = sd; 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+      subchannel_data *sd = &p->subchannels[subchannel_index]; 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				       sd->policy = p; 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				-      sd->index = subchannel_idx; 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				       sd->subchannel = subchannel; 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+      /* use some sentinel value outside of the range of grpc_connectivity_state 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+       * to signal an undefined previous state. We won't be referring to this 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+       * value again and it'll be overwritten after the first call to 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+       * rr_connectivity_changed */ 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+      sd->prev_connectivity_state = GRPC_CHANNEL_INIT; 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+      sd->curr_connectivity_state = GRPC_CHANNEL_IDLE; 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				       sd->user_data_vtable = addresses->user_data_vtable; 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				       if (sd->user_data_vtable != NULL) { 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				         sd->user_data = 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				             sd->user_data_vtable->copy(addresses->addresses[i].user_data); 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				       } 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				-      ++subchannel_idx; 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				       grpc_closure_init(&sd->connectivity_changed_closure, 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				                         rr_connectivity_changed_locked, sd, 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				                         grpc_combiner_scheduler(args->combiner, false)); 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+      ++subchannel_index; 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				     } 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				   } 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				-  if (subchannel_idx == 0) { 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+  if (subchannel_index == 0) { 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				     /* couldn't create any subchannel. Bail out */ 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				     gpr_free(p->subchannels); 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				     gpr_free(p); 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				     return NULL; 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				   } 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				-  p->num_subchannels = subchannel_idx; 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+  p->num_subchannels = subchannel_index; 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				  
			 | 
		
	
		
			
				 | 
				 | 
			
			
				-  /* The (dummy node) root of the ready list */ 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				-  p->ready_list.subchannel = NULL; 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				-  p->ready_list.prev = NULL; 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				-  p->ready_list.next = NULL; 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				-  p->ready_list_last_pick = &p->ready_list; 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+  // Initialize the last pick index to the last subchannel, so that the 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+  // first pick will start at the beginning of the list. 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+  p->last_ready_subchannel_index = subchannel_index - 1; 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				  
			 | 
		
	
		
			
				 | 
				 | 
			
			
				   grpc_lb_policy_init(&p->base, &round_robin_lb_policy_vtable, args->combiner); 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				   grpc_connectivity_state_init(&p->state_tracker, GRPC_CHANNEL_IDLE, 
			 |