blob: d95f0310b62237210965f621b96ba402fd6d6413 [file] [log] [blame]
Craig Tiller3bc8ebd2015-06-24 15:41:15 -07001/*
2 *
Craig Tiller6169d5f2016-03-31 07:46:18 -07003 * Copyright 2015, Google Inc.
Craig Tiller3bc8ebd2015-06-24 15:41:15 -07004 * 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
Craig Tillereb3b12e2015-06-26 14:42:49 -070034#include <string.h>
35
36#include <grpc/support/alloc.h>
Mark D. Roth5bd7be02016-10-21 14:19:50 -070037
Craig Tillerd4c98332016-03-31 13:45:47 -070038#include "src/core/ext/client_config/lb_policy_registry.h"
Mark D. Roth5bd7be02016-10-21 14:19:50 -070039#include "src/core/lib/channel/channel_args.h"
Craig Tiller9533d042016-03-25 17:11:06 -070040#include "src/core/lib/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;
Craig Tiller8c0d96f2016-03-11 14:27:52 -080044 uint32_t initial_metadata_flags;
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
Craig Tiller86c0f8a2015-12-01 20:05:40 -080058 /** the selected channel (a grpc_connected_subchannel) */
59 gpr_atm selected;
Craig Tiller320bee02016-01-06 17:33:45 -080060
61 /** mutex protecting remaining members */
62 gpr_mu mu;
Craig Tillereb3b12e2015-06-26 14:42:49 -070063 /** have we started picking? */
64 int started_picking;
Craig Tillera14215a2015-07-17 17:21:08 -070065 /** are we shut down? */
66 int shutdown;
Craig Tillereb3b12e2015-06-26 14:42:49 -070067 /** which subchannel are we watching? */
68 size_t checking_subchannel;
69 /** what is the connectivity of that channel? */
70 grpc_connectivity_state checking_connectivity;
71 /** list of picks that are waiting on connectivity */
72 pending_pick *pending_picks;
Craig Tillerc7b5f762015-06-27 11:48:42 -070073
74 /** our connectivity state tracker */
75 grpc_connectivity_state_tracker state_tracker;
Craig Tillereb3b12e2015-06-26 14:42:49 -070076} pick_first_lb_policy;
77
Craig Tiller81afdda2016-01-11 17:09:18 -080078#define GET_SELECTED(p) \
Craig Tillerd9d474a2016-01-26 06:50:51 -080079 ((grpc_connected_subchannel *)gpr_atm_acq_load(&(p)->selected))
Craig Tiller86c0f8a2015-12-01 20:05:40 -080080
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 Tiller86c0f8a2015-12-01 20:05:40 -080083 grpc_connected_subchannel *selected = GET_SELECTED(p);
Craig Tillerd7b68e72015-06-28 11:41:09 -070084 size_t i;
Craig Tillera82950e2015-09-22 12:33:20 -070085 GPR_ASSERT(p->pending_picks == NULL);
86 for (i = 0; i < p->num_subchannels; i++) {
87 GRPC_SUBCHANNEL_UNREF(exec_ctx, p->subchannels[i], "pick_first");
88 }
Craig Tiller86c0f8a2015-12-01 20:05:40 -080089 if (selected != NULL) {
90 GRPC_CONNECTED_SUBCHANNEL_UNREF(exec_ctx, selected, "picked_first");
Craig Tiller89a768e2015-10-06 09:55:59 -070091 }
Craig Tillera82950e2015-09-22 12:33:20 -070092 grpc_connectivity_state_destroy(exec_ctx, &p->state_tracker);
93 gpr_free(p->subchannels);
94 gpr_mu_destroy(&p->mu);
95 gpr_free(p);
Craig Tillereb3b12e2015-06-26 14:42:49 -070096}
97
Craig Tillerfb433852016-03-29 08:51:07 -070098static void pf_shutdown(grpc_exec_ctx *exec_ctx, grpc_lb_policy *pol) {
Craig Tillera82950e2015-09-22 12:33:20 -070099 pick_first_lb_policy *p = (pick_first_lb_policy *)pol;
Craig Tillerd2cc4592015-07-01 07:50:47 -0700100 pending_pick *pp;
Craig Tiller86c0f8a2015-12-01 20:05:40 -0800101 grpc_connected_subchannel *selected;
Craig Tillera82950e2015-09-22 12:33:20 -0700102 gpr_mu_lock(&p->mu);
Craig Tiller86c0f8a2015-12-01 20:05:40 -0800103 selected = GET_SELECTED(p);
Craig Tillera14215a2015-07-17 17:21:08 -0700104 p->shutdown = 1;
Craig Tiller5795da72015-09-17 15:27:13 -0700105 pp = p->pending_picks;
106 p->pending_picks = NULL;
Craig Tiller804ff712016-05-05 16:25:40 -0700107 grpc_connectivity_state_set(
Craig Tillerd925c932016-06-06 08:38:50 -0700108 exec_ctx, &p->state_tracker, GRPC_CHANNEL_SHUTDOWN,
Craig Tiller804ff712016-05-05 16:25:40 -0700109 GRPC_ERROR_CREATE("Channel shutdown"), "shutdown");
Craig Tillerf036a642015-12-01 17:00:40 -0800110 /* cancel subscription */
Craig Tiller86c0f8a2015-12-01 20:05:40 -0800111 if (selected != NULL) {
Craig Tiller1d881fb2015-12-01 07:39:04 -0800112 grpc_connected_subchannel_notify_on_state_change(
Craig Tiller86c0f8a2015-12-01 20:05:40 -0800113 exec_ctx, selected, NULL, NULL, &p->connectivity_changed);
Craig Tillere2b86c72016-04-14 17:34:01 -0700114 } else if (p->num_subchannels > 0) {
Craig Tiller1d881fb2015-12-01 07:39:04 -0800115 grpc_subchannel_notify_on_state_change(
116 exec_ctx, p->subchannels[p->checking_subchannel], NULL, NULL,
117 &p->connectivity_changed);
Craig Tiller48613042015-11-29 14:45:11 -0800118 }
Craig Tillera82950e2015-09-22 12:33:20 -0700119 gpr_mu_unlock(&p->mu);
120 while (pp != NULL) {
121 pending_pick *next = pp->next;
122 *pp->target = NULL;
Craig Tiller332f1b32016-05-24 13:21:21 -0700123 grpc_exec_ctx_sched(exec_ctx, pp->on_complete, GRPC_ERROR_NONE, NULL);
Craig Tillera82950e2015-09-22 12:33:20 -0700124 gpr_free(pp);
125 pp = next;
126 }
Craig Tillereb3b12e2015-06-26 14:42:49 -0700127}
128
Craig Tiller577c9b22015-11-02 14:11:15 -0800129static void pf_cancel_pick(grpc_exec_ctx *exec_ctx, grpc_lb_policy *pol,
Mark D. Roth5f844002016-09-08 08:20:53 -0700130 grpc_connected_subchannel **target,
131 grpc_error *error) {
Craig Tiller577c9b22015-11-02 14:11:15 -0800132 pick_first_lb_policy *p = (pick_first_lb_policy *)pol;
133 pending_pick *pp;
134 gpr_mu_lock(&p->mu);
135 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;
Mark D. Roth932b10c2016-09-09 08:44:30 -0700141 grpc_exec_ctx_sched(
142 exec_ctx, pp->on_complete,
143 GRPC_ERROR_CREATE_REFERENCING("Pick Cancelled", &error, 1), NULL);
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 }
151 gpr_mu_unlock(&p->mu);
Mark D. Roth5f844002016-09-08 08:20:53 -0700152 GRPC_ERROR_UNREF(error);
Craig Tiller577c9b22015-11-02 14:11:15 -0800153}
154
Craig Tiller8c0d96f2016-03-11 14:27:52 -0800155static void pf_cancel_picks(grpc_exec_ctx *exec_ctx, grpc_lb_policy *pol,
156 uint32_t initial_metadata_flags_mask,
Mark D. Rothe65ff112016-09-09 13:48:38 -0700157 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;
161 gpr_mu_lock(&p->mu);
162 pp = p->pending_picks;
163 p->pending_picks = NULL;
164 while (pp != NULL) {
165 pending_pick *next = pp->next;
166 if ((pp->initial_metadata_flags & initial_metadata_flags_mask) ==
167 initial_metadata_flags_eq) {
Mark D. Roth58f52b72016-09-09 13:55:18 -0700168 grpc_exec_ctx_sched(
169 exec_ctx, pp->on_complete,
170 GRPC_ERROR_CREATE_REFERENCING("Pick Cancelled", &error, 1), NULL);
Craig Tiller8c0d96f2016-03-11 14:27:52 -0800171 gpr_free(pp);
172 } else {
173 pp->next = p->pending_picks;
174 p->pending_picks = pp;
175 }
176 pp = next;
177 }
178 gpr_mu_unlock(&p->mu);
Mark D. Rothe65ff112016-09-09 13:48:38 -0700179 GRPC_ERROR_UNREF(error);
Craig Tiller8c0d96f2016-03-11 14:27:52 -0800180}
181
Craig Tillera82950e2015-09-22 12:33:20 -0700182static void start_picking(grpc_exec_ctx *exec_ctx, pick_first_lb_policy *p) {
Craig Tiller48cb07c2015-07-15 16:16:15 -0700183 p->started_picking = 1;
184 p->checking_subchannel = 0;
185 p->checking_connectivity = GRPC_CHANNEL_IDLE;
Craig Tiller48613042015-11-29 14:45:11 -0800186 GRPC_LB_POLICY_WEAK_REF(&p->base, "pick_first_connectivity");
Craig Tillera82950e2015-09-22 12:33:20 -0700187 grpc_subchannel_notify_on_state_change(
188 exec_ctx, p->subchannels[p->checking_subchannel],
Craig Tiller69b093b2016-02-25 19:04:07 -0800189 p->base.interested_parties, &p->checking_connectivity,
Craig Tiller1d881fb2015-12-01 07:39:04 -0800190 &p->connectivity_changed);
Craig Tiller48cb07c2015-07-15 16:16:15 -0700191}
192
Craig Tillerfb433852016-03-29 08:51:07 -0700193static void pf_exit_idle(grpc_exec_ctx *exec_ctx, grpc_lb_policy *pol) {
Craig Tillera82950e2015-09-22 12:33:20 -0700194 pick_first_lb_policy *p = (pick_first_lb_policy *)pol;
195 gpr_mu_lock(&p->mu);
196 if (!p->started_picking) {
197 start_picking(exec_ctx, p);
198 }
199 gpr_mu_unlock(&p->mu);
Craig Tillereb3b12e2015-06-26 14:42:49 -0700200}
201
Craig Tillerfb433852016-03-29 08:51:07 -0700202static int pf_pick(grpc_exec_ctx *exec_ctx, grpc_lb_policy *pol,
David Garcia Quintas8aace512016-08-15 14:55:12 -0700203 const grpc_lb_policy_pick_args *pick_args,
David Garcia Quintas331b9c02016-09-12 18:37:05 -0700204 grpc_connected_subchannel **target, void **user_data,
Craig Tillerfb433852016-03-29 08:51:07 -0700205 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 Tiller86c0f8a2015-12-01 20:05:40 -0800210 grpc_connected_subchannel *selected = GET_SELECTED(p);
211 if (selected != NULL) {
212 *target = selected;
213 return 1;
214 }
Craig Tiller320bee02016-01-06 17:33:45 -0800215
216 /* No subchannel selected yet, so acquire lock and then attempt again */
Craig Tillera82950e2015-09-22 12:33:20 -0700217 gpr_mu_lock(&p->mu);
Craig Tiller86c0f8a2015-12-01 20:05:40 -0800218 selected = GET_SELECTED(p);
219 if (selected) {
Craig Tillera82950e2015-09-22 12:33:20 -0700220 gpr_mu_unlock(&p->mu);
Craig Tiller86c0f8a2015-12-01 20:05:40 -0800221 *target = selected;
Craig Tiller577c9b22015-11-02 14:11:15 -0800222 return 1;
Craig Tillera82950e2015-09-22 12:33:20 -0700223 } else {
224 if (!p->started_picking) {
225 start_picking(exec_ctx, p);
Craig Tiller45724b32015-09-22 10:42:19 -0700226 }
Craig Tillera82950e2015-09-22 12:33:20 -0700227 pp = gpr_malloc(sizeof(*pp));
228 pp->next = p->pending_picks;
Craig Tillera82950e2015-09-22 12:33:20 -0700229 pp->target = target;
David Garcia Quintas8aace512016-08-15 14:55:12 -0700230 pp->initial_metadata_flags = pick_args->initial_metadata_flags;
Craig Tillera82950e2015-09-22 12:33:20 -0700231 pp->on_complete = on_complete;
232 p->pending_picks = pp;
233 gpr_mu_unlock(&p->mu);
Craig Tiller577c9b22015-11-02 14:11:15 -0800234 return 0;
Craig Tillera82950e2015-09-22 12:33:20 -0700235 }
Craig Tiller45724b32015-09-22 10:42:19 -0700236}
237
Craig Tiller1f41b6b2015-10-09 15:07:02 -0700238static void destroy_subchannels(grpc_exec_ctx *exec_ctx, void *arg,
Craig Tiller804ff712016-05-05 16:25:40 -0700239 grpc_error *error) {
Craig Tillerb09d84d2015-10-06 09:12:16 -0700240 pick_first_lb_policy *p = arg;
241 size_t i;
Craig Tillerb09d84d2015-10-06 09:12:16 -0700242 size_t num_subchannels = p->num_subchannels;
243 grpc_subchannel **subchannels;
Craig Tillerb09d84d2015-10-06 09:12:16 -0700244
245 gpr_mu_lock(&p->mu);
246 subchannels = p->subchannels;
Craig Tillerb09d84d2015-10-06 09:12:16 -0700247 p->num_subchannels = 0;
248 p->subchannels = NULL;
249 gpr_mu_unlock(&p->mu);
Craig Tiller48613042015-11-29 14:45:11 -0800250 GRPC_LB_POLICY_WEAK_UNREF(exec_ctx, &p->base, "destroy_subchannels");
Craig Tillerb09d84d2015-10-06 09:12:16 -0700251
252 for (i = 0; i < num_subchannels; i++) {
Craig Tillerb09d84d2015-10-06 09:12:16 -0700253 GRPC_SUBCHANNEL_UNREF(exec_ctx, subchannels[i], "pick_first");
254 }
255
256 gpr_free(subchannels);
257}
258
Craig Tillera82950e2015-09-22 12:33:20 -0700259static void pf_connectivity_changed(grpc_exec_ctx *exec_ctx, void *arg,
Craig Tiller804ff712016-05-05 16:25:40 -0700260 grpc_error *error) {
Craig Tillereb3b12e2015-06-26 14:42:49 -0700261 pick_first_lb_policy *p = arg;
Craig Tillerb5585d42015-11-17 07:18:31 -0800262 grpc_subchannel *selected_subchannel;
Craig Tillereb3b12e2015-06-26 14:42:49 -0700263 pending_pick *pp;
Craig Tiller86c0f8a2015-12-01 20:05:40 -0800264 grpc_connected_subchannel *selected;
Craig Tillereb3b12e2015-06-26 14:42:49 -0700265
Craig Tillerf707d622016-05-06 14:26:12 -0700266 GRPC_ERROR_REF(error);
Craig Tiller804ff712016-05-05 16:25:40 -0700267
Craig Tillera82950e2015-09-22 12:33:20 -0700268 gpr_mu_lock(&p->mu);
Craig Tiller1ada6ad2015-07-16 16:19:14 -0700269
Craig Tiller86c0f8a2015-12-01 20:05:40 -0800270 selected = GET_SELECTED(p);
271
Craig Tillera82950e2015-09-22 12:33:20 -0700272 if (p->shutdown) {
273 gpr_mu_unlock(&p->mu);
Craig Tiller48613042015-11-29 14:45:11 -0800274 GRPC_LB_POLICY_WEAK_UNREF(exec_ctx, &p->base, "pick_first_connectivity");
Craig Tillerae125932016-05-13 16:34:29 -0700275 GRPC_ERROR_UNREF(error);
Craig Tillera82950e2015-09-22 12:33:20 -0700276 return;
Craig Tiller86c0f8a2015-12-01 20:05:40 -0800277 } else if (selected != NULL) {
Craig Tillercb2609f2015-11-24 17:19:19 -0800278 if (p->checking_connectivity == GRPC_CHANNEL_TRANSIENT_FAILURE) {
279 /* if the selected channel goes bad, we're done */
Craig Tiller48ed92e2016-06-02 11:07:12 -0700280 p->checking_connectivity = GRPC_CHANNEL_SHUTDOWN;
Craig Tillercb2609f2015-11-24 17:19:19 -0800281 }
Craig Tillera82950e2015-09-22 12:33:20 -0700282 grpc_connectivity_state_set(exec_ctx, &p->state_tracker,
Craig Tillerf707d622016-05-06 14:26:12 -0700283 p->checking_connectivity, GRPC_ERROR_REF(error),
Craig Tiller804ff712016-05-05 16:25:40 -0700284 "selected_changed");
Craig Tiller48ed92e2016-06-02 11:07:12 -0700285 if (p->checking_connectivity != GRPC_CHANNEL_SHUTDOWN) {
Craig Tillerab33b482015-11-21 08:11:04 -0800286 grpc_connected_subchannel_notify_on_state_change(
Craig Tiller69b093b2016-02-25 19:04:07 -0800287 exec_ctx, selected, p->base.interested_parties,
Craig Tillera6bebf42015-12-01 17:02:35 -0800288 &p->checking_connectivity, &p->connectivity_changed);
Craig Tillera82950e2015-09-22 12:33:20 -0700289 } else {
Craig Tiller48613042015-11-29 14:45:11 -0800290 GRPC_LB_POLICY_WEAK_UNREF(exec_ctx, &p->base, "pick_first_connectivity");
Craig Tiller1ada6ad2015-07-16 16:19:14 -0700291 }
Craig Tillera82950e2015-09-22 12:33:20 -0700292 } else {
293 loop:
294 switch (p->checking_connectivity) {
295 case GRPC_CHANNEL_READY:
296 grpc_connectivity_state_set(exec_ctx, &p->state_tracker,
Craig Tiller804ff712016-05-05 16:25:40 -0700297 GRPC_CHANNEL_READY, GRPC_ERROR_NONE,
298 "connecting_ready");
Craig Tillerb5585d42015-11-17 07:18:31 -0800299 selected_subchannel = p->subchannels[p->checking_subchannel];
Craig Tiller81afdda2016-01-11 17:09:18 -0800300 selected =
301 grpc_subchannel_get_connected_subchannel(selected_subchannel);
Craig Tiller86c0f8a2015-12-01 20:05:40 -0800302 GPR_ASSERT(selected != NULL);
Craig Tiller86c0f8a2015-12-01 20:05:40 -0800303 GRPC_CONNECTED_SUBCHANNEL_REF(selected, "picked_first");
Craig Tillerb09d84d2015-10-06 09:12:16 -0700304 /* drop the pick list: we are connected now */
Craig Tiller48613042015-11-29 14:45:11 -0800305 GRPC_LB_POLICY_WEAK_REF(&p->base, "destroy_subchannels");
Craig Tillerd9d474a2016-01-26 06:50:51 -0800306 gpr_atm_rel_store(&p->selected, (gpr_atm)selected);
Craig Tiller332f1b32016-05-24 13:21:21 -0700307 grpc_exec_ctx_sched(exec_ctx,
308 grpc_closure_create(destroy_subchannels, p),
309 GRPC_ERROR_NONE, NULL);
Craig Tillerb09d84d2015-10-06 09:12:16 -0700310 /* update any calls that were waiting for a pick */
Craig Tillera82950e2015-09-22 12:33:20 -0700311 while ((pp = p->pending_picks)) {
312 p->pending_picks = pp->next;
Craig Tiller86c0f8a2015-12-01 20:05:40 -0800313 *pp->target = selected;
Craig Tiller332f1b32016-05-24 13:21:21 -0700314 grpc_exec_ctx_sched(exec_ctx, pp->on_complete, GRPC_ERROR_NONE, NULL);
Craig Tillera82950e2015-09-22 12:33:20 -0700315 gpr_free(pp);
316 }
Craig Tillerab33b482015-11-21 08:11:04 -0800317 grpc_connected_subchannel_notify_on_state_change(
Craig Tiller69b093b2016-02-25 19:04:07 -0800318 exec_ctx, selected, p->base.interested_parties,
Craig Tillera6bebf42015-12-01 17:02:35 -0800319 &p->checking_connectivity, &p->connectivity_changed);
Craig Tillera82950e2015-09-22 12:33:20 -0700320 break;
321 case GRPC_CHANNEL_TRANSIENT_FAILURE:
Craig Tillera82950e2015-09-22 12:33:20 -0700322 p->checking_subchannel =
323 (p->checking_subchannel + 1) % p->num_subchannels;
Craig Tiller131b6de2016-03-31 17:05:28 -0700324 if (p->checking_subchannel == 0) {
325 /* only trigger transient failure when we've tried all alternatives */
Craig Tiller804ff712016-05-05 16:25:40 -0700326 grpc_connectivity_state_set(
327 exec_ctx, &p->state_tracker, GRPC_CHANNEL_TRANSIENT_FAILURE,
Craig Tillerf707d622016-05-06 14:26:12 -0700328 GRPC_ERROR_REF(error), "connecting_transient_failure");
Craig Tiller131b6de2016-03-31 17:05:28 -0700329 }
Craig Tillerf707d622016-05-06 14:26:12 -0700330 GRPC_ERROR_UNREF(error);
Craig Tillera82950e2015-09-22 12:33:20 -0700331 p->checking_connectivity = grpc_subchannel_check_connectivity(
Craig Tiller804ff712016-05-05 16:25:40 -0700332 p->subchannels[p->checking_subchannel], &error);
Craig Tillera82950e2015-09-22 12:33:20 -0700333 if (p->checking_connectivity == GRPC_CHANNEL_TRANSIENT_FAILURE) {
334 grpc_subchannel_notify_on_state_change(
335 exec_ctx, p->subchannels[p->checking_subchannel],
Craig Tiller69b093b2016-02-25 19:04:07 -0800336 p->base.interested_parties, &p->checking_connectivity,
Craig Tiller1d881fb2015-12-01 07:39:04 -0800337 &p->connectivity_changed);
Craig Tillera82950e2015-09-22 12:33:20 -0700338 } else {
339 goto loop;
340 }
341 break;
342 case GRPC_CHANNEL_CONNECTING:
343 case GRPC_CHANNEL_IDLE:
Craig Tiller804ff712016-05-05 16:25:40 -0700344 grpc_connectivity_state_set(
345 exec_ctx, &p->state_tracker, GRPC_CHANNEL_CONNECTING,
Craig Tillerf707d622016-05-06 14:26:12 -0700346 GRPC_ERROR_REF(error), "connecting_changed");
Craig Tillera82950e2015-09-22 12:33:20 -0700347 grpc_subchannel_notify_on_state_change(
348 exec_ctx, p->subchannels[p->checking_subchannel],
Craig Tiller69b093b2016-02-25 19:04:07 -0800349 p->base.interested_parties, &p->checking_connectivity,
Craig Tiller1d881fb2015-12-01 07:39:04 -0800350 &p->connectivity_changed);
Craig Tillera82950e2015-09-22 12:33:20 -0700351 break;
Craig Tiller48ed92e2016-06-02 11:07:12 -0700352 case GRPC_CHANNEL_SHUTDOWN:
Craig Tillera82950e2015-09-22 12:33:20 -0700353 p->num_subchannels--;
Craig Tiller86c99582015-11-25 15:22:26 -0800354 GPR_SWAP(grpc_subchannel *, p->subchannels[p->checking_subchannel],
355 p->subchannels[p->num_subchannels]);
Craig Tillera82950e2015-09-22 12:33:20 -0700356 GRPC_SUBCHANNEL_UNREF(exec_ctx, p->subchannels[p->num_subchannels],
357 "pick_first");
358 if (p->num_subchannels == 0) {
Craig Tiller804ff712016-05-05 16:25:40 -0700359 grpc_connectivity_state_set(
Craig Tillerd925c932016-06-06 08:38:50 -0700360 exec_ctx, &p->state_tracker, GRPC_CHANNEL_SHUTDOWN,
Craig Tiller804ff712016-05-05 16:25:40 -0700361 GRPC_ERROR_CREATE_REFERENCING("Pick first exhausted channels",
362 &error, 1),
363 "no_more_channels");
Craig Tillera82950e2015-09-22 12:33:20 -0700364 while ((pp = p->pending_picks)) {
365 p->pending_picks = pp->next;
366 *pp->target = NULL;
Craig Tiller332f1b32016-05-24 13:21:21 -0700367 grpc_exec_ctx_sched(exec_ctx, pp->on_complete, GRPC_ERROR_NONE,
368 NULL);
Craig Tillera82950e2015-09-22 12:33:20 -0700369 gpr_free(pp);
370 }
Craig Tiller1d881fb2015-12-01 07:39:04 -0800371 GRPC_LB_POLICY_WEAK_UNREF(exec_ctx, &p->base,
372 "pick_first_connectivity");
Craig Tillera82950e2015-09-22 12:33:20 -0700373 } else {
Craig Tiller804ff712016-05-05 16:25:40 -0700374 grpc_connectivity_state_set(
375 exec_ctx, &p->state_tracker, GRPC_CHANNEL_TRANSIENT_FAILURE,
Craig Tillerf707d622016-05-06 14:26:12 -0700376 GRPC_ERROR_REF(error), "subchannel_failed");
Craig Tillera82950e2015-09-22 12:33:20 -0700377 p->checking_subchannel %= p->num_subchannels;
Craig Tillerf707d622016-05-06 14:26:12 -0700378 GRPC_ERROR_UNREF(error);
Craig Tillera82950e2015-09-22 12:33:20 -0700379 p->checking_connectivity = grpc_subchannel_check_connectivity(
Craig Tiller804ff712016-05-05 16:25:40 -0700380 p->subchannels[p->checking_subchannel], &error);
Craig Tillera82950e2015-09-22 12:33:20 -0700381 goto loop;
382 }
Craig Tiller1ada6ad2015-07-16 16:19:14 -0700383 }
Craig Tillera82950e2015-09-22 12:33:20 -0700384 }
Craig Tiller1ada6ad2015-07-16 16:19:14 -0700385
Craig Tillera82950e2015-09-22 12:33:20 -0700386 gpr_mu_unlock(&p->mu);
Craig Tiller804ff712016-05-05 16:25:40 -0700387
Craig Tillerf707d622016-05-06 14:26:12 -0700388 GRPC_ERROR_UNREF(error);
Craig Tillereb3b12e2015-06-26 14:42:49 -0700389}
390
Craig Tillera82950e2015-09-22 12:33:20 -0700391static grpc_connectivity_state pf_check_connectivity(grpc_exec_ctx *exec_ctx,
Craig Tiller804ff712016-05-05 16:25:40 -0700392 grpc_lb_policy *pol,
393 grpc_error **error) {
Craig Tillera82950e2015-09-22 12:33:20 -0700394 pick_first_lb_policy *p = (pick_first_lb_policy *)pol;
Craig Tillerc7b5f762015-06-27 11:48:42 -0700395 grpc_connectivity_state st;
Craig Tillera82950e2015-09-22 12:33:20 -0700396 gpr_mu_lock(&p->mu);
Craig Tiller804ff712016-05-05 16:25:40 -0700397 st = grpc_connectivity_state_check(&p->state_tracker, error);
Craig Tillera82950e2015-09-22 12:33:20 -0700398 gpr_mu_unlock(&p->mu);
Craig Tillerc7b5f762015-06-27 11:48:42 -0700399 return st;
400}
401
Craig Tillerfb433852016-03-29 08:51:07 -0700402static void pf_notify_on_state_change(grpc_exec_ctx *exec_ctx,
403 grpc_lb_policy *pol,
404 grpc_connectivity_state *current,
405 grpc_closure *notify) {
Craig Tillera82950e2015-09-22 12:33:20 -0700406 pick_first_lb_policy *p = (pick_first_lb_policy *)pol;
407 gpr_mu_lock(&p->mu);
408 grpc_connectivity_state_notify_on_state_change(exec_ctx, &p->state_tracker,
409 current, notify);
410 gpr_mu_unlock(&p->mu);
Craig Tillerc7b5f762015-06-27 11:48:42 -0700411}
412
Craig Tillerfb433852016-03-29 08:51:07 -0700413static void pf_ping_one(grpc_exec_ctx *exec_ctx, grpc_lb_policy *pol,
414 grpc_closure *closure) {
Craig Tiller28bf8912015-12-07 16:07:04 -0800415 pick_first_lb_policy *p = (pick_first_lb_policy *)pol;
Craig Tiller093193e2016-01-07 07:14:44 -0800416 grpc_connected_subchannel *selected = GET_SELECTED(p);
417 if (selected) {
418 grpc_connected_subchannel_ping(exec_ctx, selected, closure);
Craig Tiller28bf8912015-12-07 16:07:04 -0800419 } else {
Craig Tiller332f1b32016-05-24 13:21:21 -0700420 grpc_exec_ctx_sched(exec_ctx, closure, GRPC_ERROR_CREATE("Not connected"),
421 NULL);
Craig Tiller28bf8912015-12-07 16:07:04 -0800422 }
Craig Tiller28bf8912015-12-07 16:07:04 -0800423}
424
Craig Tillereb3b12e2015-06-26 14:42:49 -0700425static const grpc_lb_policy_vtable pick_first_lb_policy_vtable = {
Craig Tillerc5ff7812016-03-28 12:45:55 -0700426 pf_destroy, pf_shutdown, pf_pick,
427 pf_cancel_pick, pf_cancel_picks, pf_ping_one,
428 pf_exit_idle, pf_check_connectivity, pf_notify_on_state_change};
Craig Tillereb3b12e2015-06-26 14:42:49 -0700429
Craig Tillera82950e2015-09-22 12:33:20 -0700430static void pick_first_factory_ref(grpc_lb_policy_factory *factory) {}
David Garcia Quintas5c4543d2015-09-03 15:49:56 -0700431
Craig Tillera82950e2015-09-22 12:33:20 -0700432static void pick_first_factory_unref(grpc_lb_policy_factory *factory) {}
David Garcia Quintas5c4543d2015-09-03 15:49:56 -0700433
David Garcia Quintas67c0d042016-03-25 01:37:53 -0700434static grpc_lb_policy *create_pick_first(grpc_exec_ctx *exec_ctx,
435 grpc_lb_policy_factory *factory,
Craig Tillera82950e2015-09-22 12:33:20 -0700436 grpc_lb_policy_args *args) {
David Garcia Quintas86fcfcc2016-03-31 23:22:28 -0700437 GPR_ASSERT(args->client_channel_factory != NULL);
David Garcia Quintas67c0d042016-03-25 01:37:53 -0700438
Mark D. Roth5bd7be02016-10-21 14:19:50 -0700439 /* Get server name. */
440 const grpc_arg* arg =
441 grpc_channel_args_find(args->args, GRPC_ARG_SERVER_NAME);
442 const char* server_name =
443 arg != NULL && arg->type == GRPC_ARG_STRING
444 ? arg->value.string : NULL;
445
Mark D. Rothe011b1e2016-09-07 08:28:00 -0700446 /* Find the number of backend addresses. We ignore balancer
447 * addresses, since we don't know how to handle them. */
Mark D. Roth5bd7be02016-10-21 14:19:50 -0700448 arg = grpc_channel_args_find(args->args, GRPC_ARG_LB_ADDRESSES);
449 GPR_ASSERT(arg != NULL && arg->type == GRPC_ARG_POINTER);
450 grpc_lb_addresses* addresses = arg->value.pointer.p;
Mark D. Rothf655c852016-09-06 10:40:38 -0700451 size_t num_addrs = 0;
Mark D. Roth5bd7be02016-10-21 14:19:50 -0700452 for (size_t i = 0; i < addresses->num_addresses; i++) {
453 if (!addresses->addresses[i].is_balancer) ++num_addrs;
Mark D. Rothf655c852016-09-06 10:40:38 -0700454 }
455 if (num_addrs == 0) return NULL;
David Garcia Quintas67c0d042016-03-25 01:37:53 -0700456
Craig Tillera82950e2015-09-22 12:33:20 -0700457 pick_first_lb_policy *p = gpr_malloc(sizeof(*p));
Craig Tillera82950e2015-09-22 12:33:20 -0700458 memset(p, 0, sizeof(*p));
David Garcia Quintas67c0d042016-03-25 01:37:53 -0700459
Mark D. Roth989cdcd2016-09-06 13:28:28 -0700460 p->subchannels = gpr_malloc(sizeof(grpc_subchannel *) * num_addrs);
Mark D. Rothf655c852016-09-06 10:40:38 -0700461 memset(p->subchannels, 0, sizeof(*p->subchannels) * num_addrs);
David Garcia Quintas67c0d042016-03-25 01:37:53 -0700462 grpc_subchannel_args sc_args;
463 size_t subchannel_idx = 0;
Mark D. Roth5bd7be02016-10-21 14:19:50 -0700464 for (size_t i = 0; i < addresses->num_addresses; i++) {
Mark D. Rothe011b1e2016-09-07 08:28:00 -0700465 /* Skip balancer addresses, since we only know how to handle backends. */
Mark D. Roth5bd7be02016-10-21 14:19:50 -0700466 if (addresses->addresses[i].is_balancer) continue;
Mark D. Rothf655c852016-09-06 10:40:38 -0700467
Mark D. Roth5bd7be02016-10-21 14:19:50 -0700468 if (addresses->addresses[i].user_data != NULL) {
David Garcia Quintas5ebb7af2016-09-15 10:02:16 -0700469 gpr_log(GPR_ERROR,
470 "This LB policy doesn't support user data. It will be ignored");
471 }
David Garcia Quintasf47d6fb2016-09-14 12:59:17 -0700472
David Garcia Quintas67c0d042016-03-25 01:37:53 -0700473 memset(&sc_args, 0, sizeof(grpc_subchannel_args));
David Garcia Quintas129bb462016-09-28 09:50:23 -0700474 /* server_name will be copied as part of the subchannel creation. This makes
Mark D. Roth5bd7be02016-10-21 14:19:50 -0700475 * the copying of server_name (a borrowed pointer) OK. */
476 sc_args.server_name = server_name;
David Garcia Quintas331b9c02016-09-12 18:37:05 -0700477 sc_args.addr =
Mark D. Roth5bd7be02016-10-21 14:19:50 -0700478 (struct sockaddr *)(&addresses->addresses[i].address.addr);
479 sc_args.addr_len = addresses->addresses[i].address.len;
Mark D. Roth98abfd32016-10-21 08:10:51 -0700480 sc_args.args = args->args;
David Garcia Quintas67c0d042016-03-25 01:37:53 -0700481
David Garcia Quintas86fcfcc2016-03-31 23:22:28 -0700482 grpc_subchannel *subchannel = grpc_client_channel_factory_create_subchannel(
483 exec_ctx, args->client_channel_factory, &sc_args);
David Garcia Quintas67c0d042016-03-25 01:37:53 -0700484
485 if (subchannel != NULL) {
486 p->subchannels[subchannel_idx++] = subchannel;
487 }
488 }
489 if (subchannel_idx == 0) {
490 gpr_free(p->subchannels);
491 gpr_free(p);
492 return NULL;
493 }
494 p->num_subchannels = subchannel_idx;
495
496 grpc_lb_policy_init(&p->base, &pick_first_lb_policy_vtable);
Craig Tillera82950e2015-09-22 12:33:20 -0700497 grpc_closure_init(&p->connectivity_changed, pf_connectivity_changed, p);
498 gpr_mu_init(&p->mu);
Craig Tillereb3b12e2015-06-26 14:42:49 -0700499 return &p->base;
500}
David Garcia Quintas5c4543d2015-09-03 15:49:56 -0700501
502static const grpc_lb_policy_factory_vtable pick_first_factory_vtable = {
Craig Tillera82950e2015-09-22 12:33:20 -0700503 pick_first_factory_ref, pick_first_factory_unref, create_pick_first,
504 "pick_first"};
David Garcia Quintas5c4543d2015-09-03 15:49:56 -0700505
506static grpc_lb_policy_factory pick_first_lb_policy_factory = {
Craig Tillera82950e2015-09-22 12:33:20 -0700507 &pick_first_factory_vtable};
David Garcia Quintas5c4543d2015-09-03 15:49:56 -0700508
Craig Tillerfb433852016-03-29 08:51:07 -0700509static grpc_lb_policy_factory *pick_first_lb_factory_create() {
David Garcia Quintas5c4543d2015-09-03 15:49:56 -0700510 return &pick_first_lb_policy_factory;
511}
Craig Tillerfb433852016-03-29 08:51:07 -0700512
513/* Plugin registration */
514
515void grpc_lb_policy_pick_first_init() {
Craig Tiller3113ef42016-03-29 09:03:14 -0700516 grpc_register_lb_policy(pick_first_lb_factory_create());
Craig Tillerfb433852016-03-29 08:51:07 -0700517}
518
519void grpc_lb_policy_pick_first_shutdown() {}