|  | @@ -77,6 +77,14 @@ static void wrapped_rr_closure(grpc_exec_ctx *exec_ctx, void *arg,
 | 
	
		
			
				|  |  |    gpr_free(wc);
 | 
	
		
			
				|  |  |  }
 | 
	
		
			
				|  |  |  
 | 
	
		
			
				|  |  | +/* Linked list of pending pick requests. It stores all information needed to
 | 
	
		
			
				|  |  | + * eventually call (Round Robin's) pick() on them. They mainly stay pending
 | 
	
		
			
				|  |  | + * waiting for the RR policy to be created/updated.
 | 
	
		
			
				|  |  | + *
 | 
	
		
			
				|  |  | + * One particularity is the wrapping of the user-provided \a on_complete closure
 | 
	
		
			
				|  |  | + * (in \a wrapped_on_complete and \a wrapped_on_complete_arg). This is needed in
 | 
	
		
			
				|  |  | + * order to correctly unref the RR policy instance upon completion of the pick.
 | 
	
		
			
				|  |  | + * See \a wrapped_rr_closure for details. */
 | 
	
		
			
				|  |  |  typedef struct pending_pick {
 | 
	
		
			
				|  |  |    struct pending_pick *next;
 | 
	
		
			
				|  |  |    grpc_polling_entity *pollent;
 | 
	
	
		
			
				|  | @@ -87,6 +95,7 @@ typedef struct pending_pick {
 | 
	
		
			
				|  |  |    wrapped_rr_closure_arg *wrapped_on_complete_arg;
 | 
	
		
			
				|  |  |  } pending_pick;
 | 
	
		
			
				|  |  |  
 | 
	
		
			
				|  |  | +/* Same as the \a pending_pick struct but for ping operations */
 | 
	
		
			
				|  |  |  typedef struct pending_ping {
 | 
	
		
			
				|  |  |    struct pending_ping *next;
 | 
	
		
			
				|  |  |    grpc_closure *wrapped_notify;
 | 
	
	
		
			
				|  | @@ -95,7 +104,7 @@ typedef struct pending_ping {
 | 
	
		
			
				|  |  |  
 | 
	
		
			
				|  |  |  typedef struct glb_lb_policy glb_lb_policy;
 | 
	
		
			
				|  |  |  
 | 
	
		
			
				|  |  | -#define MAX_LBCD_OPS_LEN 6
 | 
	
		
			
				|  |  | +/* Used internally for the client call to the LB */
 | 
	
		
			
				|  |  |  typedef struct lb_client_data {
 | 
	
		
			
				|  |  |    gpr_mu mu;
 | 
	
		
			
				|  |  |    grpc_closure md_sent;
 | 
	
	
		
			
				|  | @@ -138,7 +147,7 @@ struct glb_lb_policy {
 | 
	
		
			
				|  |  |    grpc_client_channel_factory *cc_factory;
 | 
	
		
			
				|  |  |  
 | 
	
		
			
				|  |  |    /** for communicating with the LB server */
 | 
	
		
			
				|  |  | -  grpc_channel *lb_server_channel;
 | 
	
		
			
				|  |  | +  grpc_channel *lb_channel;
 | 
	
		
			
				|  |  |  
 | 
	
		
			
				|  |  |    /** the RR policy to use of the backend servers returned by the LB server */
 | 
	
		
			
				|  |  |    grpc_lb_policy *rr_policy;
 | 
	
	
		
			
				|  | @@ -148,15 +157,17 @@ struct glb_lb_policy {
 | 
	
		
			
				|  |  |    /** our connectivity state tracker */
 | 
	
		
			
				|  |  |    grpc_connectivity_state_tracker state_tracker;
 | 
	
		
			
				|  |  |  
 | 
	
		
			
				|  |  | +  /** stores the deserialized response from the LB. May be NULL until one such
 | 
	
		
			
				|  |  | +   * response has arrived. */
 | 
	
		
			
				|  |  |    grpc_grpclb_serverlist *serverlist;
 | 
	
		
			
				|  |  |  
 | 
	
		
			
				|  |  | -  /** list of picks that are waiting on connectivity */
 | 
	
		
			
				|  |  | +  /** list of picks that are waiting on RR's policy connectivity */
 | 
	
		
			
				|  |  |    pending_pick *pending_picks;
 | 
	
		
			
				|  |  |  
 | 
	
		
			
				|  |  | -  /** list of pings that are waiting on connectivity */
 | 
	
		
			
				|  |  | +  /** list of pings that are waiting on RR's policy connectivity */
 | 
	
		
			
				|  |  |    pending_ping *pending_pings;
 | 
	
		
			
				|  |  |  
 | 
	
		
			
				|  |  | -  /** data associated with the communication with the LB server */
 | 
	
		
			
				|  |  | +  /** client data associated with the LB server communication */
 | 
	
		
			
				|  |  |    lb_client_data *lbcd;
 | 
	
		
			
				|  |  |  
 | 
	
		
			
				|  |  |    /** for tracking of the RR connectivity */
 | 
	
	
		
			
				|  | @@ -175,12 +186,12 @@ static void rr_connectivity_changed(grpc_exec_ctx *exec_ctx, void *arg,
 | 
	
		
			
				|  |  |         * perform a handover */
 | 
	
		
			
				|  |  |        rr_handover(exec_ctx, p, error);
 | 
	
		
			
				|  |  |      } else {
 | 
	
		
			
				|  |  | -      /* shutting down and no new serverlist available. bail out. */
 | 
	
		
			
				|  |  | +      /* shutting down and no new serverlist available. Bail out. */
 | 
	
		
			
				|  |  |        gpr_free(rrcd);
 | 
	
		
			
				|  |  |      }
 | 
	
		
			
				|  |  |    } else {
 | 
	
		
			
				|  |  |      if (error == GRPC_ERROR_NONE) {
 | 
	
		
			
				|  |  | -      /* not shutting down. mimic the RR's policy state */
 | 
	
		
			
				|  |  | +      /* RR not shutting down. Mimic the RR's policy state */
 | 
	
		
			
				|  |  |        grpc_connectivity_state_set(exec_ctx, &p->state_tracker, rrcd->state,
 | 
	
		
			
				|  |  |                                    error, "rr_connectivity_changed");
 | 
	
		
			
				|  |  |        /* resubscribe */
 | 
	
	
		
			
				|  | @@ -281,50 +292,62 @@ static void req_sent_cb(grpc_exec_ctx *exec_ctx, void *arg, grpc_error *error) {
 | 
	
		
			
				|  |  |  }
 | 
	
		
			
				|  |  |  
 | 
	
		
			
				|  |  |  static void res_rcvd_cb(grpc_exec_ctx *exec_ctx, void *arg, grpc_error *error) {
 | 
	
		
			
				|  |  | -  /* look inside lbcd->response_payload, ideally to send it back as the
 | 
	
		
			
				|  |  | -   * serverlist. */
 | 
	
		
			
				|  |  |    lb_client_data *lbcd = arg;
 | 
	
		
			
				|  |  |    grpc_op ops[2];
 | 
	
		
			
				|  |  |    memset(ops, 0, sizeof(ops));
 | 
	
		
			
				|  |  |    grpc_op *op = ops;
 | 
	
		
			
				|  |  | -  if (lbcd->response_payload) {
 | 
	
		
			
				|  |  | +  if (lbcd->response_payload != NULL) {
 | 
	
		
			
				|  |  | +    /* Received data from the LB server. Look inside lbcd->response_payload, for
 | 
	
		
			
				|  |  | +     * a serverlist. */
 | 
	
		
			
				|  |  |      grpc_byte_buffer_reader bbr;
 | 
	
		
			
				|  |  |      grpc_byte_buffer_reader_init(&bbr, lbcd->response_payload);
 | 
	
		
			
				|  |  |      gpr_slice response_slice = grpc_byte_buffer_reader_readall(&bbr);
 | 
	
		
			
				|  |  |      grpc_byte_buffer_destroy(lbcd->response_payload);
 | 
	
		
			
				|  |  |      grpc_grpclb_serverlist *serverlist =
 | 
	
		
			
				|  |  |          grpc_grpclb_response_parse_serverlist(response_slice);
 | 
	
		
			
				|  |  | -    if (serverlist) {
 | 
	
		
			
				|  |  | +    if (serverlist != NULL) {
 | 
	
		
			
				|  |  |        gpr_slice_unref(response_slice);
 | 
	
		
			
				|  |  |        if (grpc_lb_glb_trace) {
 | 
	
		
			
				|  |  |          gpr_log(GPR_INFO, "Serverlist with %zu servers received",
 | 
	
		
			
				|  |  |                  serverlist->num_servers);
 | 
	
		
			
				|  |  |        }
 | 
	
		
			
				|  |  | +
 | 
	
		
			
				|  |  |        /* update serverlist */
 | 
	
		
			
				|  |  |        if (serverlist->num_servers > 0) {
 | 
	
		
			
				|  |  |          if (grpc_grpclb_serverlist_equals(lbcd->p->serverlist, serverlist)) {
 | 
	
		
			
				|  |  | -          gpr_log(GPR_INFO,
 | 
	
		
			
				|  |  | -                  "Incoming server list identical to current, ignoring.");
 | 
	
		
			
				|  |  | -        } else {
 | 
	
		
			
				|  |  | +          if (grpc_lb_glb_trace) {
 | 
	
		
			
				|  |  | +            gpr_log(GPR_INFO,
 | 
	
		
			
				|  |  | +                    "Incoming server list identical to current, ignoring.");
 | 
	
		
			
				|  |  | +          }
 | 
	
		
			
				|  |  | +        } else { /* new serverlist */
 | 
	
		
			
				|  |  |            if (lbcd->p->serverlist != NULL) {
 | 
	
		
			
				|  |  | +            /* dispose of the old serverlist */
 | 
	
		
			
				|  |  |              grpc_grpclb_destroy_serverlist(lbcd->p->serverlist);
 | 
	
		
			
				|  |  |            }
 | 
	
		
			
				|  |  | +          /* and update the copy in the glb_lb_policy instance */
 | 
	
		
			
				|  |  |            lbcd->p->serverlist = serverlist;
 | 
	
		
			
				|  |  |          }
 | 
	
		
			
				|  |  | -      }
 | 
	
		
			
				|  |  | -      if (lbcd->p->rr_policy == NULL) {
 | 
	
		
			
				|  |  | -        /* initial "handover", in this case from a null RR policy, meaning it'll
 | 
	
		
			
				|  |  | -         * just create the first one */
 | 
	
		
			
				|  |  | -        rr_handover(exec_ctx, lbcd->p, error);
 | 
	
		
			
				|  |  | +        if (lbcd->p->rr_policy == NULL) {
 | 
	
		
			
				|  |  | +          /* initial "handover", in this case from a null RR policy, meaning
 | 
	
		
			
				|  |  | +           * it'll
 | 
	
		
			
				|  |  | +           * just create the first RR policy instance */
 | 
	
		
			
				|  |  | +          rr_handover(exec_ctx, lbcd->p, error);
 | 
	
		
			
				|  |  | +        } else {
 | 
	
		
			
				|  |  | +          /* unref the RR policy, eventually leading to its substitution with a
 | 
	
		
			
				|  |  | +           * new one constructed from the received serverlist (see
 | 
	
		
			
				|  |  | +           * rr_connectivity_changed) */
 | 
	
		
			
				|  |  | +          GRPC_LB_POLICY_UNREF(exec_ctx, lbcd->p->rr_policy,
 | 
	
		
			
				|  |  | +                               "serverlist_received");
 | 
	
		
			
				|  |  | +        }
 | 
	
		
			
				|  |  |        } else {
 | 
	
		
			
				|  |  | -        /* unref the RR policy, eventually leading to its substitution with a
 | 
	
		
			
				|  |  | -         * new one constructed from the received serverlist (see
 | 
	
		
			
				|  |  | -         * rr_connectivity_changed) */
 | 
	
		
			
				|  |  | -        GRPC_LB_POLICY_UNREF(exec_ctx, lbcd->p->rr_policy,
 | 
	
		
			
				|  |  | -                             "serverlist_received");
 | 
	
		
			
				|  |  | +        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");
 | 
	
		
			
				|  |  | +        }
 | 
	
		
			
				|  |  |        }
 | 
	
		
			
				|  |  |  
 | 
	
		
			
				|  |  | -      /* listen for a potential serverlist update */
 | 
	
		
			
				|  |  | +      /* keep listening for serverlist updates */
 | 
	
		
			
				|  |  |        op->op = GRPC_OP_RECV_MESSAGE;
 | 
	
		
			
				|  |  |        op->data.recv_message = &lbcd->response_payload;
 | 
	
		
			
				|  |  |        op->flags = 0;
 | 
	
	
		
			
				|  | @@ -335,24 +358,26 @@ static void res_rcvd_cb(grpc_exec_ctx *exec_ctx, void *arg, grpc_error *error) {
 | 
	
		
			
				|  |  |            &lbcd->res_rcvd); /* loop */
 | 
	
		
			
				|  |  |        GPR_ASSERT(GRPC_CALL_OK == call_error);
 | 
	
		
			
				|  |  |        return;
 | 
	
		
			
				|  |  | -    } else {
 | 
	
		
			
				|  |  | -      gpr_log(GPR_ERROR, "Invalid LB response received: '%s'",
 | 
	
		
			
				|  |  | -              gpr_dump_slice(response_slice, GPR_DUMP_ASCII));
 | 
	
		
			
				|  |  | -      gpr_slice_unref(response_slice);
 | 
	
		
			
				|  |  | -
 | 
	
		
			
				|  |  | -      /* Disconnect from server returning invalid response. */
 | 
	
		
			
				|  |  | -      op->op = GRPC_OP_SEND_CLOSE_FROM_CLIENT;
 | 
	
		
			
				|  |  | -      op->flags = 0;
 | 
	
		
			
				|  |  | -      op->reserved = NULL;
 | 
	
		
			
				|  |  | -      op++;
 | 
	
		
			
				|  |  | -      grpc_call_error call_error = grpc_call_start_batch_and_execute(
 | 
	
		
			
				|  |  | -          exec_ctx, lbcd->c, ops, (size_t)(op - ops), &lbcd->close_sent);
 | 
	
		
			
				|  |  | -      GPR_ASSERT(GRPC_CALL_OK == call_error);
 | 
	
		
			
				|  |  |      }
 | 
	
		
			
				|  |  | +
 | 
	
		
			
				|  |  | +    GPR_ASSERT(serverlist == NULL);
 | 
	
		
			
				|  |  | +    gpr_log(GPR_ERROR, "Invalid LB response received: '%s'",
 | 
	
		
			
				|  |  | +            gpr_dump_slice(response_slice, GPR_DUMP_ASCII));
 | 
	
		
			
				|  |  | +    gpr_slice_unref(response_slice);
 | 
	
		
			
				|  |  | +
 | 
	
		
			
				|  |  | +    /* Disconnect from server returning invalid response. */
 | 
	
		
			
				|  |  | +    op->op = GRPC_OP_SEND_CLOSE_FROM_CLIENT;
 | 
	
		
			
				|  |  | +    op->flags = 0;
 | 
	
		
			
				|  |  | +    op->reserved = NULL;
 | 
	
		
			
				|  |  | +    op++;
 | 
	
		
			
				|  |  | +    grpc_call_error call_error = grpc_call_start_batch_and_execute(
 | 
	
		
			
				|  |  | +        exec_ctx, lbcd->c, ops, (size_t)(op - ops), &lbcd->close_sent);
 | 
	
		
			
				|  |  | +    GPR_ASSERT(GRPC_CALL_OK == call_error);
 | 
	
		
			
				|  |  |    }
 | 
	
		
			
				|  |  |    /* empty payload: call cancelled by server. Cleanups happening in
 | 
	
		
			
				|  |  |     * srv_status_rcvd_cb */
 | 
	
		
			
				|  |  |  }
 | 
	
		
			
				|  |  | +
 | 
	
		
			
				|  |  |  static void close_sent_cb(grpc_exec_ctx *exec_ctx, void *arg,
 | 
	
		
			
				|  |  |                            grpc_error *error) {
 | 
	
		
			
				|  |  |    if (grpc_lb_glb_trace) {
 | 
	
	
		
			
				|  | @@ -360,21 +385,22 @@ static void close_sent_cb(grpc_exec_ctx *exec_ctx, void *arg,
 | 
	
		
			
				|  |  |              "Close from LB client sent. Waiting from server status now");
 | 
	
		
			
				|  |  |    }
 | 
	
		
			
				|  |  |  }
 | 
	
		
			
				|  |  | +
 | 
	
		
			
				|  |  |  static void srv_status_rcvd_cb(grpc_exec_ctx *exec_ctx, void *arg,
 | 
	
		
			
				|  |  |                                 grpc_error *error) {
 | 
	
		
			
				|  |  |    lb_client_data *lbcd = arg;
 | 
	
		
			
				|  |  |    glb_lb_policy *p = lbcd->p;
 | 
	
		
			
				|  |  |    if (grpc_lb_glb_trace) {
 | 
	
		
			
				|  |  | -    gpr_log(
 | 
	
		
			
				|  |  | -        GPR_INFO,
 | 
	
		
			
				|  |  | -        "status from lb server received. Status = %d, Details = '%s', Capaticy "
 | 
	
		
			
				|  |  | -        "= %zu",
 | 
	
		
			
				|  |  | -        lbcd->status, lbcd->status_details, lbcd->status_details_capacity);
 | 
	
		
			
				|  |  | +    gpr_log(GPR_INFO,
 | 
	
		
			
				|  |  | +            "status from lb server received. Status = %d, Details = '%s', "
 | 
	
		
			
				|  |  | +            "Capaticy "
 | 
	
		
			
				|  |  | +            "= %zu",
 | 
	
		
			
				|  |  | +            lbcd->status, lbcd->status_details, lbcd->status_details_capacity);
 | 
	
		
			
				|  |  |    }
 | 
	
		
			
				|  |  |  
 | 
	
		
			
				|  |  |    grpc_call_destroy(lbcd->c);
 | 
	
		
			
				|  |  | -  grpc_channel_destroy(lbcd->p->lb_server_channel);
 | 
	
		
			
				|  |  | -  lbcd->p->lb_server_channel = NULL;
 | 
	
		
			
				|  |  | +  grpc_channel_destroy(lbcd->p->lb_channel);
 | 
	
		
			
				|  |  | +  lbcd->p->lb_channel = NULL;
 | 
	
		
			
				|  |  |    lb_client_data_destroy(lbcd);
 | 
	
		
			
				|  |  |    p->lbcd = NULL;
 | 
	
		
			
				|  |  |  }
 | 
	
	
		
			
				|  | @@ -392,16 +418,14 @@ static lb_client_data *lb_client_data_create(glb_lb_policy *p) {
 | 
	
		
			
				|  |  |    grpc_closure_init(&lbcd->close_sent, close_sent_cb, lbcd);
 | 
	
		
			
				|  |  |    grpc_closure_init(&lbcd->srv_status_rcvd, srv_status_rcvd_cb, lbcd);
 | 
	
		
			
				|  |  |  
 | 
	
		
			
				|  |  | -  /* TODO(dgq): get the deadline from the client/user instead of fabricating
 | 
	
		
			
				|  |  | -   * one
 | 
	
		
			
				|  |  | -   * here. Make it a policy arg? */
 | 
	
		
			
				|  |  | +  /* TODO(dgq): get the deadline from the client config instead of fabricating
 | 
	
		
			
				|  |  | +   * one here. */
 | 
	
		
			
				|  |  |    lbcd->deadline = gpr_time_add(gpr_now(GPR_CLOCK_MONOTONIC),
 | 
	
		
			
				|  |  |                                  gpr_time_from_seconds(3, GPR_TIMESPAN));
 | 
	
		
			
				|  |  |  
 | 
	
		
			
				|  |  |    lbcd->c = grpc_channel_create_pollset_set_call(
 | 
	
		
			
				|  |  | -      p->lb_server_channel, NULL, GRPC_PROPAGATE_DEFAULTS,
 | 
	
		
			
				|  |  | -      p->base.interested_parties, "/BalanceLoad",
 | 
	
		
			
				|  |  | -      NULL, /* FIXME(dgq): which "host" value to use? */
 | 
	
		
			
				|  |  | +      p->lb_channel, NULL, GRPC_PROPAGATE_DEFAULTS, p->base.interested_parties,
 | 
	
		
			
				|  |  | +      "/BalanceLoad", NULL, /* FIXME(dgq): which "host" value to use? */
 | 
	
		
			
				|  |  |        lbcd->deadline, NULL);
 | 
	
		
			
				|  |  |  
 | 
	
		
			
				|  |  |    grpc_metadata_array_init(&lbcd->initial_metadata_recv);
 | 
	
	
		
			
				|  | @@ -409,7 +433,9 @@ static lb_client_data *lb_client_data_create(glb_lb_policy *p) {
 | 
	
		
			
				|  |  |  
 | 
	
		
			
				|  |  |    grpc_grpclb_request *request = grpc_grpclb_request_create(
 | 
	
		
			
				|  |  |        "load.balanced.service.name"); /* FIXME(dgq): get the name of the load
 | 
	
		
			
				|  |  | -                                        balanced service from above. */
 | 
	
		
			
				|  |  | +                                        balanced service from somewhere
 | 
	
		
			
				|  |  | +                                        (client
 | 
	
		
			
				|  |  | +                                        config?). */
 | 
	
		
			
				|  |  |    gpr_slice request_payload_slice = grpc_grpclb_request_encode(request);
 | 
	
		
			
				|  |  |    lbcd->request_payload =
 | 
	
		
			
				|  |  |        grpc_raw_byte_buffer_create(&request_payload_slice, 1);
 | 
	
	
		
			
				|  | @@ -536,7 +562,7 @@ static void glb_cancel_picks(grpc_exec_ctx *exec_ctx, grpc_lb_policy *pol,
 | 
	
		
			
				|  |  |  }
 | 
	
		
			
				|  |  |  
 | 
	
		
			
				|  |  |  static void query_for_backends(grpc_exec_ctx *exec_ctx, glb_lb_policy *p) {
 | 
	
		
			
				|  |  | -  GPR_ASSERT(p->lb_server_channel != NULL);
 | 
	
		
			
				|  |  | +  GPR_ASSERT(p->lb_channel != NULL);
 | 
	
		
			
				|  |  |  
 | 
	
		
			
				|  |  |    p->lbcd = lb_client_data_create(p);
 | 
	
		
			
				|  |  |    grpc_call_error call_error;
 | 
	
	
		
			
				|  | @@ -612,10 +638,8 @@ static grpc_lb_policy *create_rr(grpc_exec_ctx *exec_ctx,
 | 
	
		
			
				|  |  |      gpr_free(host_ports[i]);
 | 
	
		
			
				|  |  |    }
 | 
	
		
			
				|  |  |    gpr_free(host_ports);
 | 
	
		
			
				|  |  | -
 | 
	
		
			
				|  |  |    gpr_free(args.addresses->addrs);
 | 
	
		
			
				|  |  |    gpr_free(args.addresses);
 | 
	
		
			
				|  |  | -
 | 
	
		
			
				|  |  |    return rr;
 | 
	
		
			
				|  |  |  }
 | 
	
		
			
				|  |  |  
 | 
	
	
		
			
				|  | @@ -709,7 +733,7 @@ static int glb_pick(grpc_exec_ctx *exec_ctx, grpc_lb_policy *pol,
 | 
	
		
			
				|  |  |                              wrapped_on_complete);
 | 
	
		
			
				|  |  |      if (r != 0) {
 | 
	
		
			
				|  |  |        /* the call to grpc_lb_policy_pick has been sychronous. Invoke a neutered
 | 
	
		
			
				|  |  | -       * wrapped closure */
 | 
	
		
			
				|  |  | +       * wrapped closure: it'll only take care of unreffing the RR policy */
 | 
	
		
			
				|  |  |        warg->wrapped_closure = NULL;
 | 
	
		
			
				|  |  |        grpc_exec_ctx_sched(exec_ctx, wrapped_on_complete, GRPC_ERROR_NONE, NULL);
 | 
	
		
			
				|  |  |      }
 | 
	
	
		
			
				|  | @@ -808,7 +832,7 @@ static grpc_lb_policy *glb_create(grpc_exec_ctx *exec_ctx,
 | 
	
		
			
				|  |  |        (const char **)addr_strs, args->addresses->naddrs, ",", &uri_path_len);
 | 
	
		
			
				|  |  |  
 | 
	
		
			
				|  |  |    /* will pick using pick_first */
 | 
	
		
			
				|  |  | -  p->lb_server_channel = grpc_client_channel_factory_create_channel(
 | 
	
		
			
				|  |  | +  p->lb_channel = grpc_client_channel_factory_create_channel(
 | 
	
		
			
				|  |  |        exec_ctx, p->cc_factory, target_uri_str,
 | 
	
		
			
				|  |  |        GRPC_CLIENT_CHANNEL_TYPE_LOAD_BALANCING, NULL);
 | 
	
		
			
				|  |  |  
 | 
	
	
		
			
				|  | @@ -818,7 +842,7 @@ static grpc_lb_policy *glb_create(grpc_exec_ctx *exec_ctx,
 | 
	
		
			
				|  |  |    }
 | 
	
		
			
				|  |  |    gpr_free(addr_strs);
 | 
	
		
			
				|  |  |  
 | 
	
		
			
				|  |  | -  if (p->lb_server_channel == NULL) {
 | 
	
		
			
				|  |  | +  if (p->lb_channel == NULL) {
 | 
	
		
			
				|  |  |      gpr_free(p);
 | 
	
		
			
				|  |  |      return NULL;
 | 
	
		
			
				|  |  |    }
 |