blob: d0acd7a90192a2dc75b457cdc8414e75a9d5f2c3 [file] [log] [blame]
Craig Tiller3bc8ebd2015-06-24 15:41:15 -07001/*
2 *
Jan Tattermusch7897ae92017-06-07 22:57:36 +02003 * Copyright 2015 gRPC authors.
Craig Tiller3bc8ebd2015-06-24 15:41:15 -07004 *
Jan Tattermusch7897ae92017-06-07 22:57:36 +02005 * Licensed under the Apache License, Version 2.0 (the "License");
6 * you may not use this file except in compliance with the License.
7 * You may obtain a copy of the License at
Craig Tiller3bc8ebd2015-06-24 15:41:15 -07008 *
Jan Tattermusch7897ae92017-06-07 22:57:36 +02009 * http://www.apache.org/licenses/LICENSE-2.0
Craig Tiller3bc8ebd2015-06-24 15:41:15 -070010 *
Jan Tattermusch7897ae92017-06-07 22:57:36 +020011 * Unless required by applicable law or agreed to in writing, software
12 * distributed under the License is distributed on an "AS IS" BASIS,
13 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
14 * See the License for the specific language governing permissions and
15 * limitations under the License.
Craig Tiller3bc8ebd2015-06-24 15:41:15 -070016 *
17 */
18
Craig Tillereb3b12e2015-06-26 14:42:49 -070019#include <string.h>
20
21#include <grpc/support/alloc.h>
Mark D. Roth5bd7be02016-10-21 14:19:50 -070022
Craig Tiller9eb0fde2017-03-31 16:59:30 -070023#include "src/core/ext/filters/client_channel/lb_policy_registry.h"
24#include "src/core/ext/filters/client_channel/subchannel.h"
David Garcia Quintas87d5a312017-06-06 19:45:58 -070025#include "src/core/ext/filters/client_channel/subchannel_index.h"
Mark D. Roth557c9902016-10-24 11:12:05 -070026#include "src/core/lib/channel/channel_args.h"
Craig Tiller2400bf52017-02-09 16:25:19 -080027#include "src/core/lib/iomgr/combiner.h"
Mark D. Roth0748f392017-01-13 09:22:44 -080028#include "src/core/lib/iomgr/sockaddr_utils.h"
Craig Tiller9533d042016-03-25 17:11:06 -070029#include "src/core/lib/transport/connectivity_state.h"
Craig Tillereb3b12e2015-06-26 14:42:49 -070030
David Garcia Quintas87d5a312017-06-06 19:45:58 -070031grpc_tracer_flag grpc_lb_pick_first_trace = GRPC_TRACER_INITIALIZER(false);
32
Craig Tillera82950e2015-09-22 12:33:20 -070033typedef struct pending_pick {
Craig Tillereb3b12e2015-06-26 14:42:49 -070034 struct pending_pick *next;
Craig Tiller8c0d96f2016-03-11 14:27:52 -080035 uint32_t initial_metadata_flags;
Craig Tillerb5585d42015-11-17 07:18:31 -080036 grpc_connected_subchannel **target;
Craig Tiller33825112015-09-18 07:44:19 -070037 grpc_closure *on_complete;
Craig Tillereb3b12e2015-06-26 14:42:49 -070038} pending_pick;
39
Craig Tillera82950e2015-09-22 12:33:20 -070040typedef struct {
Craig Tillereb3b12e2015-06-26 14:42:49 -070041 /** base policy: must be first */
42 grpc_lb_policy base;
Craig Tillereb3b12e2015-06-26 14:42:49 -070043 /** all our subchannels */
44 grpc_subchannel **subchannels;
David Garcia Quintas87d5a312017-06-06 19:45:58 -070045 grpc_subchannel **new_subchannels;
Craig Tillereb3b12e2015-06-26 14:42:49 -070046 size_t num_subchannels;
David Garcia Quintas87d5a312017-06-06 19:45:58 -070047 size_t num_new_subchannels;
Craig Tillereb3b12e2015-06-26 14:42:49 -070048
Craig Tiller33825112015-09-18 07:44:19 -070049 grpc_closure connectivity_changed;
Craig Tillereb3b12e2015-06-26 14:42:49 -070050
Craig Tiller2400bf52017-02-09 16:25:19 -080051 /** remaining members are protected by the combiner */
Craig Tiller320bee02016-01-06 17:33:45 -080052
Craig Tiller46dd7902017-02-23 09:42:16 -080053 /** the selected channel */
Craig Tiller2400bf52017-02-09 16:25:19 -080054 grpc_connected_subchannel *selected;
55
David Garcia Quintas87d5a312017-06-06 19:45:58 -070056 /** the subchannel key for \a selected, or NULL if \a selected not set */
57 const grpc_subchannel_key *selected_key;
58
Craig Tillereb3b12e2015-06-26 14:42:49 -070059 /** have we started picking? */
David Garcia Quintas87d5a312017-06-06 19:45:58 -070060 bool started_picking;
Craig Tillera14215a2015-07-17 17:21:08 -070061 /** are we shut down? */
David Garcia Quintas87d5a312017-06-06 19:45:58 -070062 bool shutdown;
63 /** are we updating the selected subchannel? */
64 bool updating_selected;
65 /** are we updating the subchannel candidates? */
66 bool updating_subchannels;
67 /** args from the latest update received while already updating, or NULL */
68 grpc_lb_policy_args *pending_update_args;
Craig Tillereb3b12e2015-06-26 14:42:49 -070069 /** which subchannel are we watching? */
70 size_t checking_subchannel;
71 /** what is the connectivity of that channel? */
72 grpc_connectivity_state checking_connectivity;
73 /** list of picks that are waiting on connectivity */
74 pending_pick *pending_picks;
Craig Tillerc7b5f762015-06-27 11:48:42 -070075
76 /** our connectivity state tracker */
77 grpc_connectivity_state_tracker state_tracker;
Craig Tillereb3b12e2015-06-26 14:42:49 -070078} pick_first_lb_policy;
79
Craig Tillerfb433852016-03-29 08:51:07 -070080static void pf_destroy(grpc_exec_ctx *exec_ctx, grpc_lb_policy *pol) {
Craig Tillera82950e2015-09-22 12:33:20 -070081 pick_first_lb_policy *p = (pick_first_lb_policy *)pol;
Craig Tillera82950e2015-09-22 12:33:20 -070082 GPR_ASSERT(p->pending_picks == NULL);
David Garcia Quintas87d5a312017-06-06 19:45:58 -070083 for (size_t i = 0; i < p->num_subchannels; i++) {
84 GRPC_SUBCHANNEL_UNREF(exec_ctx, p->subchannels[i], "pick_first_destroy");
Craig Tillera82950e2015-09-22 12:33:20 -070085 }
Craig Tiller2400bf52017-02-09 16:25:19 -080086 if (p->selected != NULL) {
David Garcia Quintas87d5a312017-06-06 19:45:58 -070087 GRPC_CONNECTED_SUBCHANNEL_UNREF(exec_ctx, p->selected,
88 "picked_first_destroy");
Craig Tiller89a768e2015-10-06 09:55:59 -070089 }
Craig Tillera82950e2015-09-22 12:33:20 -070090 grpc_connectivity_state_destroy(exec_ctx, &p->state_tracker);
David Garcia Quintas87d5a312017-06-06 19:45:58 -070091 if (p->pending_update_args != NULL) {
92 grpc_channel_args_destroy(exec_ctx, p->pending_update_args->args);
93 gpr_free(p->pending_update_args);
94 }
Craig Tillera82950e2015-09-22 12:33:20 -070095 gpr_free(p->subchannels);
David Garcia Quintas87d5a312017-06-06 19:45:58 -070096 gpr_free(p->new_subchannels);
Craig Tillera82950e2015-09-22 12:33:20 -070097 gpr_free(p);
David Garcia Quintasaf084dc2017-06-27 13:42:54 -070098 if (GRPC_TRACER_ON(grpc_lb_pick_first_trace)) {
99 gpr_log(GPR_DEBUG, "Pick First %p destroyed.", (void *)p);
100 }
Craig Tillereb3b12e2015-06-26 14:42:49 -0700101}
102
Craig Tiller2400bf52017-02-09 16:25:19 -0800103static void pf_shutdown_locked(grpc_exec_ctx *exec_ctx, grpc_lb_policy *pol) {
Craig Tillera82950e2015-09-22 12:33:20 -0700104 pick_first_lb_policy *p = (pick_first_lb_policy *)pol;
Craig Tillerd2cc4592015-07-01 07:50:47 -0700105 pending_pick *pp;
David Garcia Quintas87d5a312017-06-06 19:45:58 -0700106 p->shutdown = true;
Craig Tiller5795da72015-09-17 15:27:13 -0700107 pp = p->pending_picks;
108 p->pending_picks = NULL;
Craig Tiller804ff712016-05-05 16:25:40 -0700109 grpc_connectivity_state_set(
Craig Tillerd925c932016-06-06 08:38:50 -0700110 exec_ctx, &p->state_tracker, GRPC_CHANNEL_SHUTDOWN,
ncteisen4b36a3d2017-03-13 19:08:06 -0700111 GRPC_ERROR_CREATE_FROM_STATIC_STRING("Channel shutdown"), "shutdown");
Craig Tillerf036a642015-12-01 17:00:40 -0800112 /* cancel subscription */
Craig Tiller2400bf52017-02-09 16:25:19 -0800113 if (p->selected != NULL) {
Craig Tiller1d881fb2015-12-01 07:39:04 -0800114 grpc_connected_subchannel_notify_on_state_change(
Craig Tiller2400bf52017-02-09 16:25:19 -0800115 exec_ctx, p->selected, NULL, NULL, &p->connectivity_changed);
David Garcia Quintas87d5a312017-06-06 19:45:58 -0700116 } else if (p->num_subchannels > 0 && p->started_picking) {
Craig Tiller1d881fb2015-12-01 07:39:04 -0800117 grpc_subchannel_notify_on_state_change(
118 exec_ctx, p->subchannels[p->checking_subchannel], NULL, NULL,
119 &p->connectivity_changed);
Craig Tiller48613042015-11-29 14:45:11 -0800120 }
Craig Tillera82950e2015-09-22 12:33:20 -0700121 while (pp != NULL) {
122 pending_pick *next = pp->next;
123 *pp->target = NULL;
ncteisen274bbbe2017-06-08 14:57:11 -0700124 GRPC_CLOSURE_SCHED(exec_ctx, pp->on_complete, GRPC_ERROR_NONE);
Craig Tillera82950e2015-09-22 12:33:20 -0700125 gpr_free(pp);
126 pp = next;
127 }
Craig Tillereb3b12e2015-06-26 14:42:49 -0700128}
129
Craig Tiller2400bf52017-02-09 16:25:19 -0800130static void pf_cancel_pick_locked(grpc_exec_ctx *exec_ctx, grpc_lb_policy *pol,
131 grpc_connected_subchannel **target,
132 grpc_error *error) {
Craig Tiller577c9b22015-11-02 14:11:15 -0800133 pick_first_lb_policy *p = (pick_first_lb_policy *)pol;
134 pending_pick *pp;
Craig Tiller577c9b22015-11-02 14:11:15 -0800135 pp = p->pending_picks;
136 p->pending_picks = NULL;
137 while (pp != NULL) {
138 pending_pick *next = pp->next;
139 if (pp->target == target) {
Craig Tiller577c9b22015-11-02 14:11:15 -0800140 *target = NULL;
ncteisen274bbbe2017-06-08 14:57:11 -0700141 GRPC_CLOSURE_SCHED(exec_ctx, pp->on_complete,
ncteisen4b36a3d2017-03-13 19:08:06 -0700142 GRPC_ERROR_CREATE_REFERENCING_FROM_STATIC_STRING(
143 "Pick Cancelled", &error, 1));
Craig Tiller577c9b22015-11-02 14:11:15 -0800144 gpr_free(pp);
145 } else {
146 pp->next = p->pending_picks;
147 p->pending_picks = pp;
148 }
149 pp = next;
150 }
Mark D. Roth5f844002016-09-08 08:20:53 -0700151 GRPC_ERROR_UNREF(error);
Craig Tiller577c9b22015-11-02 14:11:15 -0800152}
153
Craig Tiller2400bf52017-02-09 16:25:19 -0800154static void pf_cancel_picks_locked(grpc_exec_ctx *exec_ctx, grpc_lb_policy *pol,
155 uint32_t initial_metadata_flags_mask,
156 uint32_t initial_metadata_flags_eq,
157 grpc_error *error) {
Craig Tiller8c0d96f2016-03-11 14:27:52 -0800158 pick_first_lb_policy *p = (pick_first_lb_policy *)pol;
159 pending_pick *pp;
Craig Tiller8c0d96f2016-03-11 14:27:52 -0800160 pp = p->pending_picks;
161 p->pending_picks = NULL;
162 while (pp != NULL) {
163 pending_pick *next = pp->next;
164 if ((pp->initial_metadata_flags & initial_metadata_flags_mask) ==
165 initial_metadata_flags_eq) {
ncteisen274bbbe2017-06-08 14:57:11 -0700166 GRPC_CLOSURE_SCHED(exec_ctx, pp->on_complete,
ncteisen4b36a3d2017-03-13 19:08:06 -0700167 GRPC_ERROR_CREATE_REFERENCING_FROM_STATIC_STRING(
168 "Pick Cancelled", &error, 1));
Craig Tiller8c0d96f2016-03-11 14:27:52 -0800169 gpr_free(pp);
170 } else {
171 pp->next = p->pending_picks;
172 p->pending_picks = pp;
173 }
174 pp = next;
175 }
Mark D. Rothe65ff112016-09-09 13:48:38 -0700176 GRPC_ERROR_UNREF(error);
Craig Tiller8c0d96f2016-03-11 14:27:52 -0800177}
178
David Garcia Quintas87d5a312017-06-06 19:45:58 -0700179static void start_picking_locked(grpc_exec_ctx *exec_ctx,
180 pick_first_lb_policy *p) {
181 p->started_picking = true;
182 if (p->subchannels != NULL) {
183 GPR_ASSERT(p->num_subchannels > 0);
184 p->checking_subchannel = 0;
185 p->checking_connectivity = GRPC_CHANNEL_IDLE;
186 GRPC_LB_POLICY_WEAK_REF(&p->base, "pick_first_connectivity");
187 grpc_subchannel_notify_on_state_change(
188 exec_ctx, p->subchannels[p->checking_subchannel],
189 p->base.interested_parties, &p->checking_connectivity,
190 &p->connectivity_changed);
191 }
Craig Tiller48cb07c2015-07-15 16:16:15 -0700192}
193
Craig Tiller2400bf52017-02-09 16:25:19 -0800194static void pf_exit_idle_locked(grpc_exec_ctx *exec_ctx, grpc_lb_policy *pol) {
Craig Tillera82950e2015-09-22 12:33:20 -0700195 pick_first_lb_policy *p = (pick_first_lb_policy *)pol;
Craig Tillera82950e2015-09-22 12:33:20 -0700196 if (!p->started_picking) {
David Garcia Quintas87d5a312017-06-06 19:45:58 -0700197 start_picking_locked(exec_ctx, p);
Craig Tillera82950e2015-09-22 12:33:20 -0700198 }
Craig Tillereb3b12e2015-06-26 14:42:49 -0700199}
200
Craig Tiller2400bf52017-02-09 16:25:19 -0800201static int pf_pick_locked(grpc_exec_ctx *exec_ctx, grpc_lb_policy *pol,
202 const grpc_lb_policy_pick_args *pick_args,
Mark D. Roth09e458c2017-05-02 08:13:26 -0700203 grpc_connected_subchannel **target,
204 grpc_call_context_element *context, void **user_data,
Craig Tiller2400bf52017-02-09 16:25:19 -0800205 grpc_closure *on_complete) {
Craig Tillera82950e2015-09-22 12:33:20 -0700206 pick_first_lb_policy *p = (pick_first_lb_policy *)pol;
Craig Tiller45724b32015-09-22 10:42:19 -0700207 pending_pick *pp;
Craig Tiller320bee02016-01-06 17:33:45 -0800208
209 /* Check atomically for a selected channel */
Craig Tiller2400bf52017-02-09 16:25:19 -0800210 if (p->selected != NULL) {
211 *target = GRPC_CONNECTED_SUBCHANNEL_REF(p->selected, "picked");
Craig Tiller86c0f8a2015-12-01 20:05:40 -0800212 return 1;
213 }
Craig Tiller320bee02016-01-06 17:33:45 -0800214
Craig Tiller46dd7902017-02-23 09:42:16 -0800215 /* No subchannel selected yet, so try again */
Craig Tiller2400bf52017-02-09 16:25:19 -0800216 if (!p->started_picking) {
David Garcia Quintas87d5a312017-06-06 19:45:58 -0700217 start_picking_locked(exec_ctx, p);
Craig Tillera82950e2015-09-22 12:33:20 -0700218 }
Craig Tiller2400bf52017-02-09 16:25:19 -0800219 pp = gpr_malloc(sizeof(*pp));
220 pp->next = p->pending_picks;
221 pp->target = target;
222 pp->initial_metadata_flags = pick_args->initial_metadata_flags;
223 pp->on_complete = on_complete;
224 p->pending_picks = pp;
225 return 0;
Craig Tiller45724b32015-09-22 10:42:19 -0700226}
227
Craig Tiller2400bf52017-02-09 16:25:19 -0800228static void destroy_subchannels_locked(grpc_exec_ctx *exec_ctx,
229 pick_first_lb_policy *p) {
Craig Tillerb09d84d2015-10-06 09:12:16 -0700230 size_t num_subchannels = p->num_subchannels;
David Garcia Quintas87d5a312017-06-06 19:45:58 -0700231 grpc_subchannel **subchannels = p->subchannels;
Craig Tillerb09d84d2015-10-06 09:12:16 -0700232
Craig Tillerb09d84d2015-10-06 09:12:16 -0700233 p->num_subchannels = 0;
234 p->subchannels = NULL;
Craig Tiller48613042015-11-29 14:45:11 -0800235 GRPC_LB_POLICY_WEAK_UNREF(exec_ctx, &p->base, "destroy_subchannels");
Craig Tillerb09d84d2015-10-06 09:12:16 -0700236
David Garcia Quintas87d5a312017-06-06 19:45:58 -0700237 for (size_t i = 0; i < num_subchannels; i++) {
Craig Tillerb09d84d2015-10-06 09:12:16 -0700238 GRPC_SUBCHANNEL_UNREF(exec_ctx, subchannels[i], "pick_first");
239 }
Craig Tillerb09d84d2015-10-06 09:12:16 -0700240 gpr_free(subchannels);
241}
242
David Garcia Quintas87d5a312017-06-06 19:45:58 -0700243static grpc_connectivity_state pf_check_connectivity_locked(
244 grpc_exec_ctx *exec_ctx, grpc_lb_policy *pol, grpc_error **error) {
245 pick_first_lb_policy *p = (pick_first_lb_policy *)pol;
246 return grpc_connectivity_state_get(&p->state_tracker, error);
247}
248
249static void pf_notify_on_state_change_locked(grpc_exec_ctx *exec_ctx,
250 grpc_lb_policy *pol,
251 grpc_connectivity_state *current,
252 grpc_closure *notify) {
253 pick_first_lb_policy *p = (pick_first_lb_policy *)pol;
254 grpc_connectivity_state_notify_on_state_change(exec_ctx, &p->state_tracker,
255 current, notify);
256}
257
258static void pf_ping_one_locked(grpc_exec_ctx *exec_ctx, grpc_lb_policy *pol,
259 grpc_closure *closure) {
260 pick_first_lb_policy *p = (pick_first_lb_policy *)pol;
261 if (p->selected) {
262 grpc_connected_subchannel_ping(exec_ctx, p->selected, closure);
263 } else {
ncteisen274bbbe2017-06-08 14:57:11 -0700264 GRPC_CLOSURE_SCHED(exec_ctx, closure,
David Garcia Quintas87d5a312017-06-06 19:45:58 -0700265 GRPC_ERROR_CREATE_FROM_STATIC_STRING("Not connected"));
266 }
267}
268
269/* unsubscribe all subchannels */
270static void stop_connectivity_watchers(grpc_exec_ctx *exec_ctx,
271 pick_first_lb_policy *p) {
272 if (p->num_subchannels > 0) {
273 GPR_ASSERT(p->selected == NULL);
David Garcia Quintasaf084dc2017-06-27 13:42:54 -0700274 if (GRPC_TRACER_ON(grpc_lb_pick_first_trace)) {
275 gpr_log(GPR_DEBUG, "Pick First %p unsubscribing from subchannel %p",
276 (void *)p, (void *)p->subchannels[p->checking_subchannel]);
277 }
David Garcia Quintas87d5a312017-06-06 19:45:58 -0700278 grpc_subchannel_notify_on_state_change(
279 exec_ctx, p->subchannels[p->checking_subchannel], NULL, NULL,
280 &p->connectivity_changed);
281 p->updating_subchannels = true;
282 } else if (p->selected != NULL) {
David Garcia Quintasaf084dc2017-06-27 13:42:54 -0700283 if (GRPC_TRACER_ON(grpc_lb_pick_first_trace)) {
284 gpr_log(GPR_DEBUG,
285 "Pick First %p unsubscribing from selected subchannel %p",
286 (void *)p, (void *)p->selected);
287 }
David Garcia Quintas87d5a312017-06-06 19:45:58 -0700288 grpc_connected_subchannel_notify_on_state_change(
289 exec_ctx, p->selected, NULL, NULL, &p->connectivity_changed);
290 p->updating_selected = true;
291 }
292}
293
294/* true upon success */
295static void pf_update_locked(grpc_exec_ctx *exec_ctx, grpc_lb_policy *policy,
296 const grpc_lb_policy_args *args) {
297 pick_first_lb_policy *p = (pick_first_lb_policy *)policy;
298 /* Find the number of backend addresses. We ignore balancer
299 * addresses, since we don't know how to handle them. */
300 const grpc_arg *arg =
301 grpc_channel_args_find(args->args, GRPC_ARG_LB_ADDRESSES);
302 if (arg == NULL || arg->type != GRPC_ARG_POINTER) {
303 if (p->subchannels == NULL) {
304 // If we don't have a current subchannel list, go into TRANSIENT FAILURE.
305 grpc_connectivity_state_set(
306 exec_ctx, &p->state_tracker, GRPC_CHANNEL_TRANSIENT_FAILURE,
307 GRPC_ERROR_CREATE_FROM_STATIC_STRING("Missing update in args"),
308 "pf_update_missing");
309 } else {
310 // otherwise, keep using the current subchannel list (ignore this update).
311 gpr_log(GPR_ERROR,
312 "No valid LB addresses channel arg for Pick First %p update, "
313 "ignoring.",
314 (void *)p);
315 }
316 return;
317 }
318 const grpc_lb_addresses *addresses = arg->value.pointer.p;
319 size_t num_addrs = 0;
320 for (size_t i = 0; i < addresses->num_addresses; i++) {
321 if (!addresses->addresses[i].is_balancer) ++num_addrs;
322 }
323 if (num_addrs == 0) {
324 // Empty update. Unsubscribe from all current subchannels and put the
325 // channel in TRANSIENT_FAILURE.
326 grpc_connectivity_state_set(
327 exec_ctx, &p->state_tracker, GRPC_CHANNEL_TRANSIENT_FAILURE,
328 GRPC_ERROR_CREATE_FROM_STATIC_STRING("Empty update"),
329 "pf_update_empty");
330 stop_connectivity_watchers(exec_ctx, p);
331 return;
332 }
333 if (GRPC_TRACER_ON(grpc_lb_pick_first_trace)) {
334 gpr_log(GPR_INFO, "Pick First %p received update with %lu addresses",
335 (void *)p, (unsigned long)num_addrs);
336 }
337 grpc_subchannel_args *sc_args = gpr_zalloc(sizeof(*sc_args) * num_addrs);
338 /* We remove the following keys in order for subchannel keys belonging to
339 * subchannels point to the same address to match. */
340 static const char *keys_to_remove[] = {GRPC_ARG_SUBCHANNEL_ADDRESS,
341 GRPC_ARG_LB_ADDRESSES};
342 size_t sc_args_count = 0;
343
344 /* Create list of subchannel args for new addresses in \a args. */
345 for (size_t i = 0; i < addresses->num_addresses; i++) {
346 if (addresses->addresses[i].is_balancer) continue;
347 if (addresses->addresses[i].user_data != NULL) {
348 gpr_log(GPR_ERROR,
349 "This LB policy doesn't support user data. It will be ignored");
350 }
351 grpc_arg addr_arg =
352 grpc_create_subchannel_address_arg(&addresses->addresses[i].address);
353 grpc_channel_args *new_args = grpc_channel_args_copy_and_add_and_remove(
354 args->args, keys_to_remove, GPR_ARRAY_SIZE(keys_to_remove), &addr_arg,
355 1);
356 gpr_free(addr_arg.value.string);
357 sc_args[sc_args_count++].args = new_args;
358 }
359
360 /* Check if p->selected is amongst them. If so, we are done. */
361 if (p->selected != NULL) {
362 GPR_ASSERT(p->selected_key != NULL);
363 for (size_t i = 0; i < sc_args_count; i++) {
364 grpc_subchannel_key *ith_sc_key = grpc_subchannel_key_create(&sc_args[i]);
365 const bool found_selected =
366 grpc_subchannel_key_compare(p->selected_key, ith_sc_key) == 0;
367 grpc_subchannel_key_destroy(exec_ctx, ith_sc_key);
368 if (found_selected) {
369 // The currently selected subchannel is in the update: we are done.
370 if (GRPC_TRACER_ON(grpc_lb_pick_first_trace)) {
371 gpr_log(GPR_INFO,
372 "Pick First %p found already selected subchannel %p amongst "
373 "updates. Update done.",
374 (void *)p, (void *)p->selected);
375 }
376 for (size_t j = 0; j < sc_args_count; j++) {
377 grpc_channel_args_destroy(exec_ctx,
378 (grpc_channel_args *)sc_args[j].args);
379 }
380 gpr_free(sc_args);
381 return;
382 }
383 }
384 }
385 // We only check for already running updates here because if the previous
386 // steps were successful, the update can be considered done without any
387 // interference (ie, no callbacks were scheduled).
388 if (p->updating_selected || p->updating_subchannels) {
389 if (GRPC_TRACER_ON(grpc_lb_pick_first_trace)) {
390 gpr_log(GPR_INFO,
391 "Update already in progress for pick first %p. Deferring update.",
392 (void *)p);
393 }
394 if (p->pending_update_args != NULL) {
395 grpc_channel_args_destroy(exec_ctx, p->pending_update_args->args);
396 gpr_free(p->pending_update_args);
397 }
398 p->pending_update_args = gpr_zalloc(sizeof(*p->pending_update_args));
399 p->pending_update_args->client_channel_factory =
400 args->client_channel_factory;
401 p->pending_update_args->args = grpc_channel_args_copy(args->args);
402 p->pending_update_args->combiner = args->combiner;
403 return;
404 }
405 /* Create the subchannels for the new subchannel args/addresses. */
406 grpc_subchannel **new_subchannels =
407 gpr_zalloc(sizeof(*new_subchannels) * sc_args_count);
408 size_t num_new_subchannels = 0;
409 for (size_t i = 0; i < sc_args_count; i++) {
410 grpc_subchannel *subchannel = grpc_client_channel_factory_create_subchannel(
411 exec_ctx, args->client_channel_factory, &sc_args[i]);
412 if (GRPC_TRACER_ON(grpc_lb_pick_first_trace)) {
413 char *address_uri =
414 grpc_sockaddr_to_uri(&addresses->addresses[i].address);
415 gpr_log(GPR_INFO,
416 "Pick First %p created subchannel %p for address uri %s",
417 (void *)p, (void *)subchannel, address_uri);
418 gpr_free(address_uri);
419 }
420 grpc_channel_args_destroy(exec_ctx, (grpc_channel_args *)sc_args[i].args);
421 if (subchannel != NULL) new_subchannels[num_new_subchannels++] = subchannel;
422 }
423 gpr_free(sc_args);
424 if (num_new_subchannels == 0) {
425 gpr_free(new_subchannels);
426 // Empty update. Unsubscribe from all current subchannels and put the
427 // channel in TRANSIENT_FAILURE.
428 grpc_connectivity_state_set(
429 exec_ctx, &p->state_tracker, GRPC_CHANNEL_TRANSIENT_FAILURE,
430 GRPC_ERROR_CREATE_FROM_STATIC_STRING("No valid addresses in update"),
431 "pf_update_no_valid_addresses");
432 stop_connectivity_watchers(exec_ctx, p);
433 return;
434 }
435
436 /* Destroy the current subchannels. Repurpose pf_shutdown/destroy. */
437 stop_connectivity_watchers(exec_ctx, p);
438
439 /* Save new subchannels. The switch over will happen in
440 * pf_connectivity_changed_locked */
441 if (p->updating_selected || p->updating_subchannels) {
442 p->num_new_subchannels = num_new_subchannels;
443 p->new_subchannels = new_subchannels;
444 } else { /* nothing is updating. Get things moving from here */
445 p->num_subchannels = num_new_subchannels;
446 p->subchannels = new_subchannels;
447 p->new_subchannels = NULL;
448 p->num_new_subchannels = 0;
449 if (p->started_picking) {
450 p->checking_subchannel = 0;
451 p->checking_connectivity = GRPC_CHANNEL_IDLE;
452 grpc_subchannel_notify_on_state_change(
453 exec_ctx, p->subchannels[p->checking_subchannel],
454 p->base.interested_parties, &p->checking_connectivity,
455 &p->connectivity_changed);
456 }
457 }
458}
459
Craig Tiller2400bf52017-02-09 16:25:19 -0800460static void pf_connectivity_changed_locked(grpc_exec_ctx *exec_ctx, void *arg,
461 grpc_error *error) {
Craig Tillereb3b12e2015-06-26 14:42:49 -0700462 pick_first_lb_policy *p = arg;
Craig Tillerb5585d42015-11-17 07:18:31 -0800463 grpc_subchannel *selected_subchannel;
Craig Tillereb3b12e2015-06-26 14:42:49 -0700464 pending_pick *pp;
Craig Tillereb3b12e2015-06-26 14:42:49 -0700465
David Garcia Quintasaf084dc2017-06-27 13:42:54 -0700466 if (GRPC_TRACER_ON(grpc_lb_pick_first_trace)) {
467 gpr_log(
468 GPR_DEBUG,
469 "Pick First %p connectivity changed. Updating selected: %d; Updating "
470 "subchannels: %d; Checking %lu index (%lu total); State: %d; ",
471 (void *)p, p->updating_selected, p->updating_subchannels,
472 (unsigned long)p->checking_subchannel,
473 (unsigned long)p->num_subchannels, p->checking_connectivity);
474 }
David Garcia Quintas87d5a312017-06-06 19:45:58 -0700475 bool restart = false;
David Garcia Quintasaf084dc2017-06-27 13:42:54 -0700476 if (p->updating_selected && error != GRPC_ERROR_NONE) {
David Garcia Quintas87d5a312017-06-06 19:45:58 -0700477 /* Captured the unsubscription for p->selected */
478 GPR_ASSERT(p->selected != NULL);
479 GRPC_CONNECTED_SUBCHANNEL_UNREF(exec_ctx, p->selected,
480 "pf_update_connectivity");
David Garcia Quintasaf084dc2017-06-27 13:42:54 -0700481 if (GRPC_TRACER_ON(grpc_lb_pick_first_trace)) {
482 gpr_log(GPR_DEBUG, "Pick First %p unreffing selected subchannel %p",
483 (void *)p, (void *)p->selected);
484 }
David Garcia Quintas87d5a312017-06-06 19:45:58 -0700485 p->updating_selected = false;
486 if (p->num_new_subchannels == 0) {
487 p->selected = NULL;
488 return;
489 }
490 restart = true;
491 }
David Garcia Quintasaf084dc2017-06-27 13:42:54 -0700492 if (p->updating_subchannels && error != GRPC_ERROR_NONE) {
David Garcia Quintas87d5a312017-06-06 19:45:58 -0700493 /* Captured the unsubscription for the checking subchannel */
494 GPR_ASSERT(p->selected == NULL);
495 for (size_t i = 0; i < p->num_subchannels; i++) {
496 GRPC_SUBCHANNEL_UNREF(exec_ctx, p->subchannels[i],
497 "pf_update_connectivity");
David Garcia Quintasaf084dc2017-06-27 13:42:54 -0700498 if (GRPC_TRACER_ON(grpc_lb_pick_first_trace)) {
499 gpr_log(GPR_DEBUG, "Pick First %p unreffing subchannel %p", (void *)p,
500 (void *)p->subchannels[i]);
501 }
David Garcia Quintas87d5a312017-06-06 19:45:58 -0700502 }
503 gpr_free(p->subchannels);
504 p->subchannels = NULL;
505 p->num_subchannels = 0;
506 p->updating_subchannels = false;
507 if (p->num_new_subchannels == 0) return;
508 restart = true;
509 }
510 if (restart) {
511 p->selected = NULL;
512 p->selected_key = NULL;
David Garcia Quintas87d5a312017-06-06 19:45:58 -0700513 GPR_ASSERT(p->new_subchannels != NULL);
514 GPR_ASSERT(p->num_new_subchannels > 0);
515 p->num_subchannels = p->num_new_subchannels;
516 p->subchannels = p->new_subchannels;
517 p->num_new_subchannels = 0;
518 p->new_subchannels = NULL;
David Garcia Quintas87d5a312017-06-06 19:45:58 -0700519 if (p->started_picking) {
520 /* If we were picking, continue to do so over the new subchannels,
521 * starting from the 0th index. */
522 p->checking_subchannel = 0;
523 p->checking_connectivity = GRPC_CHANNEL_IDLE;
524 /* reuses the weak ref from start_picking_locked */
525 grpc_subchannel_notify_on_state_change(
526 exec_ctx, p->subchannels[p->checking_subchannel],
527 p->base.interested_parties, &p->checking_connectivity,
528 &p->connectivity_changed);
529 }
530 if (p->pending_update_args != NULL) {
531 const grpc_lb_policy_args *args = p->pending_update_args;
532 p->pending_update_args = NULL;
533 pf_update_locked(exec_ctx, &p->base, args);
534 }
535 return;
536 }
537 GRPC_ERROR_REF(error);
Craig Tillera82950e2015-09-22 12:33:20 -0700538 if (p->shutdown) {
Craig Tiller48613042015-11-29 14:45:11 -0800539 GRPC_LB_POLICY_WEAK_UNREF(exec_ctx, &p->base, "pick_first_connectivity");
Craig Tillerae125932016-05-13 16:34:29 -0700540 GRPC_ERROR_UNREF(error);
Craig Tillera82950e2015-09-22 12:33:20 -0700541 return;
Craig Tiller2400bf52017-02-09 16:25:19 -0800542 } else if (p->selected != NULL) {
Craig Tillercb2609f2015-11-24 17:19:19 -0800543 if (p->checking_connectivity == GRPC_CHANNEL_TRANSIENT_FAILURE) {
544 /* if the selected channel goes bad, we're done */
Craig Tiller48ed92e2016-06-02 11:07:12 -0700545 p->checking_connectivity = GRPC_CHANNEL_SHUTDOWN;
Craig Tillercb2609f2015-11-24 17:19:19 -0800546 }
Craig Tillera82950e2015-09-22 12:33:20 -0700547 grpc_connectivity_state_set(exec_ctx, &p->state_tracker,
Craig Tillerf707d622016-05-06 14:26:12 -0700548 p->checking_connectivity, GRPC_ERROR_REF(error),
Craig Tiller804ff712016-05-05 16:25:40 -0700549 "selected_changed");
Craig Tiller48ed92e2016-06-02 11:07:12 -0700550 if (p->checking_connectivity != GRPC_CHANNEL_SHUTDOWN) {
Craig Tillerab33b482015-11-21 08:11:04 -0800551 grpc_connected_subchannel_notify_on_state_change(
Craig Tiller2400bf52017-02-09 16:25:19 -0800552 exec_ctx, p->selected, p->base.interested_parties,
Craig Tillera6bebf42015-12-01 17:02:35 -0800553 &p->checking_connectivity, &p->connectivity_changed);
Craig Tillera82950e2015-09-22 12:33:20 -0700554 } else {
Craig Tiller48613042015-11-29 14:45:11 -0800555 GRPC_LB_POLICY_WEAK_UNREF(exec_ctx, &p->base, "pick_first_connectivity");
Craig Tiller1ada6ad2015-07-16 16:19:14 -0700556 }
Craig Tillera82950e2015-09-22 12:33:20 -0700557 } else {
558 loop:
559 switch (p->checking_connectivity) {
David Garcia Quintasea6689d2016-11-08 09:46:41 -0800560 case GRPC_CHANNEL_INIT:
Jan Tattermuschb0fb2d22016-11-16 14:04:05 +0100561 GPR_UNREACHABLE_CODE(return );
Craig Tillera82950e2015-09-22 12:33:20 -0700562 case GRPC_CHANNEL_READY:
563 grpc_connectivity_state_set(exec_ctx, &p->state_tracker,
Craig Tiller804ff712016-05-05 16:25:40 -0700564 GRPC_CHANNEL_READY, GRPC_ERROR_NONE,
565 "connecting_ready");
Craig Tillerb5585d42015-11-17 07:18:31 -0800566 selected_subchannel = p->subchannels[p->checking_subchannel];
Craig Tiller2400bf52017-02-09 16:25:19 -0800567 p->selected = GRPC_CONNECTED_SUBCHANNEL_REF(
568 grpc_subchannel_get_connected_subchannel(selected_subchannel),
569 "picked_first");
David Garcia Quintas87d5a312017-06-06 19:45:58 -0700570
571 if (GRPC_TRACER_ON(grpc_lb_pick_first_trace)) {
David Garcia Quintasaf084dc2017-06-27 13:42:54 -0700572 gpr_log(GPR_INFO,
573 "Pick First %p selected subchannel %p (connected %p)",
574 (void *)p, (void *)selected_subchannel, (void *)p->selected);
David Garcia Quintas87d5a312017-06-06 19:45:58 -0700575 }
576 p->selected_key = grpc_subchannel_get_key(selected_subchannel);
Craig Tillerb09d84d2015-10-06 09:12:16 -0700577 /* drop the pick list: we are connected now */
Craig Tiller48613042015-11-29 14:45:11 -0800578 GRPC_LB_POLICY_WEAK_REF(&p->base, "destroy_subchannels");
Craig Tiller2400bf52017-02-09 16:25:19 -0800579 destroy_subchannels_locked(exec_ctx, p);
Craig Tillerb09d84d2015-10-06 09:12:16 -0700580 /* update any calls that were waiting for a pick */
Craig Tillera82950e2015-09-22 12:33:20 -0700581 while ((pp = p->pending_picks)) {
582 p->pending_picks = pp->next;
Craig Tiller2400bf52017-02-09 16:25:19 -0800583 *pp->target = GRPC_CONNECTED_SUBCHANNEL_REF(p->selected, "picked");
David Garcia Quintas87d5a312017-06-06 19:45:58 -0700584 if (GRPC_TRACER_ON(grpc_lb_pick_first_trace)) {
585 gpr_log(GPR_INFO,
586 "Servicing pending pick with selected subchannel %p",
587 (void *)p->selected);
588 }
ncteisen274bbbe2017-06-08 14:57:11 -0700589 GRPC_CLOSURE_SCHED(exec_ctx, pp->on_complete, GRPC_ERROR_NONE);
Craig Tillera82950e2015-09-22 12:33:20 -0700590 gpr_free(pp);
591 }
Craig Tillerab33b482015-11-21 08:11:04 -0800592 grpc_connected_subchannel_notify_on_state_change(
Craig Tiller2400bf52017-02-09 16:25:19 -0800593 exec_ctx, p->selected, p->base.interested_parties,
Craig Tillera6bebf42015-12-01 17:02:35 -0800594 &p->checking_connectivity, &p->connectivity_changed);
Craig Tillera82950e2015-09-22 12:33:20 -0700595 break;
596 case GRPC_CHANNEL_TRANSIENT_FAILURE:
Craig Tillera82950e2015-09-22 12:33:20 -0700597 p->checking_subchannel =
598 (p->checking_subchannel + 1) % p->num_subchannels;
Craig Tiller131b6de2016-03-31 17:05:28 -0700599 if (p->checking_subchannel == 0) {
David Garcia Quintasaf084dc2017-06-27 13:42:54 -0700600 /* only trigger transient failure when we've tried all alternatives
601 */
Craig Tiller804ff712016-05-05 16:25:40 -0700602 grpc_connectivity_state_set(
603 exec_ctx, &p->state_tracker, GRPC_CHANNEL_TRANSIENT_FAILURE,
Craig Tillerf707d622016-05-06 14:26:12 -0700604 GRPC_ERROR_REF(error), "connecting_transient_failure");
Craig Tiller131b6de2016-03-31 17:05:28 -0700605 }
Craig Tillerf707d622016-05-06 14:26:12 -0700606 GRPC_ERROR_UNREF(error);
Craig Tillera82950e2015-09-22 12:33:20 -0700607 p->checking_connectivity = grpc_subchannel_check_connectivity(
Craig Tiller804ff712016-05-05 16:25:40 -0700608 p->subchannels[p->checking_subchannel], &error);
Craig Tillera82950e2015-09-22 12:33:20 -0700609 if (p->checking_connectivity == GRPC_CHANNEL_TRANSIENT_FAILURE) {
610 grpc_subchannel_notify_on_state_change(
611 exec_ctx, p->subchannels[p->checking_subchannel],
Craig Tiller69b093b2016-02-25 19:04:07 -0800612 p->base.interested_parties, &p->checking_connectivity,
Craig Tiller1d881fb2015-12-01 07:39:04 -0800613 &p->connectivity_changed);
Craig Tillera82950e2015-09-22 12:33:20 -0700614 } else {
615 goto loop;
616 }
617 break;
618 case GRPC_CHANNEL_CONNECTING:
619 case GRPC_CHANNEL_IDLE:
Craig Tiller804ff712016-05-05 16:25:40 -0700620 grpc_connectivity_state_set(
621 exec_ctx, &p->state_tracker, GRPC_CHANNEL_CONNECTING,
Craig Tillerf707d622016-05-06 14:26:12 -0700622 GRPC_ERROR_REF(error), "connecting_changed");
Craig Tillera82950e2015-09-22 12:33:20 -0700623 grpc_subchannel_notify_on_state_change(
624 exec_ctx, p->subchannels[p->checking_subchannel],
Craig Tiller69b093b2016-02-25 19:04:07 -0800625 p->base.interested_parties, &p->checking_connectivity,
Craig Tiller1d881fb2015-12-01 07:39:04 -0800626 &p->connectivity_changed);
Craig Tillera82950e2015-09-22 12:33:20 -0700627 break;
Craig Tiller48ed92e2016-06-02 11:07:12 -0700628 case GRPC_CHANNEL_SHUTDOWN:
Craig Tillera82950e2015-09-22 12:33:20 -0700629 p->num_subchannels--;
Craig Tiller86c99582015-11-25 15:22:26 -0800630 GPR_SWAP(grpc_subchannel *, p->subchannels[p->checking_subchannel],
631 p->subchannels[p->num_subchannels]);
Craig Tillera82950e2015-09-22 12:33:20 -0700632 GRPC_SUBCHANNEL_UNREF(exec_ctx, p->subchannels[p->num_subchannels],
633 "pick_first");
634 if (p->num_subchannels == 0) {
Craig Tiller804ff712016-05-05 16:25:40 -0700635 grpc_connectivity_state_set(
Craig Tillerd925c932016-06-06 08:38:50 -0700636 exec_ctx, &p->state_tracker, GRPC_CHANNEL_SHUTDOWN,
ncteisen4b36a3d2017-03-13 19:08:06 -0700637 GRPC_ERROR_CREATE_REFERENCING_FROM_STATIC_STRING(
638 "Pick first exhausted channels", &error, 1),
Craig Tiller804ff712016-05-05 16:25:40 -0700639 "no_more_channels");
Craig Tillera82950e2015-09-22 12:33:20 -0700640 while ((pp = p->pending_picks)) {
641 p->pending_picks = pp->next;
642 *pp->target = NULL;
ncteisen274bbbe2017-06-08 14:57:11 -0700643 GRPC_CLOSURE_SCHED(exec_ctx, pp->on_complete, GRPC_ERROR_NONE);
Craig Tillera82950e2015-09-22 12:33:20 -0700644 gpr_free(pp);
645 }
Craig Tiller1d881fb2015-12-01 07:39:04 -0800646 GRPC_LB_POLICY_WEAK_UNREF(exec_ctx, &p->base,
647 "pick_first_connectivity");
Craig Tillera82950e2015-09-22 12:33:20 -0700648 } else {
Craig Tiller804ff712016-05-05 16:25:40 -0700649 grpc_connectivity_state_set(
650 exec_ctx, &p->state_tracker, GRPC_CHANNEL_TRANSIENT_FAILURE,
Craig Tillerf707d622016-05-06 14:26:12 -0700651 GRPC_ERROR_REF(error), "subchannel_failed");
Craig Tillera82950e2015-09-22 12:33:20 -0700652 p->checking_subchannel %= p->num_subchannels;
Craig Tillerf707d622016-05-06 14:26:12 -0700653 GRPC_ERROR_UNREF(error);
Craig Tillera82950e2015-09-22 12:33:20 -0700654 p->checking_connectivity = grpc_subchannel_check_connectivity(
Craig Tiller804ff712016-05-05 16:25:40 -0700655 p->subchannels[p->checking_subchannel], &error);
Craig Tillera82950e2015-09-22 12:33:20 -0700656 goto loop;
657 }
Craig Tiller1ada6ad2015-07-16 16:19:14 -0700658 }
Craig Tillera82950e2015-09-22 12:33:20 -0700659 }
Craig Tiller1ada6ad2015-07-16 16:19:14 -0700660
Craig Tillerf707d622016-05-06 14:26:12 -0700661 GRPC_ERROR_UNREF(error);
Craig Tillereb3b12e2015-06-26 14:42:49 -0700662}
663
664static const grpc_lb_policy_vtable pick_first_lb_policy_vtable = {
Craig Tiller2400bf52017-02-09 16:25:19 -0800665 pf_destroy,
666 pf_shutdown_locked,
667 pf_pick_locked,
668 pf_cancel_pick_locked,
669 pf_cancel_picks_locked,
670 pf_ping_one_locked,
671 pf_exit_idle_locked,
672 pf_check_connectivity_locked,
David Garcia Quintas87d5a312017-06-06 19:45:58 -0700673 pf_notify_on_state_change_locked,
674 pf_update_locked};
Craig Tillereb3b12e2015-06-26 14:42:49 -0700675
Craig Tillera82950e2015-09-22 12:33:20 -0700676static void pick_first_factory_ref(grpc_lb_policy_factory *factory) {}
David Garcia Quintas5c4543d2015-09-03 15:49:56 -0700677
Craig Tillera82950e2015-09-22 12:33:20 -0700678static void pick_first_factory_unref(grpc_lb_policy_factory *factory) {}
David Garcia Quintas5c4543d2015-09-03 15:49:56 -0700679
David Garcia Quintas67c0d042016-03-25 01:37:53 -0700680static grpc_lb_policy *create_pick_first(grpc_exec_ctx *exec_ctx,
681 grpc_lb_policy_factory *factory,
Craig Tillera82950e2015-09-22 12:33:20 -0700682 grpc_lb_policy_args *args) {
David Garcia Quintas86fcfcc2016-03-31 23:22:28 -0700683 GPR_ASSERT(args->client_channel_factory != NULL);
Craig Tiller6f417882017-02-16 14:09:39 -0800684 pick_first_lb_policy *p = gpr_zalloc(sizeof(*p));
David Garcia Quintasaf084dc2017-06-27 13:42:54 -0700685 if (GRPC_TRACER_ON(grpc_lb_pick_first_trace)) {
686 gpr_log(GPR_DEBUG, "Pick First %p created.", (void *)p);
687 }
David Garcia Quintas87d5a312017-06-06 19:45:58 -0700688 pf_update_locked(exec_ctx, &p->base, args);
Craig Tiller2400bf52017-02-09 16:25:19 -0800689 grpc_lb_policy_init(&p->base, &pick_first_lb_policy_vtable, args->combiner);
ncteisen274bbbe2017-06-08 14:57:11 -0700690 GRPC_CLOSURE_INIT(&p->connectivity_changed, pf_connectivity_changed_locked, p,
Craig Tilleree4b1452017-05-12 10:56:03 -0700691 grpc_combiner_scheduler(args->combiner));
Craig Tillereb3b12e2015-06-26 14:42:49 -0700692 return &p->base;
693}
David Garcia Quintas5c4543d2015-09-03 15:49:56 -0700694
695static const grpc_lb_policy_factory_vtable pick_first_factory_vtable = {
Craig Tillera82950e2015-09-22 12:33:20 -0700696 pick_first_factory_ref, pick_first_factory_unref, create_pick_first,
697 "pick_first"};
David Garcia Quintas5c4543d2015-09-03 15:49:56 -0700698
699static grpc_lb_policy_factory pick_first_lb_policy_factory = {
Craig Tillera82950e2015-09-22 12:33:20 -0700700 &pick_first_factory_vtable};
David Garcia Quintas5c4543d2015-09-03 15:49:56 -0700701
Craig Tillerfb433852016-03-29 08:51:07 -0700702static grpc_lb_policy_factory *pick_first_lb_factory_create() {
David Garcia Quintas5c4543d2015-09-03 15:49:56 -0700703 return &pick_first_lb_policy_factory;
704}
Craig Tillerfb433852016-03-29 08:51:07 -0700705
706/* Plugin registration */
707
708void grpc_lb_policy_pick_first_init() {
Craig Tiller3113ef42016-03-29 09:03:14 -0700709 grpc_register_lb_policy(pick_first_lb_factory_create());
David Garcia Quintas87d5a312017-06-06 19:45:58 -0700710 grpc_register_tracer("pick_first", &grpc_lb_pick_first_trace);
Craig Tillerfb433852016-03-29 08:51:07 -0700711}
712
713void grpc_lb_policy_pick_first_shutdown() {}