blob: 7dad7f7cd4f429557a90849301d3e217304d17f9 [file] [log] [blame]
Craig Tiller3bc8ebd2015-06-24 15:41:15 -07001/*
2 *
3 * Copyright 2015, Google Inc.
4 * All rights reserved.
5 *
6 * Redistribution and use in source and binary forms, with or without
7 * modification, are permitted provided that the following conditions are
8 * met:
9 *
10 * * Redistributions of source code must retain the above copyright
11 * notice, this list of conditions and the following disclaimer.
12 * * Redistributions in binary form must reproduce the above
13 * copyright notice, this list of conditions and the following disclaimer
14 * in the documentation and/or other materials provided with the
15 * distribution.
16 * * Neither the name of Google Inc. nor the names of its
17 * contributors may be used to endorse or promote products derived from
18 * this software without specific prior written permission.
19 *
20 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
21 * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
22 * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
23 * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
24 * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
25 * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
26 * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
27 * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
28 * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
29 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
30 * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
31 *
32 */
33
David Garcia Quintas5c4543d2015-09-03 15:49:56 -070034#include "src/core/client_config/lb_policy_factory.h"
Craig Tiller3bc8ebd2015-06-24 15:41:15 -070035#include "src/core/client_config/lb_policies/pick_first.h"
Craig Tillereb3b12e2015-06-26 14:42:49 -070036
37#include <string.h>
38
39#include <grpc/support/alloc.h>
Craig Tiller08a1cf82015-06-29 09:37:52 -070040#include "src/core/transport/connectivity_state.h"
Craig Tillereb3b12e2015-06-26 14:42:49 -070041
Craig Tillera82950e2015-09-22 12:33:20 -070042typedef struct pending_pick {
Craig Tillereb3b12e2015-06-26 14:42:49 -070043 struct pending_pick *next;
44 grpc_pollset *pollset;
Craig Tillerb5585d42015-11-17 07:18:31 -080045 grpc_connected_subchannel **target;
Craig Tiller33825112015-09-18 07:44:19 -070046 grpc_closure *on_complete;
Craig Tillereb3b12e2015-06-26 14:42:49 -070047} pending_pick;
48
Craig Tillera82950e2015-09-22 12:33:20 -070049typedef struct {
Craig Tillereb3b12e2015-06-26 14:42:49 -070050 /** base policy: must be first */
51 grpc_lb_policy base;
Craig Tillereb3b12e2015-06-26 14:42:49 -070052 /** all our subchannels */
53 grpc_subchannel **subchannels;
54 size_t num_subchannels;
55
Craig Tiller33825112015-09-18 07:44:19 -070056 grpc_closure connectivity_changed;
Craig Tillereb3b12e2015-06-26 14:42:49 -070057
58 /** mutex protecting remaining members */
59 gpr_mu mu;
60 /** the selected channel
61 TODO(ctiller): this should be atomically set so we don't
62 need to take a mutex in the common case */
Craig Tillerb5585d42015-11-17 07:18:31 -080063 grpc_connected_subchannel *selected;
Craig Tillereb3b12e2015-06-26 14:42:49 -070064 /** have we started picking? */
65 int started_picking;
Craig Tillera14215a2015-07-17 17:21:08 -070066 /** are we shut down? */
67 int shutdown;
Craig Tillereb3b12e2015-06-26 14:42:49 -070068 /** which subchannel are we watching? */
69 size_t checking_subchannel;
70 /** what is the connectivity of that channel? */
71 grpc_connectivity_state checking_connectivity;
72 /** list of picks that are waiting on connectivity */
73 pending_pick *pending_picks;
Craig Tillerc7b5f762015-06-27 11:48:42 -070074
75 /** our connectivity state tracker */
76 grpc_connectivity_state_tracker state_tracker;
Craig Tillereb3b12e2015-06-26 14:42:49 -070077} pick_first_lb_policy;
78
Craig Tillera82950e2015-09-22 12:33:20 -070079void pf_destroy(grpc_exec_ctx *exec_ctx, grpc_lb_policy *pol) {
80 pick_first_lb_policy *p = (pick_first_lb_policy *)pol;
Craig Tillerd7b68e72015-06-28 11:41:09 -070081 size_t i;
Craig Tillera82950e2015-09-22 12:33:20 -070082 GPR_ASSERT(p->pending_picks == NULL);
83 for (i = 0; i < p->num_subchannels; i++) {
84 GRPC_SUBCHANNEL_UNREF(exec_ctx, p->subchannels[i], "pick_first");
85 }
Craig Tiller89a768e2015-10-06 09:55:59 -070086 if (p->selected) {
Craig Tillerb5585d42015-11-17 07:18:31 -080087 GRPC_CONNECTED_SUBCHANNEL_UNREF(exec_ctx, p->selected, "picked_first");
Craig Tiller89a768e2015-10-06 09:55:59 -070088 }
Craig Tillera82950e2015-09-22 12:33:20 -070089 grpc_connectivity_state_destroy(exec_ctx, &p->state_tracker);
90 gpr_free(p->subchannels);
91 gpr_mu_destroy(&p->mu);
92 gpr_free(p);
Craig Tillereb3b12e2015-06-26 14:42:49 -070093}
94
Craig Tillera82950e2015-09-22 12:33:20 -070095void pf_shutdown(grpc_exec_ctx *exec_ctx, grpc_lb_policy *pol) {
96 pick_first_lb_policy *p = (pick_first_lb_policy *)pol;
Craig Tillerd2cc4592015-07-01 07:50:47 -070097 pending_pick *pp;
Craig Tillera82950e2015-09-22 12:33:20 -070098 gpr_mu_lock(&p->mu);
Craig Tillera14215a2015-07-17 17:21:08 -070099 p->shutdown = 1;
Craig Tiller5795da72015-09-17 15:27:13 -0700100 pp = p->pending_picks;
101 p->pending_picks = NULL;
Craig Tillera82950e2015-09-22 12:33:20 -0700102 grpc_connectivity_state_set(exec_ctx, &p->state_tracker,
103 GRPC_CHANNEL_FATAL_FAILURE, "shutdown");
Craig Tillerf036a642015-12-01 17:00:40 -0800104 /* cancel subscription */
Craig Tiller48613042015-11-29 14:45:11 -0800105 if (p->selected != NULL) {
Craig Tiller1d881fb2015-12-01 07:39:04 -0800106 grpc_connected_subchannel_notify_on_state_change(
Craig Tillerf036a642015-12-01 17:00:40 -0800107 exec_ctx, p->selected, NULL, NULL, &p->connectivity_changed);
Craig Tiller48613042015-11-29 14:45:11 -0800108 } else {
Craig Tiller1d881fb2015-12-01 07:39:04 -0800109 grpc_subchannel_notify_on_state_change(
110 exec_ctx, p->subchannels[p->checking_subchannel], NULL, NULL,
111 &p->connectivity_changed);
Craig Tiller48613042015-11-29 14:45:11 -0800112 }
Craig Tillera82950e2015-09-22 12:33:20 -0700113 gpr_mu_unlock(&p->mu);
114 while (pp != NULL) {
115 pending_pick *next = pp->next;
116 *pp->target = NULL;
Craig Tiller1d881fb2015-12-01 07:39:04 -0800117 grpc_pollset_set_del_pollset(exec_ctx, &p->base.interested_parties,
118 pp->pollset);
Craig Tillera82950e2015-09-22 12:33:20 -0700119 grpc_exec_ctx_enqueue(exec_ctx, pp->on_complete, 1);
120 gpr_free(pp);
121 pp = next;
122 }
Craig Tillereb3b12e2015-06-26 14:42:49 -0700123}
124
Craig Tiller577c9b22015-11-02 14:11:15 -0800125static void pf_cancel_pick(grpc_exec_ctx *exec_ctx, grpc_lb_policy *pol,
Craig Tillerb5585d42015-11-17 07:18:31 -0800126 grpc_connected_subchannel **target) {
Craig Tiller577c9b22015-11-02 14:11:15 -0800127 pick_first_lb_policy *p = (pick_first_lb_policy *)pol;
128 pending_pick *pp;
129 gpr_mu_lock(&p->mu);
130 pp = p->pending_picks;
131 p->pending_picks = NULL;
132 while (pp != NULL) {
133 pending_pick *next = pp->next;
134 if (pp->target == target) {
Craig Tiller1d881fb2015-12-01 07:39:04 -0800135 grpc_pollset_set_del_pollset(exec_ctx, &p->base.interested_parties,
136 pp->pollset);
Craig Tiller577c9b22015-11-02 14:11:15 -0800137 *target = NULL;
138 grpc_exec_ctx_enqueue(exec_ctx, pp->on_complete, 0);
139 gpr_free(pp);
140 } else {
141 pp->next = p->pending_picks;
142 p->pending_picks = pp;
143 }
144 pp = next;
145 }
146 gpr_mu_unlock(&p->mu);
147}
148
Craig Tillera82950e2015-09-22 12:33:20 -0700149static void start_picking(grpc_exec_ctx *exec_ctx, pick_first_lb_policy *p) {
Craig Tiller48cb07c2015-07-15 16:16:15 -0700150 p->started_picking = 1;
151 p->checking_subchannel = 0;
152 p->checking_connectivity = GRPC_CHANNEL_IDLE;
Craig Tiller48613042015-11-29 14:45:11 -0800153 GRPC_LB_POLICY_WEAK_REF(&p->base, "pick_first_connectivity");
Craig Tillera82950e2015-09-22 12:33:20 -0700154 grpc_subchannel_notify_on_state_change(
155 exec_ctx, p->subchannels[p->checking_subchannel],
Craig Tiller1d881fb2015-12-01 07:39:04 -0800156 &p->base.interested_parties, &p->checking_connectivity,
157 &p->connectivity_changed);
Craig Tiller48cb07c2015-07-15 16:16:15 -0700158}
159
Craig Tillera82950e2015-09-22 12:33:20 -0700160void pf_exit_idle(grpc_exec_ctx *exec_ctx, grpc_lb_policy *pol) {
161 pick_first_lb_policy *p = (pick_first_lb_policy *)pol;
162 gpr_mu_lock(&p->mu);
163 if (!p->started_picking) {
164 start_picking(exec_ctx, p);
165 }
166 gpr_mu_unlock(&p->mu);
Craig Tillereb3b12e2015-06-26 14:42:49 -0700167}
168
Craig Tiller577c9b22015-11-02 14:11:15 -0800169int pf_pick(grpc_exec_ctx *exec_ctx, grpc_lb_policy *pol, grpc_pollset *pollset,
Craig Tillerab33b482015-11-21 08:11:04 -0800170 grpc_metadata_batch *initial_metadata,
171 grpc_connected_subchannel **target, grpc_closure *on_complete) {
Craig Tillera82950e2015-09-22 12:33:20 -0700172 pick_first_lb_policy *p = (pick_first_lb_policy *)pol;
Craig Tiller45724b32015-09-22 10:42:19 -0700173 pending_pick *pp;
Craig Tillera82950e2015-09-22 12:33:20 -0700174 gpr_mu_lock(&p->mu);
175 if (p->selected) {
176 gpr_mu_unlock(&p->mu);
177 *target = p->selected;
Craig Tiller577c9b22015-11-02 14:11:15 -0800178 return 1;
Craig Tillera82950e2015-09-22 12:33:20 -0700179 } else {
180 if (!p->started_picking) {
181 start_picking(exec_ctx, p);
Craig Tiller45724b32015-09-22 10:42:19 -0700182 }
Craig Tiller1d881fb2015-12-01 07:39:04 -0800183 grpc_pollset_set_add_pollset(exec_ctx, &p->base.interested_parties,
184 pollset);
Craig Tillera82950e2015-09-22 12:33:20 -0700185 pp = gpr_malloc(sizeof(*pp));
186 pp->next = p->pending_picks;
187 pp->pollset = pollset;
188 pp->target = target;
189 pp->on_complete = on_complete;
190 p->pending_picks = pp;
191 gpr_mu_unlock(&p->mu);
Craig Tiller577c9b22015-11-02 14:11:15 -0800192 return 0;
Craig Tillera82950e2015-09-22 12:33:20 -0700193 }
Craig Tiller45724b32015-09-22 10:42:19 -0700194}
195
Craig Tiller1f41b6b2015-10-09 15:07:02 -0700196static void destroy_subchannels(grpc_exec_ctx *exec_ctx, void *arg,
Craig Tillerb09d84d2015-10-06 09:12:16 -0700197 int iomgr_success) {
198 pick_first_lb_policy *p = arg;
199 size_t i;
Craig Tillerb09d84d2015-10-06 09:12:16 -0700200 size_t num_subchannels = p->num_subchannels;
201 grpc_subchannel **subchannels;
Craig Tillerb09d84d2015-10-06 09:12:16 -0700202
203 gpr_mu_lock(&p->mu);
204 subchannels = p->subchannels;
Craig Tillerb09d84d2015-10-06 09:12:16 -0700205 p->num_subchannels = 0;
206 p->subchannels = NULL;
207 gpr_mu_unlock(&p->mu);
Craig Tiller48613042015-11-29 14:45:11 -0800208 GRPC_LB_POLICY_WEAK_UNREF(exec_ctx, &p->base, "destroy_subchannels");
Craig Tillerb09d84d2015-10-06 09:12:16 -0700209
210 for (i = 0; i < num_subchannels; i++) {
Craig Tillerb09d84d2015-10-06 09:12:16 -0700211 GRPC_SUBCHANNEL_UNREF(exec_ctx, subchannels[i], "pick_first");
212 }
213
214 gpr_free(subchannels);
215}
216
Craig Tillera82950e2015-09-22 12:33:20 -0700217static void pf_connectivity_changed(grpc_exec_ctx *exec_ctx, void *arg,
218 int iomgr_success) {
Craig Tillereb3b12e2015-06-26 14:42:49 -0700219 pick_first_lb_policy *p = arg;
Craig Tillerb5585d42015-11-17 07:18:31 -0800220 grpc_subchannel *selected_subchannel;
Craig Tillereb3b12e2015-06-26 14:42:49 -0700221 pending_pick *pp;
Craig Tillereb3b12e2015-06-26 14:42:49 -0700222
Craig Tillera82950e2015-09-22 12:33:20 -0700223 gpr_mu_lock(&p->mu);
Craig Tiller1ada6ad2015-07-16 16:19:14 -0700224
Craig Tillera82950e2015-09-22 12:33:20 -0700225 if (p->shutdown) {
226 gpr_mu_unlock(&p->mu);
Craig Tiller48613042015-11-29 14:45:11 -0800227 GRPC_LB_POLICY_WEAK_UNREF(exec_ctx, &p->base, "pick_first_connectivity");
Craig Tillera82950e2015-09-22 12:33:20 -0700228 return;
229 } else if (p->selected != NULL) {
Craig Tillercb2609f2015-11-24 17:19:19 -0800230 if (p->checking_connectivity == GRPC_CHANNEL_TRANSIENT_FAILURE) {
231 /* if the selected channel goes bad, we're done */
232 p->checking_connectivity = GRPC_CHANNEL_FATAL_FAILURE;
233 }
Craig Tillera82950e2015-09-22 12:33:20 -0700234 grpc_connectivity_state_set(exec_ctx, &p->state_tracker,
235 p->checking_connectivity, "selected_changed");
236 if (p->checking_connectivity != GRPC_CHANNEL_FATAL_FAILURE) {
Craig Tillerab33b482015-11-21 08:11:04 -0800237 grpc_connected_subchannel_notify_on_state_change(
Craig Tillera6bebf42015-12-01 17:02:35 -0800238 exec_ctx, p->selected, &p->base.interested_parties,
239 &p->checking_connectivity, &p->connectivity_changed);
Craig Tillera82950e2015-09-22 12:33:20 -0700240 } else {
Craig Tiller48613042015-11-29 14:45:11 -0800241 GRPC_LB_POLICY_WEAK_UNREF(exec_ctx, &p->base, "pick_first_connectivity");
Craig Tiller1ada6ad2015-07-16 16:19:14 -0700242 }
Craig Tillera82950e2015-09-22 12:33:20 -0700243 } else {
244 loop:
245 switch (p->checking_connectivity) {
246 case GRPC_CHANNEL_READY:
247 grpc_connectivity_state_set(exec_ctx, &p->state_tracker,
248 GRPC_CHANNEL_READY, "connecting_ready");
Craig Tillerb5585d42015-11-17 07:18:31 -0800249 selected_subchannel = p->subchannels[p->checking_subchannel];
Craig Tillerab33b482015-11-21 08:11:04 -0800250 p->selected =
251 grpc_subchannel_get_connected_subchannel(selected_subchannel);
Craig Tillerb5585d42015-11-17 07:18:31 -0800252 GPR_ASSERT(p->selected);
253 GRPC_CONNECTED_SUBCHANNEL_REF(p->selected, "picked_first");
Craig Tillerb09d84d2015-10-06 09:12:16 -0700254 /* drop the pick list: we are connected now */
Craig Tiller48613042015-11-29 14:45:11 -0800255 GRPC_LB_POLICY_WEAK_REF(&p->base, "destroy_subchannels");
Craig Tiller1f41b6b2015-10-09 15:07:02 -0700256 grpc_exec_ctx_enqueue(exec_ctx,
257 grpc_closure_create(destroy_subchannels, p), 1);
Craig Tillerb09d84d2015-10-06 09:12:16 -0700258 /* update any calls that were waiting for a pick */
Craig Tillera82950e2015-09-22 12:33:20 -0700259 while ((pp = p->pending_picks)) {
260 p->pending_picks = pp->next;
261 *pp->target = p->selected;
Craig Tiller1d881fb2015-12-01 07:39:04 -0800262 grpc_pollset_set_del_pollset(exec_ctx, &p->base.interested_parties,
263 pp->pollset);
Craig Tillera82950e2015-09-22 12:33:20 -0700264 grpc_exec_ctx_enqueue(exec_ctx, pp->on_complete, 1);
265 gpr_free(pp);
266 }
Craig Tillerab33b482015-11-21 08:11:04 -0800267 grpc_connected_subchannel_notify_on_state_change(
Craig Tillera6bebf42015-12-01 17:02:35 -0800268 exec_ctx, p->selected, &p->base.interested_parties,
269 &p->checking_connectivity, &p->connectivity_changed);
Craig Tillera82950e2015-09-22 12:33:20 -0700270 break;
271 case GRPC_CHANNEL_TRANSIENT_FAILURE:
272 grpc_connectivity_state_set(exec_ctx, &p->state_tracker,
273 GRPC_CHANNEL_TRANSIENT_FAILURE,
274 "connecting_transient_failure");
Craig Tillera82950e2015-09-22 12:33:20 -0700275 p->checking_subchannel =
276 (p->checking_subchannel + 1) % p->num_subchannels;
277 p->checking_connectivity = grpc_subchannel_check_connectivity(
278 p->subchannels[p->checking_subchannel]);
Craig Tillera82950e2015-09-22 12:33:20 -0700279 if (p->checking_connectivity == GRPC_CHANNEL_TRANSIENT_FAILURE) {
280 grpc_subchannel_notify_on_state_change(
281 exec_ctx, p->subchannels[p->checking_subchannel],
Craig Tiller1d881fb2015-12-01 07:39:04 -0800282 &p->base.interested_parties, &p->checking_connectivity,
283 &p->connectivity_changed);
Craig Tillera82950e2015-09-22 12:33:20 -0700284 } else {
285 goto loop;
286 }
287 break;
288 case GRPC_CHANNEL_CONNECTING:
289 case GRPC_CHANNEL_IDLE:
290 grpc_connectivity_state_set(exec_ctx, &p->state_tracker,
291 GRPC_CHANNEL_CONNECTING,
292 "connecting_changed");
293 grpc_subchannel_notify_on_state_change(
294 exec_ctx, p->subchannels[p->checking_subchannel],
Craig Tiller1d881fb2015-12-01 07:39:04 -0800295 &p->base.interested_parties, &p->checking_connectivity,
296 &p->connectivity_changed);
Craig Tillera82950e2015-09-22 12:33:20 -0700297 break;
298 case GRPC_CHANNEL_FATAL_FAILURE:
Craig Tillera82950e2015-09-22 12:33:20 -0700299 p->num_subchannels--;
Craig Tiller86c99582015-11-25 15:22:26 -0800300 GPR_SWAP(grpc_subchannel *, p->subchannels[p->checking_subchannel],
301 p->subchannels[p->num_subchannels]);
Craig Tillera82950e2015-09-22 12:33:20 -0700302 GRPC_SUBCHANNEL_UNREF(exec_ctx, p->subchannels[p->num_subchannels],
303 "pick_first");
304 if (p->num_subchannels == 0) {
305 grpc_connectivity_state_set(exec_ctx, &p->state_tracker,
306 GRPC_CHANNEL_FATAL_FAILURE,
307 "no_more_channels");
308 while ((pp = p->pending_picks)) {
309 p->pending_picks = pp->next;
310 *pp->target = NULL;
311 grpc_exec_ctx_enqueue(exec_ctx, pp->on_complete, 1);
312 gpr_free(pp);
313 }
Craig Tiller1d881fb2015-12-01 07:39:04 -0800314 GRPC_LB_POLICY_WEAK_UNREF(exec_ctx, &p->base,
315 "pick_first_connectivity");
Craig Tillera82950e2015-09-22 12:33:20 -0700316 } else {
317 grpc_connectivity_state_set(exec_ctx, &p->state_tracker,
318 GRPC_CHANNEL_TRANSIENT_FAILURE,
319 "subchannel_failed");
320 p->checking_subchannel %= p->num_subchannels;
321 p->checking_connectivity = grpc_subchannel_check_connectivity(
322 p->subchannels[p->checking_subchannel]);
Craig Tillera82950e2015-09-22 12:33:20 -0700323 goto loop;
324 }
Craig Tiller1ada6ad2015-07-16 16:19:14 -0700325 }
Craig Tillera82950e2015-09-22 12:33:20 -0700326 }
Craig Tiller1ada6ad2015-07-16 16:19:14 -0700327
Craig Tillera82950e2015-09-22 12:33:20 -0700328 gpr_mu_unlock(&p->mu);
Craig Tillereb3b12e2015-06-26 14:42:49 -0700329}
330
Craig Tillera82950e2015-09-22 12:33:20 -0700331static grpc_connectivity_state pf_check_connectivity(grpc_exec_ctx *exec_ctx,
332 grpc_lb_policy *pol) {
333 pick_first_lb_policy *p = (pick_first_lb_policy *)pol;
Craig Tillerc7b5f762015-06-27 11:48:42 -0700334 grpc_connectivity_state st;
Craig Tillera82950e2015-09-22 12:33:20 -0700335 gpr_mu_lock(&p->mu);
336 st = grpc_connectivity_state_check(&p->state_tracker);
337 gpr_mu_unlock(&p->mu);
Craig Tillerc7b5f762015-06-27 11:48:42 -0700338 return st;
339}
340
Craig Tillera82950e2015-09-22 12:33:20 -0700341void pf_notify_on_state_change(grpc_exec_ctx *exec_ctx, grpc_lb_policy *pol,
342 grpc_connectivity_state *current,
343 grpc_closure *notify) {
344 pick_first_lb_policy *p = (pick_first_lb_policy *)pol;
345 gpr_mu_lock(&p->mu);
346 grpc_connectivity_state_notify_on_state_change(exec_ctx, &p->state_tracker,
347 current, notify);
348 gpr_mu_unlock(&p->mu);
Craig Tillerc7b5f762015-06-27 11:48:42 -0700349}
350
Craig Tiller28bf8912015-12-07 16:07:04 -0800351void pf_ping_one(grpc_exec_ctx *exec_ctx, grpc_lb_policy *pol, grpc_closure *closure) {
352 pick_first_lb_policy *p = (pick_first_lb_policy *)pol;
353 gpr_mu_lock(&p->mu);
354 if (p->selected) {
355 grpc_connected_subchannel_ping(exec_ctx, p->selected, closure);
356 } else {
357 grpc_exec_ctx_enqueue(exec_ctx, closure, 0);
358 }
359 gpr_mu_unlock(&p->mu);
360}
361
Craig Tillereb3b12e2015-06-26 14:42:49 -0700362static const grpc_lb_policy_vtable pick_first_lb_policy_vtable = {
Craig Tiller26dab312015-12-07 14:43:47 -0800363 pf_destroy, pf_shutdown, pf_pick, pf_cancel_pick, pf_ping_one, pf_exit_idle,
Craig Tiller50ec2672015-11-27 21:45:11 -0800364 pf_check_connectivity, pf_notify_on_state_change};
Craig Tillereb3b12e2015-06-26 14:42:49 -0700365
Craig Tillera82950e2015-09-22 12:33:20 -0700366static void pick_first_factory_ref(grpc_lb_policy_factory *factory) {}
David Garcia Quintas5c4543d2015-09-03 15:49:56 -0700367
Craig Tillera82950e2015-09-22 12:33:20 -0700368static void pick_first_factory_unref(grpc_lb_policy_factory *factory) {}
David Garcia Quintas5c4543d2015-09-03 15:49:56 -0700369
Craig Tillera82950e2015-09-22 12:33:20 -0700370static grpc_lb_policy *create_pick_first(grpc_lb_policy_factory *factory,
371 grpc_lb_policy_args *args) {
372 pick_first_lb_policy *p = gpr_malloc(sizeof(*p));
373 GPR_ASSERT(args->num_subchannels > 0);
374 memset(p, 0, sizeof(*p));
375 grpc_lb_policy_init(&p->base, &pick_first_lb_policy_vtable);
376 p->subchannels =
377 gpr_malloc(sizeof(grpc_subchannel *) * args->num_subchannels);
David Garcia Quintasc7705c72015-09-09 17:21:11 -0700378 p->num_subchannels = args->num_subchannels;
Craig Tillera82950e2015-09-22 12:33:20 -0700379 grpc_connectivity_state_init(&p->state_tracker, GRPC_CHANNEL_IDLE,
380 "pick_first");
381 memcpy(p->subchannels, args->subchannels,
382 sizeof(grpc_subchannel *) * args->num_subchannels);
383 grpc_closure_init(&p->connectivity_changed, pf_connectivity_changed, p);
384 gpr_mu_init(&p->mu);
Craig Tillereb3b12e2015-06-26 14:42:49 -0700385 return &p->base;
386}
David Garcia Quintas5c4543d2015-09-03 15:49:56 -0700387
388static const grpc_lb_policy_factory_vtable pick_first_factory_vtable = {
Craig Tillera82950e2015-09-22 12:33:20 -0700389 pick_first_factory_ref, pick_first_factory_unref, create_pick_first,
390 "pick_first"};
David Garcia Quintas5c4543d2015-09-03 15:49:56 -0700391
392static grpc_lb_policy_factory pick_first_lb_policy_factory = {
Craig Tillera82950e2015-09-22 12:33:20 -0700393 &pick_first_factory_vtable};
David Garcia Quintas5c4543d2015-09-03 15:49:56 -0700394
Craig Tillera82950e2015-09-22 12:33:20 -0700395grpc_lb_policy_factory *grpc_pick_first_lb_factory_create() {
David Garcia Quintas5c4543d2015-09-03 15:49:56 -0700396 return &pick_first_lb_policy_factory;
397}