blob: fd0fb41fb9ab905cfc1e4f30c3e79779ca0b0ccc [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
ncteisen7712c7c2017-07-12 23:11:27 -070031grpc_tracer_flag grpc_lb_pick_first_trace =
32 GRPC_TRACER_INITIALIZER(false, "pick_first");
David Garcia Quintas87d5a312017-06-06 19:45:58 -070033
Craig Tillera82950e2015-09-22 12:33:20 -070034typedef struct pending_pick {
Craig Tillereb3b12e2015-06-26 14:42:49 -070035 struct pending_pick *next;
Craig Tiller8c0d96f2016-03-11 14:27:52 -080036 uint32_t initial_metadata_flags;
Craig Tillerb5585d42015-11-17 07:18:31 -080037 grpc_connected_subchannel **target;
Craig Tiller33825112015-09-18 07:44:19 -070038 grpc_closure *on_complete;
Craig Tillereb3b12e2015-06-26 14:42:49 -070039} pending_pick;
40
Craig Tillera82950e2015-09-22 12:33:20 -070041typedef struct {
Craig Tillereb3b12e2015-06-26 14:42:49 -070042 /** base policy: must be first */
43 grpc_lb_policy base;
Craig Tillereb3b12e2015-06-26 14:42:49 -070044 /** all our subchannels */
45 grpc_subchannel **subchannels;
David Garcia Quintas87d5a312017-06-06 19:45:58 -070046 grpc_subchannel **new_subchannels;
Craig Tillereb3b12e2015-06-26 14:42:49 -070047 size_t num_subchannels;
David Garcia Quintas87d5a312017-06-06 19:45:58 -070048 size_t num_new_subchannels;
Craig Tillereb3b12e2015-06-26 14:42:49 -070049
Craig Tiller33825112015-09-18 07:44:19 -070050 grpc_closure connectivity_changed;
Craig Tillereb3b12e2015-06-26 14:42:49 -070051
Craig Tiller2400bf52017-02-09 16:25:19 -080052 /** remaining members are protected by the combiner */
Craig Tiller320bee02016-01-06 17:33:45 -080053
Craig Tiller46dd7902017-02-23 09:42:16 -080054 /** the selected channel */
Craig Tiller2400bf52017-02-09 16:25:19 -080055 grpc_connected_subchannel *selected;
56
David Garcia Quintas87d5a312017-06-06 19:45:58 -070057 /** the subchannel key for \a selected, or NULL if \a selected not set */
58 const grpc_subchannel_key *selected_key;
59
Craig Tillereb3b12e2015-06-26 14:42:49 -070060 /** have we started picking? */
David Garcia Quintas87d5a312017-06-06 19:45:58 -070061 bool started_picking;
Craig Tillera14215a2015-07-17 17:21:08 -070062 /** are we shut down? */
David Garcia Quintas87d5a312017-06-06 19:45:58 -070063 bool shutdown;
64 /** are we updating the selected subchannel? */
65 bool updating_selected;
66 /** are we updating the subchannel candidates? */
67 bool updating_subchannels;
68 /** args from the latest update received while already updating, or NULL */
69 grpc_lb_policy_args *pending_update_args;
Craig Tillereb3b12e2015-06-26 14:42:49 -070070 /** which subchannel are we watching? */
71 size_t checking_subchannel;
72 /** what is the connectivity of that channel? */
73 grpc_connectivity_state checking_connectivity;
74 /** list of picks that are waiting on connectivity */
75 pending_pick *pending_picks;
Craig Tillerc7b5f762015-06-27 11:48:42 -070076
77 /** our connectivity state tracker */
78 grpc_connectivity_state_tracker state_tracker;
Craig Tillereb3b12e2015-06-26 14:42:49 -070079} pick_first_lb_policy;
80
Craig Tillerfb433852016-03-29 08:51:07 -070081static void pf_destroy(grpc_exec_ctx *exec_ctx, grpc_lb_policy *pol) {
Craig Tillera82950e2015-09-22 12:33:20 -070082 pick_first_lb_policy *p = (pick_first_lb_policy *)pol;
Craig Tillera82950e2015-09-22 12:33:20 -070083 GPR_ASSERT(p->pending_picks == NULL);
David Garcia Quintas87d5a312017-06-06 19:45:58 -070084 for (size_t i = 0; i < p->num_subchannels; i++) {
85 GRPC_SUBCHANNEL_UNREF(exec_ctx, p->subchannels[i], "pick_first_destroy");
Craig Tillera82950e2015-09-22 12:33:20 -070086 }
Craig Tiller2400bf52017-02-09 16:25:19 -080087 if (p->selected != NULL) {
David Garcia Quintas87d5a312017-06-06 19:45:58 -070088 GRPC_CONNECTED_SUBCHANNEL_UNREF(exec_ctx, p->selected,
89 "picked_first_destroy");
Craig Tiller89a768e2015-10-06 09:55:59 -070090 }
Craig Tillera82950e2015-09-22 12:33:20 -070091 grpc_connectivity_state_destroy(exec_ctx, &p->state_tracker);
David Garcia Quintas87d5a312017-06-06 19:45:58 -070092 if (p->pending_update_args != NULL) {
93 grpc_channel_args_destroy(exec_ctx, p->pending_update_args->args);
94 gpr_free(p->pending_update_args);
95 }
Craig Tillera82950e2015-09-22 12:33:20 -070096 gpr_free(p->subchannels);
David Garcia Quintas87d5a312017-06-06 19:45:58 -070097 gpr_free(p->new_subchannels);
Craig Tillera82950e2015-09-22 12:33:20 -070098 gpr_free(p);
David Garcia Quintasaf084dc2017-06-27 13:42:54 -070099 if (GRPC_TRACER_ON(grpc_lb_pick_first_trace)) {
100 gpr_log(GPR_DEBUG, "Pick First %p destroyed.", (void *)p);
101 }
Craig Tillereb3b12e2015-06-26 14:42:49 -0700102}
103
Craig Tiller2400bf52017-02-09 16:25:19 -0800104static void pf_shutdown_locked(grpc_exec_ctx *exec_ctx, grpc_lb_policy *pol) {
Craig Tillera82950e2015-09-22 12:33:20 -0700105 pick_first_lb_policy *p = (pick_first_lb_policy *)pol;
Craig Tillerd2cc4592015-07-01 07:50:47 -0700106 pending_pick *pp;
David Garcia Quintas87d5a312017-06-06 19:45:58 -0700107 p->shutdown = true;
Craig Tiller5795da72015-09-17 15:27:13 -0700108 pp = p->pending_picks;
109 p->pending_picks = NULL;
Craig Tiller804ff712016-05-05 16:25:40 -0700110 grpc_connectivity_state_set(
Craig Tillerd925c932016-06-06 08:38:50 -0700111 exec_ctx, &p->state_tracker, GRPC_CHANNEL_SHUTDOWN,
ncteisen4b36a3d2017-03-13 19:08:06 -0700112 GRPC_ERROR_CREATE_FROM_STATIC_STRING("Channel shutdown"), "shutdown");
Craig Tillerf036a642015-12-01 17:00:40 -0800113 /* cancel subscription */
Craig Tiller2400bf52017-02-09 16:25:19 -0800114 if (p->selected != NULL) {
Craig Tiller1d881fb2015-12-01 07:39:04 -0800115 grpc_connected_subchannel_notify_on_state_change(
Craig Tiller2400bf52017-02-09 16:25:19 -0800116 exec_ctx, p->selected, NULL, NULL, &p->connectivity_changed);
David Garcia Quintas87d5a312017-06-06 19:45:58 -0700117 } else if (p->num_subchannels > 0 && p->started_picking) {
Craig Tiller1d881fb2015-12-01 07:39:04 -0800118 grpc_subchannel_notify_on_state_change(
119 exec_ctx, p->subchannels[p->checking_subchannel], NULL, NULL,
120 &p->connectivity_changed);
Craig Tiller48613042015-11-29 14:45:11 -0800121 }
Craig Tillera82950e2015-09-22 12:33:20 -0700122 while (pp != NULL) {
123 pending_pick *next = pp->next;
124 *pp->target = NULL;
ncteisen274bbbe2017-06-08 14:57:11 -0700125 GRPC_CLOSURE_SCHED(exec_ctx, pp->on_complete, GRPC_ERROR_NONE);
Craig Tillera82950e2015-09-22 12:33:20 -0700126 gpr_free(pp);
127 pp = next;
128 }
Craig Tillereb3b12e2015-06-26 14:42:49 -0700129}
130
Craig Tiller2400bf52017-02-09 16:25:19 -0800131static void pf_cancel_pick_locked(grpc_exec_ctx *exec_ctx, grpc_lb_policy *pol,
132 grpc_connected_subchannel **target,
133 grpc_error *error) {
Craig Tiller577c9b22015-11-02 14:11:15 -0800134 pick_first_lb_policy *p = (pick_first_lb_policy *)pol;
135 pending_pick *pp;
Craig Tiller577c9b22015-11-02 14:11:15 -0800136 pp = p->pending_picks;
137 p->pending_picks = NULL;
138 while (pp != NULL) {
139 pending_pick *next = pp->next;
140 if (pp->target == target) {
Craig Tiller577c9b22015-11-02 14:11:15 -0800141 *target = NULL;
ncteisen274bbbe2017-06-08 14:57:11 -0700142 GRPC_CLOSURE_SCHED(exec_ctx, pp->on_complete,
ncteisen4b36a3d2017-03-13 19:08:06 -0700143 GRPC_ERROR_CREATE_REFERENCING_FROM_STATIC_STRING(
144 "Pick Cancelled", &error, 1));
Craig Tiller577c9b22015-11-02 14:11:15 -0800145 gpr_free(pp);
146 } else {
147 pp->next = p->pending_picks;
148 p->pending_picks = pp;
149 }
150 pp = next;
151 }
Mark D. Roth5f844002016-09-08 08:20:53 -0700152 GRPC_ERROR_UNREF(error);
Craig Tiller577c9b22015-11-02 14:11:15 -0800153}
154
Craig Tiller2400bf52017-02-09 16:25:19 -0800155static void pf_cancel_picks_locked(grpc_exec_ctx *exec_ctx, grpc_lb_policy *pol,
156 uint32_t initial_metadata_flags_mask,
157 uint32_t initial_metadata_flags_eq,
158 grpc_error *error) {
Craig Tiller8c0d96f2016-03-11 14:27:52 -0800159 pick_first_lb_policy *p = (pick_first_lb_policy *)pol;
160 pending_pick *pp;
Craig Tiller8c0d96f2016-03-11 14:27:52 -0800161 pp = p->pending_picks;
162 p->pending_picks = NULL;
163 while (pp != NULL) {
164 pending_pick *next = pp->next;
165 if ((pp->initial_metadata_flags & initial_metadata_flags_mask) ==
166 initial_metadata_flags_eq) {
ncteisen274bbbe2017-06-08 14:57:11 -0700167 GRPC_CLOSURE_SCHED(exec_ctx, pp->on_complete,
ncteisen4b36a3d2017-03-13 19:08:06 -0700168 GRPC_ERROR_CREATE_REFERENCING_FROM_STATIC_STRING(
169 "Pick Cancelled", &error, 1));
Craig Tiller8c0d96f2016-03-11 14:27:52 -0800170 gpr_free(pp);
171 } else {
172 pp->next = p->pending_picks;
173 p->pending_picks = pp;
174 }
175 pp = next;
176 }
Mark D. Rothe65ff112016-09-09 13:48:38 -0700177 GRPC_ERROR_UNREF(error);
Craig Tiller8c0d96f2016-03-11 14:27:52 -0800178}
179
David Garcia Quintas87d5a312017-06-06 19:45:58 -0700180static void start_picking_locked(grpc_exec_ctx *exec_ctx,
181 pick_first_lb_policy *p) {
182 p->started_picking = true;
183 if (p->subchannels != NULL) {
184 GPR_ASSERT(p->num_subchannels > 0);
185 p->checking_subchannel = 0;
186 p->checking_connectivity = GRPC_CHANNEL_IDLE;
187 GRPC_LB_POLICY_WEAK_REF(&p->base, "pick_first_connectivity");
188 grpc_subchannel_notify_on_state_change(
189 exec_ctx, p->subchannels[p->checking_subchannel],
190 p->base.interested_parties, &p->checking_connectivity,
191 &p->connectivity_changed);
192 }
Craig Tiller48cb07c2015-07-15 16:16:15 -0700193}
194
Craig Tiller2400bf52017-02-09 16:25:19 -0800195static void pf_exit_idle_locked(grpc_exec_ctx *exec_ctx, grpc_lb_policy *pol) {
Craig Tillera82950e2015-09-22 12:33:20 -0700196 pick_first_lb_policy *p = (pick_first_lb_policy *)pol;
Craig Tillera82950e2015-09-22 12:33:20 -0700197 if (!p->started_picking) {
David Garcia Quintas87d5a312017-06-06 19:45:58 -0700198 start_picking_locked(exec_ctx, p);
Craig Tillera82950e2015-09-22 12:33:20 -0700199 }
Craig Tillereb3b12e2015-06-26 14:42:49 -0700200}
201
Craig Tiller2400bf52017-02-09 16:25:19 -0800202static int pf_pick_locked(grpc_exec_ctx *exec_ctx, grpc_lb_policy *pol,
203 const grpc_lb_policy_pick_args *pick_args,
Mark D. Roth09e458c2017-05-02 08:13:26 -0700204 grpc_connected_subchannel **target,
205 grpc_call_context_element *context, void **user_data,
Craig Tiller2400bf52017-02-09 16:25:19 -0800206 grpc_closure *on_complete) {
Craig Tillera82950e2015-09-22 12:33:20 -0700207 pick_first_lb_policy *p = (pick_first_lb_policy *)pol;
Craig Tiller45724b32015-09-22 10:42:19 -0700208 pending_pick *pp;
Craig Tiller320bee02016-01-06 17:33:45 -0800209
210 /* Check atomically for a selected channel */
Craig Tiller2400bf52017-02-09 16:25:19 -0800211 if (p->selected != NULL) {
212 *target = GRPC_CONNECTED_SUBCHANNEL_REF(p->selected, "picked");
Craig Tiller86c0f8a2015-12-01 20:05:40 -0800213 return 1;
214 }
Craig Tiller320bee02016-01-06 17:33:45 -0800215
Craig Tiller46dd7902017-02-23 09:42:16 -0800216 /* No subchannel selected yet, so try again */
Craig Tiller2400bf52017-02-09 16:25:19 -0800217 if (!p->started_picking) {
David Garcia Quintas87d5a312017-06-06 19:45:58 -0700218 start_picking_locked(exec_ctx, p);
Craig Tillera82950e2015-09-22 12:33:20 -0700219 }
Craig Tiller2400bf52017-02-09 16:25:19 -0800220 pp = gpr_malloc(sizeof(*pp));
221 pp->next = p->pending_picks;
222 pp->target = target;
223 pp->initial_metadata_flags = pick_args->initial_metadata_flags;
224 pp->on_complete = on_complete;
225 p->pending_picks = pp;
226 return 0;
Craig Tiller45724b32015-09-22 10:42:19 -0700227}
228
Craig Tiller2400bf52017-02-09 16:25:19 -0800229static void destroy_subchannels_locked(grpc_exec_ctx *exec_ctx,
230 pick_first_lb_policy *p) {
Craig Tillerb09d84d2015-10-06 09:12:16 -0700231 size_t num_subchannels = p->num_subchannels;
David Garcia Quintas87d5a312017-06-06 19:45:58 -0700232 grpc_subchannel **subchannels = p->subchannels;
Craig Tillerb09d84d2015-10-06 09:12:16 -0700233
Craig Tillerb09d84d2015-10-06 09:12:16 -0700234 p->num_subchannels = 0;
235 p->subchannels = NULL;
Craig Tiller48613042015-11-29 14:45:11 -0800236 GRPC_LB_POLICY_WEAK_UNREF(exec_ctx, &p->base, "destroy_subchannels");
Craig Tillerb09d84d2015-10-06 09:12:16 -0700237
David Garcia Quintas87d5a312017-06-06 19:45:58 -0700238 for (size_t i = 0; i < num_subchannels; i++) {
Craig Tillerb09d84d2015-10-06 09:12:16 -0700239 GRPC_SUBCHANNEL_UNREF(exec_ctx, subchannels[i], "pick_first");
240 }
Craig Tillerb09d84d2015-10-06 09:12:16 -0700241 gpr_free(subchannels);
242}
243
David Garcia Quintas87d5a312017-06-06 19:45:58 -0700244static grpc_connectivity_state pf_check_connectivity_locked(
245 grpc_exec_ctx *exec_ctx, grpc_lb_policy *pol, grpc_error **error) {
246 pick_first_lb_policy *p = (pick_first_lb_policy *)pol;
247 return grpc_connectivity_state_get(&p->state_tracker, error);
248}
249
250static void pf_notify_on_state_change_locked(grpc_exec_ctx *exec_ctx,
251 grpc_lb_policy *pol,
252 grpc_connectivity_state *current,
253 grpc_closure *notify) {
254 pick_first_lb_policy *p = (pick_first_lb_policy *)pol;
255 grpc_connectivity_state_notify_on_state_change(exec_ctx, &p->state_tracker,
256 current, notify);
257}
258
259static void pf_ping_one_locked(grpc_exec_ctx *exec_ctx, grpc_lb_policy *pol,
260 grpc_closure *closure) {
261 pick_first_lb_policy *p = (pick_first_lb_policy *)pol;
262 if (p->selected) {
263 grpc_connected_subchannel_ping(exec_ctx, p->selected, closure);
264 } else {
ncteisen274bbbe2017-06-08 14:57:11 -0700265 GRPC_CLOSURE_SCHED(exec_ctx, closure,
David Garcia Quintas87d5a312017-06-06 19:45:58 -0700266 GRPC_ERROR_CREATE_FROM_STATIC_STRING("Not connected"));
267 }
268}
269
270/* unsubscribe all subchannels */
271static void stop_connectivity_watchers(grpc_exec_ctx *exec_ctx,
272 pick_first_lb_policy *p) {
273 if (p->num_subchannels > 0) {
274 GPR_ASSERT(p->selected == NULL);
David Garcia Quintasaf084dc2017-06-27 13:42:54 -0700275 if (GRPC_TRACER_ON(grpc_lb_pick_first_trace)) {
276 gpr_log(GPR_DEBUG, "Pick First %p unsubscribing from subchannel %p",
277 (void *)p, (void *)p->subchannels[p->checking_subchannel]);
278 }
David Garcia Quintas87d5a312017-06-06 19:45:58 -0700279 grpc_subchannel_notify_on_state_change(
280 exec_ctx, p->subchannels[p->checking_subchannel], NULL, NULL,
281 &p->connectivity_changed);
282 p->updating_subchannels = true;
283 } else if (p->selected != NULL) {
David Garcia Quintasaf084dc2017-06-27 13:42:54 -0700284 if (GRPC_TRACER_ON(grpc_lb_pick_first_trace)) {
285 gpr_log(GPR_DEBUG,
286 "Pick First %p unsubscribing from selected subchannel %p",
287 (void *)p, (void *)p->selected);
288 }
David Garcia Quintas87d5a312017-06-06 19:45:58 -0700289 grpc_connected_subchannel_notify_on_state_change(
290 exec_ctx, p->selected, NULL, NULL, &p->connectivity_changed);
291 p->updating_selected = true;
292 }
293}
294
295/* true upon success */
296static void pf_update_locked(grpc_exec_ctx *exec_ctx, grpc_lb_policy *policy,
297 const grpc_lb_policy_args *args) {
298 pick_first_lb_policy *p = (pick_first_lb_policy *)policy;
299 /* Find the number of backend addresses. We ignore balancer
300 * addresses, since we don't know how to handle them. */
301 const grpc_arg *arg =
302 grpc_channel_args_find(args->args, GRPC_ARG_LB_ADDRESSES);
303 if (arg == NULL || arg->type != GRPC_ARG_POINTER) {
304 if (p->subchannels == NULL) {
305 // If we don't have a current subchannel list, go into TRANSIENT FAILURE.
306 grpc_connectivity_state_set(
307 exec_ctx, &p->state_tracker, GRPC_CHANNEL_TRANSIENT_FAILURE,
308 GRPC_ERROR_CREATE_FROM_STATIC_STRING("Missing update in args"),
309 "pf_update_missing");
310 } else {
311 // otherwise, keep using the current subchannel list (ignore this update).
312 gpr_log(GPR_ERROR,
313 "No valid LB addresses channel arg for Pick First %p update, "
314 "ignoring.",
315 (void *)p);
316 }
317 return;
318 }
319 const grpc_lb_addresses *addresses = arg->value.pointer.p;
320 size_t num_addrs = 0;
321 for (size_t i = 0; i < addresses->num_addresses; i++) {
322 if (!addresses->addresses[i].is_balancer) ++num_addrs;
323 }
324 if (num_addrs == 0) {
325 // Empty update. Unsubscribe from all current subchannels and put the
326 // channel in TRANSIENT_FAILURE.
327 grpc_connectivity_state_set(
328 exec_ctx, &p->state_tracker, GRPC_CHANNEL_TRANSIENT_FAILURE,
329 GRPC_ERROR_CREATE_FROM_STATIC_STRING("Empty update"),
330 "pf_update_empty");
331 stop_connectivity_watchers(exec_ctx, p);
332 return;
333 }
334 if (GRPC_TRACER_ON(grpc_lb_pick_first_trace)) {
335 gpr_log(GPR_INFO, "Pick First %p received update with %lu addresses",
336 (void *)p, (unsigned long)num_addrs);
337 }
338 grpc_subchannel_args *sc_args = gpr_zalloc(sizeof(*sc_args) * num_addrs);
339 /* We remove the following keys in order for subchannel keys belonging to
340 * subchannels point to the same address to match. */
341 static const char *keys_to_remove[] = {GRPC_ARG_SUBCHANNEL_ADDRESS,
342 GRPC_ARG_LB_ADDRESSES};
343 size_t sc_args_count = 0;
344
345 /* Create list of subchannel args for new addresses in \a args. */
346 for (size_t i = 0; i < addresses->num_addresses; i++) {
347 if (addresses->addresses[i].is_balancer) continue;
348 if (addresses->addresses[i].user_data != NULL) {
349 gpr_log(GPR_ERROR,
350 "This LB policy doesn't support user data. It will be ignored");
351 }
352 grpc_arg addr_arg =
353 grpc_create_subchannel_address_arg(&addresses->addresses[i].address);
354 grpc_channel_args *new_args = grpc_channel_args_copy_and_add_and_remove(
355 args->args, keys_to_remove, GPR_ARRAY_SIZE(keys_to_remove), &addr_arg,
356 1);
357 gpr_free(addr_arg.value.string);
358 sc_args[sc_args_count++].args = new_args;
359 }
360
361 /* Check if p->selected is amongst them. If so, we are done. */
362 if (p->selected != NULL) {
363 GPR_ASSERT(p->selected_key != NULL);
364 for (size_t i = 0; i < sc_args_count; i++) {
365 grpc_subchannel_key *ith_sc_key = grpc_subchannel_key_create(&sc_args[i]);
366 const bool found_selected =
367 grpc_subchannel_key_compare(p->selected_key, ith_sc_key) == 0;
368 grpc_subchannel_key_destroy(exec_ctx, ith_sc_key);
369 if (found_selected) {
370 // The currently selected subchannel is in the update: we are done.
371 if (GRPC_TRACER_ON(grpc_lb_pick_first_trace)) {
372 gpr_log(GPR_INFO,
373 "Pick First %p found already selected subchannel %p amongst "
374 "updates. Update done.",
375 (void *)p, (void *)p->selected);
376 }
377 for (size_t j = 0; j < sc_args_count; j++) {
378 grpc_channel_args_destroy(exec_ctx,
379 (grpc_channel_args *)sc_args[j].args);
380 }
381 gpr_free(sc_args);
382 return;
383 }
384 }
385 }
386 // We only check for already running updates here because if the previous
387 // steps were successful, the update can be considered done without any
388 // interference (ie, no callbacks were scheduled).
389 if (p->updating_selected || p->updating_subchannels) {
390 if (GRPC_TRACER_ON(grpc_lb_pick_first_trace)) {
391 gpr_log(GPR_INFO,
392 "Update already in progress for pick first %p. Deferring update.",
393 (void *)p);
394 }
395 if (p->pending_update_args != NULL) {
396 grpc_channel_args_destroy(exec_ctx, p->pending_update_args->args);
397 gpr_free(p->pending_update_args);
398 }
399 p->pending_update_args = gpr_zalloc(sizeof(*p->pending_update_args));
400 p->pending_update_args->client_channel_factory =
401 args->client_channel_factory;
402 p->pending_update_args->args = grpc_channel_args_copy(args->args);
403 p->pending_update_args->combiner = args->combiner;
404 return;
405 }
406 /* Create the subchannels for the new subchannel args/addresses. */
407 grpc_subchannel **new_subchannels =
408 gpr_zalloc(sizeof(*new_subchannels) * sc_args_count);
409 size_t num_new_subchannels = 0;
410 for (size_t i = 0; i < sc_args_count; i++) {
411 grpc_subchannel *subchannel = grpc_client_channel_factory_create_subchannel(
412 exec_ctx, args->client_channel_factory, &sc_args[i]);
413 if (GRPC_TRACER_ON(grpc_lb_pick_first_trace)) {
414 char *address_uri =
415 grpc_sockaddr_to_uri(&addresses->addresses[i].address);
416 gpr_log(GPR_INFO,
417 "Pick First %p created subchannel %p for address uri %s",
418 (void *)p, (void *)subchannel, address_uri);
419 gpr_free(address_uri);
420 }
421 grpc_channel_args_destroy(exec_ctx, (grpc_channel_args *)sc_args[i].args);
422 if (subchannel != NULL) new_subchannels[num_new_subchannels++] = subchannel;
423 }
424 gpr_free(sc_args);
425 if (num_new_subchannels == 0) {
426 gpr_free(new_subchannels);
427 // Empty update. Unsubscribe from all current subchannels and put the
428 // channel in TRANSIENT_FAILURE.
429 grpc_connectivity_state_set(
430 exec_ctx, &p->state_tracker, GRPC_CHANNEL_TRANSIENT_FAILURE,
431 GRPC_ERROR_CREATE_FROM_STATIC_STRING("No valid addresses in update"),
432 "pf_update_no_valid_addresses");
433 stop_connectivity_watchers(exec_ctx, p);
434 return;
435 }
436
437 /* Destroy the current subchannels. Repurpose pf_shutdown/destroy. */
438 stop_connectivity_watchers(exec_ctx, p);
439
440 /* Save new subchannels. The switch over will happen in
441 * pf_connectivity_changed_locked */
442 if (p->updating_selected || p->updating_subchannels) {
443 p->num_new_subchannels = num_new_subchannels;
444 p->new_subchannels = new_subchannels;
445 } else { /* nothing is updating. Get things moving from here */
446 p->num_subchannels = num_new_subchannels;
447 p->subchannels = new_subchannels;
448 p->new_subchannels = NULL;
449 p->num_new_subchannels = 0;
450 if (p->started_picking) {
451 p->checking_subchannel = 0;
452 p->checking_connectivity = GRPC_CHANNEL_IDLE;
453 grpc_subchannel_notify_on_state_change(
454 exec_ctx, p->subchannels[p->checking_subchannel],
455 p->base.interested_parties, &p->checking_connectivity,
456 &p->connectivity_changed);
457 }
458 }
459}
460
Craig Tiller2400bf52017-02-09 16:25:19 -0800461static void pf_connectivity_changed_locked(grpc_exec_ctx *exec_ctx, void *arg,
462 grpc_error *error) {
Craig Tillereb3b12e2015-06-26 14:42:49 -0700463 pick_first_lb_policy *p = arg;
Craig Tillerb5585d42015-11-17 07:18:31 -0800464 grpc_subchannel *selected_subchannel;
Craig Tillereb3b12e2015-06-26 14:42:49 -0700465 pending_pick *pp;
Craig Tillereb3b12e2015-06-26 14:42:49 -0700466
David Garcia Quintasaf084dc2017-06-27 13:42:54 -0700467 if (GRPC_TRACER_ON(grpc_lb_pick_first_trace)) {
468 gpr_log(
469 GPR_DEBUG,
470 "Pick First %p connectivity changed. Updating selected: %d; Updating "
471 "subchannels: %d; Checking %lu index (%lu total); State: %d; ",
472 (void *)p, p->updating_selected, p->updating_subchannels,
473 (unsigned long)p->checking_subchannel,
474 (unsigned long)p->num_subchannels, p->checking_connectivity);
475 }
David Garcia Quintas87d5a312017-06-06 19:45:58 -0700476 bool restart = false;
David Garcia Quintasaf084dc2017-06-27 13:42:54 -0700477 if (p->updating_selected && error != GRPC_ERROR_NONE) {
David Garcia Quintas87d5a312017-06-06 19:45:58 -0700478 /* Captured the unsubscription for p->selected */
479 GPR_ASSERT(p->selected != NULL);
480 GRPC_CONNECTED_SUBCHANNEL_UNREF(exec_ctx, p->selected,
481 "pf_update_connectivity");
David Garcia Quintasaf084dc2017-06-27 13:42:54 -0700482 if (GRPC_TRACER_ON(grpc_lb_pick_first_trace)) {
483 gpr_log(GPR_DEBUG, "Pick First %p unreffing selected subchannel %p",
484 (void *)p, (void *)p->selected);
485 }
David Garcia Quintas87d5a312017-06-06 19:45:58 -0700486 p->updating_selected = false;
487 if (p->num_new_subchannels == 0) {
488 p->selected = NULL;
489 return;
490 }
491 restart = true;
492 }
David Garcia Quintasaf084dc2017-06-27 13:42:54 -0700493 if (p->updating_subchannels && error != GRPC_ERROR_NONE) {
David Garcia Quintas87d5a312017-06-06 19:45:58 -0700494 /* Captured the unsubscription for the checking subchannel */
495 GPR_ASSERT(p->selected == NULL);
496 for (size_t i = 0; i < p->num_subchannels; i++) {
497 GRPC_SUBCHANNEL_UNREF(exec_ctx, p->subchannels[i],
498 "pf_update_connectivity");
David Garcia Quintasaf084dc2017-06-27 13:42:54 -0700499 if (GRPC_TRACER_ON(grpc_lb_pick_first_trace)) {
500 gpr_log(GPR_DEBUG, "Pick First %p unreffing subchannel %p", (void *)p,
501 (void *)p->subchannels[i]);
502 }
David Garcia Quintas87d5a312017-06-06 19:45:58 -0700503 }
504 gpr_free(p->subchannels);
505 p->subchannels = NULL;
506 p->num_subchannels = 0;
507 p->updating_subchannels = false;
508 if (p->num_new_subchannels == 0) return;
509 restart = true;
510 }
511 if (restart) {
512 p->selected = NULL;
513 p->selected_key = NULL;
David Garcia Quintas87d5a312017-06-06 19:45:58 -0700514 GPR_ASSERT(p->new_subchannels != NULL);
515 GPR_ASSERT(p->num_new_subchannels > 0);
516 p->num_subchannels = p->num_new_subchannels;
517 p->subchannels = p->new_subchannels;
518 p->num_new_subchannels = 0;
519 p->new_subchannels = NULL;
David Garcia Quintas87d5a312017-06-06 19:45:58 -0700520 if (p->started_picking) {
521 /* If we were picking, continue to do so over the new subchannels,
522 * starting from the 0th index. */
523 p->checking_subchannel = 0;
524 p->checking_connectivity = GRPC_CHANNEL_IDLE;
525 /* reuses the weak ref from start_picking_locked */
526 grpc_subchannel_notify_on_state_change(
527 exec_ctx, p->subchannels[p->checking_subchannel],
528 p->base.interested_parties, &p->checking_connectivity,
529 &p->connectivity_changed);
530 }
531 if (p->pending_update_args != NULL) {
532 const grpc_lb_policy_args *args = p->pending_update_args;
533 p->pending_update_args = NULL;
534 pf_update_locked(exec_ctx, &p->base, args);
535 }
536 return;
537 }
538 GRPC_ERROR_REF(error);
Craig Tillera82950e2015-09-22 12:33:20 -0700539 if (p->shutdown) {
Craig Tiller48613042015-11-29 14:45:11 -0800540 GRPC_LB_POLICY_WEAK_UNREF(exec_ctx, &p->base, "pick_first_connectivity");
Craig Tillerae125932016-05-13 16:34:29 -0700541 GRPC_ERROR_UNREF(error);
Craig Tillera82950e2015-09-22 12:33:20 -0700542 return;
Craig Tiller2400bf52017-02-09 16:25:19 -0800543 } else if (p->selected != NULL) {
Craig Tillercb2609f2015-11-24 17:19:19 -0800544 if (p->checking_connectivity == GRPC_CHANNEL_TRANSIENT_FAILURE) {
545 /* if the selected channel goes bad, we're done */
Craig Tiller48ed92e2016-06-02 11:07:12 -0700546 p->checking_connectivity = GRPC_CHANNEL_SHUTDOWN;
Craig Tillercb2609f2015-11-24 17:19:19 -0800547 }
Craig Tillera82950e2015-09-22 12:33:20 -0700548 grpc_connectivity_state_set(exec_ctx, &p->state_tracker,
Craig Tillerf707d622016-05-06 14:26:12 -0700549 p->checking_connectivity, GRPC_ERROR_REF(error),
Craig Tiller804ff712016-05-05 16:25:40 -0700550 "selected_changed");
Craig Tiller48ed92e2016-06-02 11:07:12 -0700551 if (p->checking_connectivity != GRPC_CHANNEL_SHUTDOWN) {
Craig Tillerab33b482015-11-21 08:11:04 -0800552 grpc_connected_subchannel_notify_on_state_change(
Craig Tiller2400bf52017-02-09 16:25:19 -0800553 exec_ctx, p->selected, p->base.interested_parties,
Craig Tillera6bebf42015-12-01 17:02:35 -0800554 &p->checking_connectivity, &p->connectivity_changed);
Craig Tillera82950e2015-09-22 12:33:20 -0700555 } else {
Craig Tiller48613042015-11-29 14:45:11 -0800556 GRPC_LB_POLICY_WEAK_UNREF(exec_ctx, &p->base, "pick_first_connectivity");
Craig Tiller1ada6ad2015-07-16 16:19:14 -0700557 }
Craig Tillera82950e2015-09-22 12:33:20 -0700558 } else {
559 loop:
560 switch (p->checking_connectivity) {
David Garcia Quintasea6689d2016-11-08 09:46:41 -0800561 case GRPC_CHANNEL_INIT:
Jan Tattermuschb0fb2d22016-11-16 14:04:05 +0100562 GPR_UNREACHABLE_CODE(return );
Craig Tillera82950e2015-09-22 12:33:20 -0700563 case GRPC_CHANNEL_READY:
564 grpc_connectivity_state_set(exec_ctx, &p->state_tracker,
Craig Tiller804ff712016-05-05 16:25:40 -0700565 GRPC_CHANNEL_READY, GRPC_ERROR_NONE,
566 "connecting_ready");
Craig Tillerb5585d42015-11-17 07:18:31 -0800567 selected_subchannel = p->subchannels[p->checking_subchannel];
Craig Tiller2400bf52017-02-09 16:25:19 -0800568 p->selected = GRPC_CONNECTED_SUBCHANNEL_REF(
569 grpc_subchannel_get_connected_subchannel(selected_subchannel),
570 "picked_first");
David Garcia Quintas87d5a312017-06-06 19:45:58 -0700571
572 if (GRPC_TRACER_ON(grpc_lb_pick_first_trace)) {
David Garcia Quintasaf084dc2017-06-27 13:42:54 -0700573 gpr_log(GPR_INFO,
574 "Pick First %p selected subchannel %p (connected %p)",
575 (void *)p, (void *)selected_subchannel, (void *)p->selected);
David Garcia Quintas87d5a312017-06-06 19:45:58 -0700576 }
577 p->selected_key = grpc_subchannel_get_key(selected_subchannel);
Craig Tillerb09d84d2015-10-06 09:12:16 -0700578 /* drop the pick list: we are connected now */
Craig Tiller48613042015-11-29 14:45:11 -0800579 GRPC_LB_POLICY_WEAK_REF(&p->base, "destroy_subchannels");
Craig Tiller2400bf52017-02-09 16:25:19 -0800580 destroy_subchannels_locked(exec_ctx, p);
Craig Tillerb09d84d2015-10-06 09:12:16 -0700581 /* update any calls that were waiting for a pick */
Craig Tillera82950e2015-09-22 12:33:20 -0700582 while ((pp = p->pending_picks)) {
583 p->pending_picks = pp->next;
Craig Tiller2400bf52017-02-09 16:25:19 -0800584 *pp->target = GRPC_CONNECTED_SUBCHANNEL_REF(p->selected, "picked");
David Garcia Quintas87d5a312017-06-06 19:45:58 -0700585 if (GRPC_TRACER_ON(grpc_lb_pick_first_trace)) {
586 gpr_log(GPR_INFO,
587 "Servicing pending pick with selected subchannel %p",
588 (void *)p->selected);
589 }
ncteisen274bbbe2017-06-08 14:57:11 -0700590 GRPC_CLOSURE_SCHED(exec_ctx, pp->on_complete, GRPC_ERROR_NONE);
Craig Tillera82950e2015-09-22 12:33:20 -0700591 gpr_free(pp);
592 }
Craig Tillerab33b482015-11-21 08:11:04 -0800593 grpc_connected_subchannel_notify_on_state_change(
Craig Tiller2400bf52017-02-09 16:25:19 -0800594 exec_ctx, p->selected, p->base.interested_parties,
Craig Tillera6bebf42015-12-01 17:02:35 -0800595 &p->checking_connectivity, &p->connectivity_changed);
Craig Tillera82950e2015-09-22 12:33:20 -0700596 break;
597 case GRPC_CHANNEL_TRANSIENT_FAILURE:
Craig Tillera82950e2015-09-22 12:33:20 -0700598 p->checking_subchannel =
599 (p->checking_subchannel + 1) % p->num_subchannels;
Craig Tiller131b6de2016-03-31 17:05:28 -0700600 if (p->checking_subchannel == 0) {
David Garcia Quintasaf084dc2017-06-27 13:42:54 -0700601 /* only trigger transient failure when we've tried all alternatives
602 */
Craig Tiller804ff712016-05-05 16:25:40 -0700603 grpc_connectivity_state_set(
604 exec_ctx, &p->state_tracker, GRPC_CHANNEL_TRANSIENT_FAILURE,
Craig Tillerf707d622016-05-06 14:26:12 -0700605 GRPC_ERROR_REF(error), "connecting_transient_failure");
Craig Tiller131b6de2016-03-31 17:05:28 -0700606 }
Craig Tillerf707d622016-05-06 14:26:12 -0700607 GRPC_ERROR_UNREF(error);
Craig Tillera82950e2015-09-22 12:33:20 -0700608 p->checking_connectivity = grpc_subchannel_check_connectivity(
Craig Tiller804ff712016-05-05 16:25:40 -0700609 p->subchannels[p->checking_subchannel], &error);
Craig Tillera82950e2015-09-22 12:33:20 -0700610 if (p->checking_connectivity == GRPC_CHANNEL_TRANSIENT_FAILURE) {
611 grpc_subchannel_notify_on_state_change(
612 exec_ctx, p->subchannels[p->checking_subchannel],
Craig Tiller69b093b2016-02-25 19:04:07 -0800613 p->base.interested_parties, &p->checking_connectivity,
Craig Tiller1d881fb2015-12-01 07:39:04 -0800614 &p->connectivity_changed);
Craig Tillera82950e2015-09-22 12:33:20 -0700615 } else {
616 goto loop;
617 }
618 break;
619 case GRPC_CHANNEL_CONNECTING:
620 case GRPC_CHANNEL_IDLE:
Craig Tiller804ff712016-05-05 16:25:40 -0700621 grpc_connectivity_state_set(
622 exec_ctx, &p->state_tracker, GRPC_CHANNEL_CONNECTING,
Craig Tillerf707d622016-05-06 14:26:12 -0700623 GRPC_ERROR_REF(error), "connecting_changed");
Craig Tillera82950e2015-09-22 12:33:20 -0700624 grpc_subchannel_notify_on_state_change(
625 exec_ctx, p->subchannels[p->checking_subchannel],
Craig Tiller69b093b2016-02-25 19:04:07 -0800626 p->base.interested_parties, &p->checking_connectivity,
Craig Tiller1d881fb2015-12-01 07:39:04 -0800627 &p->connectivity_changed);
Craig Tillera82950e2015-09-22 12:33:20 -0700628 break;
Craig Tiller48ed92e2016-06-02 11:07:12 -0700629 case GRPC_CHANNEL_SHUTDOWN:
Craig Tillera82950e2015-09-22 12:33:20 -0700630 p->num_subchannels--;
Craig Tiller86c99582015-11-25 15:22:26 -0800631 GPR_SWAP(grpc_subchannel *, p->subchannels[p->checking_subchannel],
632 p->subchannels[p->num_subchannels]);
Craig Tillera82950e2015-09-22 12:33:20 -0700633 GRPC_SUBCHANNEL_UNREF(exec_ctx, p->subchannels[p->num_subchannels],
634 "pick_first");
635 if (p->num_subchannels == 0) {
Craig Tiller804ff712016-05-05 16:25:40 -0700636 grpc_connectivity_state_set(
Craig Tillerd925c932016-06-06 08:38:50 -0700637 exec_ctx, &p->state_tracker, GRPC_CHANNEL_SHUTDOWN,
ncteisen4b36a3d2017-03-13 19:08:06 -0700638 GRPC_ERROR_CREATE_REFERENCING_FROM_STATIC_STRING(
639 "Pick first exhausted channels", &error, 1),
Craig Tiller804ff712016-05-05 16:25:40 -0700640 "no_more_channels");
Craig Tillera82950e2015-09-22 12:33:20 -0700641 while ((pp = p->pending_picks)) {
642 p->pending_picks = pp->next;
643 *pp->target = NULL;
ncteisen274bbbe2017-06-08 14:57:11 -0700644 GRPC_CLOSURE_SCHED(exec_ctx, pp->on_complete, GRPC_ERROR_NONE);
Craig Tillera82950e2015-09-22 12:33:20 -0700645 gpr_free(pp);
646 }
Craig Tiller1d881fb2015-12-01 07:39:04 -0800647 GRPC_LB_POLICY_WEAK_UNREF(exec_ctx, &p->base,
648 "pick_first_connectivity");
Craig Tillera82950e2015-09-22 12:33:20 -0700649 } else {
Craig Tiller804ff712016-05-05 16:25:40 -0700650 grpc_connectivity_state_set(
651 exec_ctx, &p->state_tracker, GRPC_CHANNEL_TRANSIENT_FAILURE,
Craig Tillerf707d622016-05-06 14:26:12 -0700652 GRPC_ERROR_REF(error), "subchannel_failed");
Craig Tillera82950e2015-09-22 12:33:20 -0700653 p->checking_subchannel %= p->num_subchannels;
Craig Tillerf707d622016-05-06 14:26:12 -0700654 GRPC_ERROR_UNREF(error);
Craig Tillera82950e2015-09-22 12:33:20 -0700655 p->checking_connectivity = grpc_subchannel_check_connectivity(
Craig Tiller804ff712016-05-05 16:25:40 -0700656 p->subchannels[p->checking_subchannel], &error);
Craig Tillera82950e2015-09-22 12:33:20 -0700657 goto loop;
658 }
Craig Tiller1ada6ad2015-07-16 16:19:14 -0700659 }
Craig Tillera82950e2015-09-22 12:33:20 -0700660 }
Craig Tiller1ada6ad2015-07-16 16:19:14 -0700661
Craig Tillerf707d622016-05-06 14:26:12 -0700662 GRPC_ERROR_UNREF(error);
Craig Tillereb3b12e2015-06-26 14:42:49 -0700663}
664
665static const grpc_lb_policy_vtable pick_first_lb_policy_vtable = {
Craig Tiller2400bf52017-02-09 16:25:19 -0800666 pf_destroy,
667 pf_shutdown_locked,
668 pf_pick_locked,
669 pf_cancel_pick_locked,
670 pf_cancel_picks_locked,
671 pf_ping_one_locked,
672 pf_exit_idle_locked,
673 pf_check_connectivity_locked,
David Garcia Quintas87d5a312017-06-06 19:45:58 -0700674 pf_notify_on_state_change_locked,
675 pf_update_locked};
Craig Tillereb3b12e2015-06-26 14:42:49 -0700676
Craig Tillera82950e2015-09-22 12:33:20 -0700677static void pick_first_factory_ref(grpc_lb_policy_factory *factory) {}
David Garcia Quintas5c4543d2015-09-03 15:49:56 -0700678
Craig Tillera82950e2015-09-22 12:33:20 -0700679static void pick_first_factory_unref(grpc_lb_policy_factory *factory) {}
David Garcia Quintas5c4543d2015-09-03 15:49:56 -0700680
David Garcia Quintas67c0d042016-03-25 01:37:53 -0700681static grpc_lb_policy *create_pick_first(grpc_exec_ctx *exec_ctx,
682 grpc_lb_policy_factory *factory,
Craig Tillera82950e2015-09-22 12:33:20 -0700683 grpc_lb_policy_args *args) {
David Garcia Quintas86fcfcc2016-03-31 23:22:28 -0700684 GPR_ASSERT(args->client_channel_factory != NULL);
Craig Tiller6f417882017-02-16 14:09:39 -0800685 pick_first_lb_policy *p = gpr_zalloc(sizeof(*p));
David Garcia Quintasaf084dc2017-06-27 13:42:54 -0700686 if (GRPC_TRACER_ON(grpc_lb_pick_first_trace)) {
687 gpr_log(GPR_DEBUG, "Pick First %p created.", (void *)p);
688 }
David Garcia Quintas87d5a312017-06-06 19:45:58 -0700689 pf_update_locked(exec_ctx, &p->base, args);
Craig Tiller2400bf52017-02-09 16:25:19 -0800690 grpc_lb_policy_init(&p->base, &pick_first_lb_policy_vtable, args->combiner);
ncteisen274bbbe2017-06-08 14:57:11 -0700691 GRPC_CLOSURE_INIT(&p->connectivity_changed, pf_connectivity_changed_locked, p,
Craig Tilleree4b1452017-05-12 10:56:03 -0700692 grpc_combiner_scheduler(args->combiner));
Craig Tillereb3b12e2015-06-26 14:42:49 -0700693 return &p->base;
694}
David Garcia Quintas5c4543d2015-09-03 15:49:56 -0700695
696static const grpc_lb_policy_factory_vtable pick_first_factory_vtable = {
Craig Tillera82950e2015-09-22 12:33:20 -0700697 pick_first_factory_ref, pick_first_factory_unref, create_pick_first,
698 "pick_first"};
David Garcia Quintas5c4543d2015-09-03 15:49:56 -0700699
700static grpc_lb_policy_factory pick_first_lb_policy_factory = {
Craig Tillera82950e2015-09-22 12:33:20 -0700701 &pick_first_factory_vtable};
David Garcia Quintas5c4543d2015-09-03 15:49:56 -0700702
Craig Tillerfb433852016-03-29 08:51:07 -0700703static grpc_lb_policy_factory *pick_first_lb_factory_create() {
David Garcia Quintas5c4543d2015-09-03 15:49:56 -0700704 return &pick_first_lb_policy_factory;
705}
Craig Tillerfb433852016-03-29 08:51:07 -0700706
707/* Plugin registration */
708
709void grpc_lb_policy_pick_first_init() {
Craig Tiller3113ef42016-03-29 09:03:14 -0700710 grpc_register_lb_policy(pick_first_lb_factory_create());
ncteisen06bce6e2017-07-10 07:58:49 -0700711 grpc_register_tracer(&grpc_lb_pick_first_trace);
Craig Tillerfb433852016-03-29 08:51:07 -0700712}
713
714void grpc_lb_policy_pick_first_shutdown() {}