| 
					
				 | 
			
			
				@@ -108,13 +108,16 @@ 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				  
			 | 
		
	
		
			
				 | 
				 | 
			
			
				 #include "src/core/ext/filters/client_channel/client_channel.h" 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				 #include "src/core/ext/filters/client_channel/client_channel_factory.h" 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+#include "src/core/ext/filters/client_channel/lb_policy/grpclb/client_load_reporting_filter.h" 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				 #include "src/core/ext/filters/client_channel/lb_policy/grpclb/grpclb.h" 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				 #include "src/core/ext/filters/client_channel/lb_policy/grpclb/grpclb_channel.h" 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+#include "src/core/ext/filters/client_channel/lb_policy/grpclb/grpclb_client_stats.h" 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				 #include "src/core/ext/filters/client_channel/lb_policy/grpclb/load_balancer_api.h" 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				 #include "src/core/ext/filters/client_channel/lb_policy_factory.h" 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				 #include "src/core/ext/filters/client_channel/lb_policy_registry.h" 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				 #include "src/core/ext/filters/client_channel/parse_address.h" 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				 #include "src/core/lib/channel/channel_args.h" 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+#include "src/core/lib/channel/channel_stack.h" 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				 #include "src/core/lib/iomgr/combiner.h" 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				 #include "src/core/lib/iomgr/sockaddr.h" 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				 #include "src/core/lib/iomgr/sockaddr_utils.h" 
			 | 
		
	
	
		
			
				| 
					
				 | 
			
			
				@@ -126,6 +129,7 @@ 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				 #include "src/core/lib/support/string.h" 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				 #include "src/core/lib/surface/call.h" 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				 #include "src/core/lib/surface/channel.h" 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+#include "src/core/lib/surface/channel_init.h" 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				 #include "src/core/lib/transport/static_metadata.h" 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				  
			 | 
		
	
		
			
				 | 
				 | 
			
			
				 #define GRPC_GRPCLB_MIN_CONNECT_TIMEOUT_SECONDS 20 
			 | 
		
	
	
		
			
				| 
					
				 | 
			
			
				@@ -147,6 +151,10 @@ static grpc_error *initial_metadata_add_lb_token( 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				                                       lb_token_mdelem_storage, lb_token); 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				 } 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				  
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+static void destroy_client_stats(void *arg) { 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+  grpc_grpclb_client_stats_unref(arg); 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+} 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+ 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				 typedef struct wrapped_rr_closure_arg { 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				   /* the closure instance using this struct as argument */ 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				   grpc_closure wrapper_closure; 
			 | 
		
	
	
		
			
				| 
					
				 | 
			
			
				@@ -163,6 +171,13 @@ typedef struct wrapped_rr_closure_arg { 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				    * initial metadata */ 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				   grpc_connected_subchannel **target; 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				  
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+  /* the context to be populated for the subchannel call */ 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+  grpc_call_context_element *context; 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+ 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+  /* Stats for client-side load reporting. Note that this holds a 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+   * reference, which must be either passed on via context or unreffed. */ 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+  grpc_grpclb_client_stats *client_stats; 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+ 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				   /* the LB token associated with the pick */ 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				   grpc_mdelem lb_token; 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				  
			 | 
		
	
	
		
			
				| 
					
				 | 
			
			
				@@ -202,6 +217,12 @@ static void wrapped_rr_closure(grpc_exec_ctx *exec_ctx, void *arg, 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				                 (void *)*wc_arg->target, (void *)wc_arg->rr_policy); 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				         abort(); 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				       } 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+      // Pass on client stats via context. Passes ownership of the reference. 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+      GPR_ASSERT(wc_arg->client_stats != NULL); 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+      wc_arg->context[GRPC_GRPCLB_CLIENT_STATS].value = wc_arg->client_stats; 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+      wc_arg->context[GRPC_GRPCLB_CLIENT_STATS].destroy = destroy_client_stats; 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+    } else { 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+      grpc_grpclb_client_stats_unref(wc_arg->client_stats); 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				     } 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				     if (grpc_lb_glb_trace) { 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				       gpr_log(GPR_INFO, "Unreffing RR %p", (void *)wc_arg->rr_policy); 
			 | 
		
	
	
		
			
				| 
					
				 | 
			
			
				@@ -237,6 +258,7 @@ typedef struct pending_pick { 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				 static void add_pending_pick(pending_pick **root, 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				                              const grpc_lb_policy_pick_args *pick_args, 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				                              grpc_connected_subchannel **target, 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+                             grpc_call_context_element *context, 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				                              grpc_closure *on_complete) { 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				   pending_pick *pp = gpr_zalloc(sizeof(*pp)); 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				   pp->next = *root; 
			 | 
		
	
	
		
			
				| 
					
				 | 
			
			
				@@ -244,6 +266,7 @@ static void add_pending_pick(pending_pick **root, 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				   pp->target = target; 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				   pp->wrapped_on_complete_arg.wrapped_closure = on_complete; 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				   pp->wrapped_on_complete_arg.target = target; 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+  pp->wrapped_on_complete_arg.context = context; 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				   pp->wrapped_on_complete_arg.initial_metadata = pick_args->initial_metadata; 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				   pp->wrapped_on_complete_arg.lb_token_mdelem_storage = 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				       pick_args->lb_token_mdelem_storage; 
			 | 
		
	
	
		
			
				| 
					
				 | 
			
			
				@@ -316,6 +339,10 @@ typedef struct glb_lb_policy { 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				   /************************************************************/ 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				   /*  client data associated with the LB server communication */ 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				   /************************************************************/ 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+ 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+  /* Finished sending initial request. */ 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+  grpc_closure lb_on_sent_initial_request; 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+ 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				   /* Status from the LB server has been received. This signals the end of the LB 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				    * call. */ 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				   grpc_closure lb_on_server_status_received; 
			 | 
		
	
	
		
			
				| 
					
				 | 
			
			
				@@ -348,6 +375,23 @@ typedef struct glb_lb_policy { 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				  
			 | 
		
	
		
			
				 | 
				 | 
			
			
				   /** LB call retry timer */ 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				   grpc_timer lb_call_retry_timer; 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+ 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+  bool initial_request_sent; 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+  bool seen_initial_response; 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+ 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+  /* Stats for client-side load reporting. Should be unreffed and 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+   * recreated whenever lb_call is replaced. */ 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+  grpc_grpclb_client_stats *client_stats; 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+  /* Interval and timer for next client load report. */ 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+  gpr_timespec client_stats_report_interval; 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+  grpc_timer client_load_report_timer; 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+  bool client_load_report_timer_pending; 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+  bool last_client_load_report_counters_were_zero; 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+  /* Closure used for either the load report timer or the callback for 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+   * completion of sending the load report. */ 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+  grpc_closure client_load_report_closure; 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+  /* Client load report message payload. */ 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+  grpc_byte_buffer *client_load_report_payload; 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				 } glb_lb_policy; 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				  
			 | 
		
	
		
			
				 | 
				 | 
			
			
				 /* Keeps track and reacts to changes in connectivity of the RR instance */ 
			 | 
		
	
	
		
			
				| 
					
				 | 
			
			
				@@ -552,8 +596,8 @@ static bool pick_from_internal_rr_locked( 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				     grpc_connected_subchannel **target, wrapped_rr_closure_arg *wc_arg) { 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				   GPR_ASSERT(rr_policy != NULL); 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				   const bool pick_done = grpc_lb_policy_pick_locked( 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				-      exec_ctx, rr_policy, pick_args, target, (void **)&wc_arg->lb_token, 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				-      &wc_arg->wrapper_closure); 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+      exec_ctx, rr_policy, pick_args, target, wc_arg->context, 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+      (void **)&wc_arg->lb_token, &wc_arg->wrapper_closure); 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				   if (pick_done) { 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				     /* synchronous grpc_lb_policy_pick call. Unref the RR policy. */ 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				     if (grpc_lb_glb_trace) { 
			 | 
		
	
	
		
			
				| 
					
				 | 
			
			
				@@ -567,7 +611,12 @@ static bool pick_from_internal_rr_locked( 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				                                   pick_args->lb_token_mdelem_storage, 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				                                   GRPC_MDELEM_REF(wc_arg->lb_token)); 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				  
			 | 
		
	
		
			
				 | 
				 | 
			
			
				-    gpr_free(wc_arg); 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+    // Pass on client stats via context. Passes ownership of the reference. 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+    GPR_ASSERT(wc_arg->client_stats != NULL); 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+    wc_arg->context[GRPC_GRPCLB_CLIENT_STATS].value = wc_arg->client_stats; 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+    wc_arg->context[GRPC_GRPCLB_CLIENT_STATS].destroy = destroy_client_stats; 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+ 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+    gpr_free(wc_arg->free_when_done); 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				   } 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				   /* else, the pending pick will be registered and taken care of by the 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				    * pending pick list inside the RR policy (glb_policy->rr_policy). 
			 | 
		
	
	
		
			
				| 
					
				 | 
			
			
				@@ -690,6 +739,8 @@ static void rr_handover_locked(grpc_exec_ctx *exec_ctx, 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				     glb_policy->pending_picks = pp->next; 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				     GRPC_LB_POLICY_REF(glb_policy->rr_policy, "rr_handover_pending_pick"); 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				     pp->wrapped_on_complete_arg.rr_policy = glb_policy->rr_policy; 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+    pp->wrapped_on_complete_arg.client_stats = 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+        grpc_grpclb_client_stats_ref(glb_policy->client_stats); 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				     if (grpc_lb_glb_trace) { 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				       gpr_log(GPR_INFO, "Pending pick about to PICK from 0x%" PRIxPTR "", 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				               (intptr_t)glb_policy->rr_policy); 
			 | 
		
	
	
		
			
				| 
					
				 | 
			
			
				@@ -864,9 +915,18 @@ static grpc_lb_policy *glb_create(grpc_exec_ctx *exec_ctx, 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				   grpc_uri_destroy(uri); 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				  
			 | 
		
	
		
			
				 | 
				 | 
			
			
				   glb_policy->cc_factory = args->client_channel_factory; 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				-  glb_policy->args = grpc_channel_args_copy(args->args); 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				   GPR_ASSERT(glb_policy->cc_factory != NULL); 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				  
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+  // Make sure that GRPC_ARG_LB_POLICY_NAME is set in channel args, 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+  // since we use this to trigger the client_load_reporting filter. 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+  grpc_arg new_arg; 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+  new_arg.key = GRPC_ARG_LB_POLICY_NAME; 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+  new_arg.type = GRPC_ARG_STRING; 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+  new_arg.value.string = "grpclb"; 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+  static const char *args_to_remove[] = {GRPC_ARG_LB_POLICY_NAME}; 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+  glb_policy->args = grpc_channel_args_copy_and_add_and_remove( 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+      args->args, args_to_remove, GPR_ARRAY_SIZE(args_to_remove), &new_arg, 1); 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+ 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				   grpc_slice_hash_table *targets_info = NULL; 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				   /* Create a client channel over them to communicate with a LB service */ 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				   char *lb_service_target_addresses = 
			 | 
		
	
	
		
			
				| 
					
				 | 
			
			
				@@ -880,6 +940,8 @@ static grpc_lb_policy *glb_create(grpc_exec_ctx *exec_ctx, 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				   grpc_channel_args_destroy(exec_ctx, lb_channel_args); 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				   gpr_free(lb_service_target_addresses); 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				   if (glb_policy->lb_channel == NULL) { 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+    gpr_free((void *)glb_policy->server_name); 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+    grpc_channel_args_destroy(exec_ctx, glb_policy->args); 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				     gpr_free(glb_policy); 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				     return NULL; 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				   } 
			 | 
		
	
	
		
			
				| 
					
				 | 
			
			
				@@ -895,6 +957,9 @@ static void glb_destroy(grpc_exec_ctx *exec_ctx, grpc_lb_policy *pol) { 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				   GPR_ASSERT(glb_policy->pending_pings == NULL); 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				   gpr_free((void *)glb_policy->server_name); 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				   grpc_channel_args_destroy(exec_ctx, glb_policy->args); 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+  if (glb_policy->client_stats != NULL) { 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+    grpc_grpclb_client_stats_unref(glb_policy->client_stats); 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+  } 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				   grpc_channel_destroy(glb_policy->lb_channel); 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				   glb_policy->lb_channel = NULL; 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				   grpc_connectivity_state_destroy(exec_ctx, &glb_policy->state_tracker); 
			 | 
		
	
	
		
			
				| 
					
				 | 
			
			
				@@ -1011,7 +1076,8 @@ static void glb_exit_idle_locked(grpc_exec_ctx *exec_ctx, grpc_lb_policy *pol) { 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				  
			 | 
		
	
		
			
				 | 
				 | 
			
			
				 static int glb_pick_locked(grpc_exec_ctx *exec_ctx, grpc_lb_policy *pol, 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				                            const grpc_lb_policy_pick_args *pick_args, 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				-                           grpc_connected_subchannel **target, void **user_data, 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+                           grpc_connected_subchannel **target, 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+                           grpc_call_context_element *context, void **user_data, 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				                            grpc_closure *on_complete) { 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				   if (pick_args->lb_token_mdelem_storage == NULL) { 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				     *target = NULL; 
			 | 
		
	
	
		
			
				| 
					
				 | 
			
			
				@@ -1039,6 +1105,10 @@ static int glb_pick_locked(grpc_exec_ctx *exec_ctx, grpc_lb_policy *pol, 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				                       grpc_schedule_on_exec_ctx); 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				     wc_arg->rr_policy = glb_policy->rr_policy; 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				     wc_arg->target = target; 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+    wc_arg->context = context; 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+    GPR_ASSERT(glb_policy->client_stats != NULL); 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+    wc_arg->client_stats = 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+        grpc_grpclb_client_stats_ref(glb_policy->client_stats); 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				     wc_arg->wrapped_closure = on_complete; 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				     wc_arg->lb_token_mdelem_storage = pick_args->lb_token_mdelem_storage; 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				     wc_arg->initial_metadata = pick_args->initial_metadata; 
			 | 
		
	
	
		
			
				| 
					
				 | 
			
			
				@@ -1052,7 +1122,7 @@ static int glb_pick_locked(grpc_exec_ctx *exec_ctx, grpc_lb_policy *pol, 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				               "picks", 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				               (void *)(glb_policy)); 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				     } 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				-    add_pending_pick(&glb_policy->pending_picks, pick_args, target, 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+    add_pending_pick(&glb_policy->pending_picks, pick_args, target, context, 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				                      on_complete); 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				  
			 | 
		
	
		
			
				 | 
				 | 
			
			
				     if (!glb_policy->started_picking) { 
			 | 
		
	
	
		
			
				| 
					
				 | 
			
			
				@@ -1093,6 +1163,104 @@ static void glb_notify_on_state_change_locked(grpc_exec_ctx *exec_ctx, 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				       exec_ctx, &glb_policy->state_tracker, current, notify); 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				 } 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				  
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+static void send_client_load_report_locked(grpc_exec_ctx *exec_ctx, void *arg, 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+                                           grpc_error *error); 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+ 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+static void schedule_next_client_load_report(grpc_exec_ctx *exec_ctx, 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+                                             glb_lb_policy *glb_policy) { 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+  const gpr_timespec now = gpr_now(GPR_CLOCK_MONOTONIC); 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+  const gpr_timespec next_client_load_report_time = 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+      gpr_time_add(now, glb_policy->client_stats_report_interval); 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+  grpc_closure_init(&glb_policy->client_load_report_closure, 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+                    send_client_load_report_locked, glb_policy, 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+                    grpc_combiner_scheduler(glb_policy->base.combiner, false)); 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+  grpc_timer_init(exec_ctx, &glb_policy->client_load_report_timer, 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+                  next_client_load_report_time, 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+                  &glb_policy->client_load_report_closure, now); 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+} 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+ 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+static void client_load_report_done_locked(grpc_exec_ctx *exec_ctx, void *arg, 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+                                           grpc_error *error) { 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+  glb_lb_policy *glb_policy = arg; 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+  grpc_byte_buffer_destroy(glb_policy->client_load_report_payload); 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+  glb_policy->client_load_report_payload = NULL; 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+  if (error != GRPC_ERROR_NONE || glb_policy->lb_call == NULL) { 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+    glb_policy->client_load_report_timer_pending = false; 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+    GRPC_LB_POLICY_WEAK_UNREF(exec_ctx, &glb_policy->base, 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+                              "client_load_report"); 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+    return; 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+  } 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+  schedule_next_client_load_report(exec_ctx, glb_policy); 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+} 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+ 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+static void do_send_client_load_report_locked(grpc_exec_ctx *exec_ctx, 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+                                              glb_lb_policy *glb_policy) { 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+  grpc_op op; 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+  memset(&op, 0, sizeof(op)); 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+  op.op = GRPC_OP_SEND_MESSAGE; 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+  op.data.send_message.send_message = glb_policy->client_load_report_payload; 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+  grpc_closure_init(&glb_policy->client_load_report_closure, 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+                    client_load_report_done_locked, glb_policy, 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+                    grpc_combiner_scheduler(glb_policy->base.combiner, false)); 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+  grpc_call_error call_error = grpc_call_start_batch_and_execute( 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+      exec_ctx, glb_policy->lb_call, &op, 1, 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+      &glb_policy->client_load_report_closure); 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+  GPR_ASSERT(GRPC_CALL_OK == call_error); 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+} 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+ 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+static bool load_report_counters_are_zero(grpc_grpclb_request *request) { 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+  return request->client_stats.num_calls_started == 0 && 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+         request->client_stats.num_calls_finished == 0 && 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+         request->client_stats.num_calls_finished_with_drop_for_rate_limiting == 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+             0 && 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+         request->client_stats 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+                 .num_calls_finished_with_drop_for_load_balancing == 0 && 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+         request->client_stats.num_calls_finished_with_client_failed_to_send == 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+             0 && 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+         request->client_stats.num_calls_finished_known_received == 0; 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+} 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+ 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+static void send_client_load_report_locked(grpc_exec_ctx *exec_ctx, void *arg, 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+                                           grpc_error *error) { 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+  glb_lb_policy *glb_policy = arg; 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+  if (error == GRPC_ERROR_CANCELLED || glb_policy->lb_call == NULL) { 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+    glb_policy->client_load_report_timer_pending = false; 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+    GRPC_LB_POLICY_WEAK_UNREF(exec_ctx, &glb_policy->base, 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+                              "client_load_report"); 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+    return; 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+  } 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+  // Construct message payload. 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+  GPR_ASSERT(glb_policy->client_load_report_payload == NULL); 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+  grpc_grpclb_request *request = 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+      grpc_grpclb_load_report_request_create(glb_policy->client_stats); 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+  // Skip client load report if the counters were all zero in the last 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+  // report and they are still zero in this one. 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+  if (load_report_counters_are_zero(request)) { 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+    if (glb_policy->last_client_load_report_counters_were_zero) { 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+      grpc_grpclb_request_destroy(request); 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+      schedule_next_client_load_report(exec_ctx, glb_policy); 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+      return; 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+    } 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+    glb_policy->last_client_load_report_counters_were_zero = true; 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+  } else { 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+    glb_policy->last_client_load_report_counters_were_zero = false; 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+  } 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+  grpc_slice request_payload_slice = grpc_grpclb_request_encode(request); 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+  glb_policy->client_load_report_payload = 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+      grpc_raw_byte_buffer_create(&request_payload_slice, 1); 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+  grpc_slice_unref_internal(exec_ctx, request_payload_slice); 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+  grpc_grpclb_request_destroy(request); 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+  // If we've already sent the initial request, then we can go ahead and 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+  // sent the load report.  Otherwise, we need to wait until the initial 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+  // request has been sent to send this 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+  // (see lb_on_sent_initial_request_locked() below). 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+  if (glb_policy->initial_request_sent) { 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+    do_send_client_load_report_locked(exec_ctx, glb_policy); 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+  } 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+} 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+ 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+static void lb_on_sent_initial_request_locked(grpc_exec_ctx *exec_ctx, 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+                                              void *arg, grpc_error *error); 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				 static void lb_on_server_status_received_locked(grpc_exec_ctx *exec_ctx, 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				                                                 void *arg, grpc_error *error); 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				 static void lb_on_response_received_locked(grpc_exec_ctx *exec_ctx, void *arg, 
			 | 
		
	
	
		
			
				| 
					
				 | 
			
			
				@@ -1114,6 +1282,11 @@ static void lb_call_init_locked(grpc_exec_ctx *exec_ctx, 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				       &host, glb_policy->deadline, NULL); 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				   grpc_slice_unref_internal(exec_ctx, host); 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				  
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+  if (glb_policy->client_stats != NULL) { 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+    grpc_grpclb_client_stats_unref(glb_policy->client_stats); 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+  } 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+  glb_policy->client_stats = grpc_grpclb_client_stats_create(); 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+ 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				   grpc_metadata_array_init(&glb_policy->lb_initial_metadata_recv); 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				   grpc_metadata_array_init(&glb_policy->lb_trailing_metadata_recv); 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				  
			 | 
		
	
	
		
			
				| 
					
				 | 
			
			
				@@ -1125,6 +1298,9 @@ static void lb_call_init_locked(grpc_exec_ctx *exec_ctx, 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				   grpc_slice_unref_internal(exec_ctx, request_payload_slice); 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				   grpc_grpclb_request_destroy(request); 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				  
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+  grpc_closure_init(&glb_policy->lb_on_sent_initial_request, 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+                    lb_on_sent_initial_request_locked, glb_policy, 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+                    grpc_combiner_scheduler(glb_policy->base.combiner, false)); 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				   grpc_closure_init(&glb_policy->lb_on_server_status_received, 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				                     lb_on_server_status_received_locked, glb_policy, 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				                     grpc_combiner_scheduler(glb_policy->base.combiner, false)); 
			 | 
		
	
	
		
			
				| 
					
				 | 
			
			
				@@ -1138,6 +1314,10 @@ static void lb_call_init_locked(grpc_exec_ctx *exec_ctx, 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				                    GRPC_GRPCLB_RECONNECT_JITTER, 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				                    GRPC_GRPCLB_MIN_CONNECT_TIMEOUT_SECONDS * 1000, 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				                    GRPC_GRPCLB_RECONNECT_MAX_BACKOFF_SECONDS * 1000); 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+ 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+  glb_policy->initial_request_sent = false; 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+  glb_policy->seen_initial_response = false; 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+  glb_policy->last_client_load_report_counters_were_zero = false; 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				 } 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				  
			 | 
		
	
		
			
				 | 
				 | 
			
			
				 static void lb_call_destroy_locked(grpc_exec_ctx *exec_ctx, 
			 | 
		
	
	
		
			
				| 
					
				 | 
			
			
				@@ -1151,6 +1331,10 @@ static void lb_call_destroy_locked(grpc_exec_ctx *exec_ctx, 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				  
			 | 
		
	
		
			
				 | 
				 | 
			
			
				   grpc_byte_buffer_destroy(glb_policy->lb_request_payload); 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				   grpc_slice_unref_internal(exec_ctx, glb_policy->lb_call_status_details); 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+ 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+  if (!glb_policy->client_load_report_timer_pending) { 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+    grpc_timer_cancel(exec_ctx, &glb_policy->client_load_report_timer); 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+  } 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				 } 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				  
			 | 
		
	
		
			
				 | 
				 | 
			
			
				 /* 
			 | 
		
	
	
		
			
				| 
					
				 | 
			
			
				@@ -1179,21 +1363,27 @@ static void query_for_backends_locked(grpc_exec_ctx *exec_ctx, 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				   op->flags = 0; 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				   op->reserved = NULL; 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				   op++; 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				- 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				   op->op = GRPC_OP_RECV_INITIAL_METADATA; 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				   op->data.recv_initial_metadata.recv_initial_metadata = 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				       &glb_policy->lb_initial_metadata_recv; 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				   op->flags = 0; 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				   op->reserved = NULL; 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				   op++; 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				- 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				   GPR_ASSERT(glb_policy->lb_request_payload != NULL); 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				   op->op = GRPC_OP_SEND_MESSAGE; 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				   op->data.send_message.send_message = glb_policy->lb_request_payload; 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				   op->flags = 0; 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				   op->reserved = NULL; 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				   op++; 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+  /* take a weak ref (won't prevent calling of \a glb_shutdown if the strong ref 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+   * count goes to zero) to be unref'd in lb_on_sent_initial_request_locked() */ 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+  GRPC_LB_POLICY_WEAK_REF(&glb_policy->base, "lb_on_server_status_received"); 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+  call_error = grpc_call_start_batch_and_execute( 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+      exec_ctx, glb_policy->lb_call, ops, (size_t)(op - ops), 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+      &glb_policy->lb_on_sent_initial_request); 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+  GPR_ASSERT(GRPC_CALL_OK == call_error); 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				  
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+  op = ops; 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				   op->op = GRPC_OP_RECV_STATUS_ON_CLIENT; 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				   op->data.recv_status_on_client.trailing_metadata = 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				       &glb_policy->lb_trailing_metadata_recv; 
			 | 
		
	
	
		
			
				| 
					
				 | 
			
			
				@@ -1225,6 +1415,19 @@ static void query_for_backends_locked(grpc_exec_ctx *exec_ctx, 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				   GPR_ASSERT(GRPC_CALL_OK == call_error); 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				 } 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				  
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+static void lb_on_sent_initial_request_locked(grpc_exec_ctx *exec_ctx, 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+                                              void *arg, grpc_error *error) { 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+  glb_lb_policy *glb_policy = arg; 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+  glb_policy->initial_request_sent = true; 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+  // If we attempted to send a client load report before the initial 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+  // request was sent, send the load report now. 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+  if (glb_policy->client_load_report_payload != NULL) { 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+    do_send_client_load_report_locked(exec_ctx, glb_policy); 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+  } 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+  GRPC_LB_POLICY_WEAK_UNREF(exec_ctx, &glb_policy->base, 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+                            "lb_on_response_received_locked"); 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+} 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+ 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				 static void lb_on_response_received_locked(grpc_exec_ctx *exec_ctx, void *arg, 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				                                            grpc_error *error) { 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				   glb_lb_policy *glb_policy = arg; 
			 | 
		
	
	
		
			
				| 
					
				 | 
			
			
				@@ -1240,58 +1443,91 @@ static void lb_on_response_received_locked(grpc_exec_ctx *exec_ctx, void *arg, 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				     grpc_byte_buffer_reader_init(&bbr, glb_policy->lb_response_payload); 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				     grpc_slice response_slice = grpc_byte_buffer_reader_readall(&bbr); 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				     grpc_byte_buffer_destroy(glb_policy->lb_response_payload); 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				-    grpc_grpclb_serverlist *serverlist = 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				-        grpc_grpclb_response_parse_serverlist(response_slice); 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				-    if (serverlist != NULL) { 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				-      GPR_ASSERT(glb_policy->lb_call != NULL); 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				-      grpc_slice_unref_internal(exec_ctx, response_slice); 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				-      if (grpc_lb_glb_trace) { 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				-        gpr_log(GPR_INFO, "Serverlist with %lu servers received", 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				-                (unsigned long)serverlist->num_servers); 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				-        for (size_t i = 0; i < serverlist->num_servers; ++i) { 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				-          grpc_resolved_address addr; 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				-          parse_server(serverlist->servers[i], &addr); 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				-          char *ipport; 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				-          grpc_sockaddr_to_string(&ipport, &addr, false); 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				-          gpr_log(GPR_INFO, "Serverlist[%lu]: %s", (unsigned long)i, ipport); 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				-          gpr_free(ipport); 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+ 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+    grpc_grpclb_initial_response *response = NULL; 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+    if (!glb_policy->seen_initial_response && 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+        (response = grpc_grpclb_initial_response_parse(response_slice)) != 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+            NULL) { 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+      if (response->has_client_stats_report_interval) { 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+        glb_policy->client_stats_report_interval = 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+            gpr_time_max(gpr_time_from_seconds(1, GPR_TIMESPAN), 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+                         grpc_grpclb_duration_to_timespec( 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+                             &response->client_stats_report_interval)); 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+        if (grpc_lb_glb_trace) { 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+          gpr_log(GPR_INFO, 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+                  "received initial LB response message; " 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+                  "client load reporting interval = %" PRId64 ".%09d sec", 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+                  glb_policy->client_stats_report_interval.tv_sec, 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+                  glb_policy->client_stats_report_interval.tv_nsec); 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				         } 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+        /* take a weak ref (won't prevent calling of \a glb_shutdown() if the 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+         * strong ref count goes to zero) to be unref'd in 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+         * send_client_load_report() */ 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+        glb_policy->client_load_report_timer_pending = true; 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+        GRPC_LB_POLICY_WEAK_REF(&glb_policy->base, "client_load_report"); 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+        schedule_next_client_load_report(exec_ctx, glb_policy); 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+      } else if (grpc_lb_glb_trace) { 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+        gpr_log(GPR_INFO, 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+                "received initial LB response message; " 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+                "client load reporting NOT enabled"); 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				       } 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+      grpc_grpclb_initial_response_destroy(response); 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+      glb_policy->seen_initial_response = true; 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+    } else { 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+      grpc_grpclb_serverlist *serverlist = 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+          grpc_grpclb_response_parse_serverlist(response_slice); 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+      if (serverlist != NULL) { 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+        GPR_ASSERT(glb_policy->lb_call != NULL); 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+        if (grpc_lb_glb_trace) { 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+          gpr_log(GPR_INFO, "Serverlist with %lu servers received", 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+                  (unsigned long)serverlist->num_servers); 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+          for (size_t i = 0; i < serverlist->num_servers; ++i) { 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+            grpc_resolved_address addr; 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+            parse_server(serverlist->servers[i], &addr); 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+            char *ipport; 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+            grpc_sockaddr_to_string(&ipport, &addr, false); 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+            gpr_log(GPR_INFO, "Serverlist[%lu]: %s", (unsigned long)i, ipport); 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+            gpr_free(ipport); 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+          } 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+        } 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				  
			 | 
		
	
		
			
				 | 
				 | 
			
			
				-      /* update serverlist */ 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				-      if (serverlist->num_servers > 0) { 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				-        if (grpc_grpclb_serverlist_equals(glb_policy->serverlist, serverlist)) { 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+        /* update serverlist */ 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+        if (serverlist->num_servers > 0) { 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+          if (grpc_grpclb_serverlist_equals(glb_policy->serverlist, 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+                                            serverlist)) { 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+            if (grpc_lb_glb_trace) { 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+              gpr_log(GPR_INFO, 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+                      "Incoming server list identical to current, ignoring."); 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+            } 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+            grpc_grpclb_destroy_serverlist(serverlist); 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+          } else { /* new serverlist */ 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+            if (glb_policy->serverlist != NULL) { 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+              /* dispose of the old serverlist */ 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+              grpc_grpclb_destroy_serverlist(glb_policy->serverlist); 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+            } 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+            /* and update the copy in the glb_lb_policy instance. This 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+             * serverlist instance will be destroyed either upon the next 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+             * update or in glb_destroy() */ 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+            glb_policy->serverlist = serverlist; 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+ 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+            rr_handover_locked(exec_ctx, glb_policy); 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+          } 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+        } else { 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				           if (grpc_lb_glb_trace) { 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				             gpr_log(GPR_INFO, 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				-                    "Incoming server list identical to current, ignoring."); 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+                    "Received empty server list. Picks will stay pending until " 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+                    "a response with > 0 servers is received"); 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				           } 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				           grpc_grpclb_destroy_serverlist(serverlist); 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				-        } else { /* new serverlist */ 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				-          if (glb_policy->serverlist != NULL) { 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				-            /* dispose of the old serverlist */ 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				-            grpc_grpclb_destroy_serverlist(glb_policy->serverlist); 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				-          } 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				-          /* and update the copy in the glb_lb_policy instance. This serverlist 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				-           * instance will be destroyed either upon the next update or in 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				-           * glb_destroy() */ 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				-          glb_policy->serverlist = serverlist; 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				- 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				-          rr_handover_locked(exec_ctx, glb_policy); 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				         } 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				-      } else { 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				-        if (grpc_lb_glb_trace) { 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				-          gpr_log(GPR_INFO, 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				-                  "Received empty server list. Picks will stay pending until a " 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				-                  "response with > 0 servers is received"); 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				-        } 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				-        grpc_grpclb_destroy_serverlist(serverlist); 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+      } else { /* serverlist == NULL */ 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+        gpr_log(GPR_ERROR, "Invalid LB response received: '%s'. Ignoring.", 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+                grpc_dump_slice(response_slice, GPR_DUMP_ASCII | GPR_DUMP_HEX)); 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				       } 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				-    } else { /* serverlist == NULL */ 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				-      gpr_log(GPR_ERROR, "Invalid LB response received: '%s'. Ignoring.", 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				-              grpc_dump_slice(response_slice, GPR_DUMP_ASCII | GPR_DUMP_HEX)); 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				-      grpc_slice_unref_internal(exec_ctx, response_slice); 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				     } 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				  
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+    grpc_slice_unref_internal(exec_ctx, response_slice); 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+ 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				     if (!glb_policy->shutting_down) { 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				       /* keep listening for serverlist updates */ 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				       op->op = GRPC_OP_RECV_MESSAGE; 
			 | 
		
	
	
		
			
				| 
					
				 | 
			
			
				@@ -1403,9 +1639,29 @@ grpc_lb_policy_factory *grpc_glb_lb_factory_create() { 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				 } 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				  
			 | 
		
	
		
			
				 | 
				 | 
			
			
				 /* Plugin registration */ 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+ 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+// Only add client_load_reporting filter if the grpclb LB policy is used. 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+static bool maybe_add_client_load_reporting_filter( 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+    grpc_exec_ctx *exec_ctx, grpc_channel_stack_builder *builder, void *arg) { 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+  const grpc_channel_args *args = 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+      grpc_channel_stack_builder_get_channel_arguments(builder); 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+  const grpc_arg *channel_arg = 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+      grpc_channel_args_find(args, GRPC_ARG_LB_POLICY_NAME); 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+  if (channel_arg != NULL && channel_arg->type == GRPC_ARG_STRING && 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+      strcmp(channel_arg->value.string, "grpclb") == 0) { 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+    return grpc_channel_stack_builder_append_filter( 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+        builder, (const grpc_channel_filter *)arg, NULL, NULL); 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+  } 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+  return true; 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+} 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+ 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				 void grpc_lb_policy_grpclb_init() { 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				   grpc_register_lb_policy(grpc_glb_lb_factory_create()); 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				   grpc_register_tracer("glb", &grpc_lb_glb_trace); 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+  grpc_channel_init_register_stage(GRPC_CLIENT_SUBCHANNEL, 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+                                   GRPC_CHANNEL_INIT_BUILTIN_PRIORITY, 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+                                   maybe_add_client_load_reporting_filter, 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+                                   (void *)&grpc_client_load_reporting_filter); 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				 } 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				  
			 | 
		
	
		
			
				 | 
				 | 
			
			
				 void grpc_lb_policy_grpclb_shutdown() {} 
			 |