blob: 63e3d033adf5d9104542d5abf7fe8dd6c853fc5b [file] [log] [blame]
David Garcia Quintas4fb049b2015-09-03 17:26:06 -07001/*
2 *
Craig Tiller6169d5f2016-03-31 07:46:18 -07003 * Copyright 2015, Google Inc.
David Garcia Quintas4fb049b2015-09-03 17:26:06 -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
David Garcia Quintas02008702016-06-02 21:40:45 -070034/** Round Robin Policy.
35 *
36 * This policy keeps:
David Garcia Quintas23bb5262016-06-03 13:12:30 -070037 * - A circular list of ready (connected) subchannels, the *readylist*. An empty
38 * readylist consists solely of its root (dummy) node.
David Garcia Quintas02008702016-06-02 21:40:45 -070039 * - A pointer to the last element picked from the readylist, the *lastpick*.
40 * Initially set to point to the readylist's root.
41 *
42 * Behavior:
43 * - When a subchannel connects, it's *prepended* to the readylist's root node.
44 * Ie, if readylist = A <-> B <-> ROOT <-> C
45 * ^ ^
46 * |____________________|
47 * and subchannel D becomes connected, the addition of D to the readylist
48 * results in readylist = A <-> B <-> D <-> ROOT <-> C
49 * ^ ^
50 * |__________________________|
51 * - When a subchannel disconnects, it's removed from the readylist. If the
52 * subchannel being removed was the most recently picked, the *lastpick*
53 * pointer moves to the removed node's previous element. Note that if the
54 * readylist only had one element, this is still legal, as the lastpick would
55 * point to the dummy root node, for an empty readylist.
56 * - Upon picking, *lastpick* is updated to point to the returned (connected)
David Garcia Quintas23bb5262016-06-03 13:12:30 -070057 * subchannel. Note that it's possible that the selected subchannel becomes
David Garcia Quintas02008702016-06-02 21:40:45 -070058 * disconnected in the interim between the selection and the actual usage of
59 * the subchannel by the caller.
60 */
61
David Garcia Quintas4fb049b2015-09-03 17:26:06 -070062#include <string.h>
63
64#include <grpc/support/alloc.h>
Craig Tillerfb433852016-03-29 08:51:07 -070065
Mark D. Roth2137cd82016-09-14 09:04:00 -070066#include "src/core/ext/client_channel/lb_policy_registry.h"
Mark D. Roth0748f392017-01-13 09:22:44 -080067#include "src/core/ext/client_channel/subchannel.h"
Mark D. Roth5bd7be02016-10-21 14:19:50 -070068#include "src/core/lib/channel/channel_args.h"
Craig Tillerfb433852016-03-29 08:51:07 -070069#include "src/core/lib/debug/trace.h"
Mark D. Roth0748f392017-01-13 09:22:44 -080070#include "src/core/lib/iomgr/sockaddr_utils.h"
Craig Tiller9533d042016-03-25 17:11:06 -070071#include "src/core/lib/transport/connectivity_state.h"
David Garcia Quintas5b0e9462016-08-15 19:38:39 -070072#include "src/core/lib/transport/static_metadata.h"
David Garcia Quintas4fb049b2015-09-03 17:26:06 -070073
Craig Tillere2a65102015-11-30 17:51:49 -080074typedef struct round_robin_lb_policy round_robin_lb_policy;
75
David Garcia Quintas4fb049b2015-09-03 17:26:06 -070076int grpc_lb_round_robin_trace = 0;
77
78/** List of entities waiting for a pick.
79 *
80 * Once a pick is available, \a target is updated and \a on_complete called. */
Craig Tillera82950e2015-09-22 12:33:20 -070081typedef struct pending_pick {
David Garcia Quintas4fb049b2015-09-03 17:26:06 -070082 struct pending_pick *next;
David Garcia Quintas5b0e9462016-08-15 19:38:39 -070083
David Garcia Quintas331b9c02016-09-12 18:37:05 -070084 /* output argument where to store the pick()ed user_data. It'll be NULL if no
85 * such data is present or there's an error (the definite test for errors is
86 * \a target being NULL). */
87 void **user_data;
David Garcia Quintas5b0e9462016-08-15 19:38:39 -070088
89 /* bitmask passed to pick() and used for selective cancelling. See
90 * grpc_lb_policy_cancel_picks() */
Craig Tiller8c0d96f2016-03-11 14:27:52 -080091 uint32_t initial_metadata_flags;
David Garcia Quintas5b0e9462016-08-15 19:38:39 -070092
93 /* output argument where to store the pick()ed connected subchannel, or NULL
94 * upon error. */
Craig Tillerb5585d42015-11-17 07:18:31 -080095 grpc_connected_subchannel **target;
David Garcia Quintas5b0e9462016-08-15 19:38:39 -070096
97 /* to be invoked once the pick() has completed (regardless of success) */
Craig Tiller10ee2742015-09-22 09:25:57 -070098 grpc_closure *on_complete;
David Garcia Quintas4fb049b2015-09-03 17:26:06 -070099} pending_pick;
100
101/** List of subchannels in a connectivity READY state */
Craig Tillera82950e2015-09-22 12:33:20 -0700102typedef struct ready_list {
David Garcia Quintas4fb049b2015-09-03 17:26:06 -0700103 grpc_subchannel *subchannel;
David Garcia Quintas5b0e9462016-08-15 19:38:39 -0700104 /* references namesake entry in subchannel_data */
David Garcia Quintas331b9c02016-09-12 18:37:05 -0700105 void *user_data;
David Garcia Quintas4fb049b2015-09-03 17:26:06 -0700106 struct ready_list *next;
107 struct ready_list *prev;
108} ready_list;
109
Craig Tillera82950e2015-09-22 12:33:20 -0700110typedef struct {
Craig Tillere2a65102015-11-30 17:51:49 -0800111 /** index within policy->subchannels */
112 size_t index;
113 /** backpointer to owning policy */
114 round_robin_lb_policy *policy;
115 /** subchannel itself */
116 grpc_subchannel *subchannel;
117 /** notification that connectivity has changed on subchannel */
118 grpc_closure connectivity_changed_closure;
119 /** this subchannels current position in subchannel->ready_list */
120 ready_list *ready_list_node;
David Garcia Quintasa9cf87d2016-11-07 17:43:15 -0800121 /** last observed connectivity. Not updated by
122 * \a grpc_subchannel_notify_on_state_change. Used to determine the previous
123 * state while processing the new state in \a rr_connectivity_changed */
124 grpc_connectivity_state prev_connectivity_state;
125 /** current connectivity state. Updated by \a
126 * grpc_subchannel_notify_on_state_change */
127 grpc_connectivity_state curr_connectivity_state;
David Garcia Quintas331b9c02016-09-12 18:37:05 -0700128 /** the subchannel's target user data */
129 void *user_data;
David Garcia Quintas98da61b2016-10-29 08:46:31 +0200130 /** vtable to operate over \a user_data */
David Garcia Quintas7ec29132016-11-01 04:09:05 +0100131 const grpc_lb_user_data_vtable *user_data_vtable;
Craig Tillere2a65102015-11-30 17:51:49 -0800132} subchannel_data;
David Garcia Quintas4fb049b2015-09-03 17:26:06 -0700133
Craig Tillere2a65102015-11-30 17:51:49 -0800134struct round_robin_lb_policy {
David Garcia Quintas4fb049b2015-09-03 17:26:06 -0700135 /** base policy: must be first */
136 grpc_lb_policy base;
David Garcia Quintasa9cf87d2016-11-07 17:43:15 -0800137 gpr_mu mu;
David Garcia Quintas4fb049b2015-09-03 17:26:06 -0700138
David Garcia Quintas5b0e9462016-08-15 19:38:39 -0700139 /** total number of addresses received at creation time */
140 size_t num_addresses;
David Garcia Quintas5b0e9462016-08-15 19:38:39 -0700141
David Garcia Quintas4fb049b2015-09-03 17:26:06 -0700142 /** all our subchannels */
David Garcia Quintas4fb049b2015-09-03 17:26:06 -0700143 size_t num_subchannels;
Craig Tillere2a65102015-11-30 17:51:49 -0800144 subchannel_data **subchannels;
David Garcia Quintas4fb049b2015-09-03 17:26:06 -0700145
David Garcia Quintasa9cf87d2016-11-07 17:43:15 -0800146 /** how many subchannels are in TRANSIENT_FAILURE */
147 size_t num_transient_failures;
148 /** how many subchannels are IDLE */
149 size_t num_idle;
150
David Garcia Quintas4fb049b2015-09-03 17:26:06 -0700151 /** have we started picking? */
152 int started_picking;
153 /** are we shutting down? */
154 int shutdown;
David Garcia Quintas4fb049b2015-09-03 17:26:06 -0700155 /** List of picks that are waiting on connectivity */
156 pending_pick *pending_picks;
157
158 /** our connectivity state tracker */
159 grpc_connectivity_state_tracker state_tracker;
160
161 /** (Dummy) root of the doubly linked list containing READY subchannels */
162 ready_list ready_list;
163 /** Last pick from the ready list. */
164 ready_list *ready_list_last_pick;
Craig Tillere2a65102015-11-30 17:51:49 -0800165};
David Garcia Quintas4fb049b2015-09-03 17:26:06 -0700166
167/** Returns the next subchannel from the connected list or NULL if the list is
168 * empty.
169 *
170 * Note that this function does *not* advance p->ready_list_last_pick. Use \a
171 * advance_last_picked_locked() for that. */
Craig Tillera82950e2015-09-22 12:33:20 -0700172static ready_list *peek_next_connected_locked(const round_robin_lb_policy *p) {
David Garcia Quintas4fb049b2015-09-03 17:26:06 -0700173 ready_list *selected;
174 selected = p->ready_list_last_pick->next;
175
Craig Tillera82950e2015-09-22 12:33:20 -0700176 while (selected != NULL) {
177 if (selected == &p->ready_list) {
178 GPR_ASSERT(selected->subchannel == NULL);
179 /* skip dummy root */
180 selected = selected->next;
181 } else {
182 GPR_ASSERT(selected->subchannel != NULL);
183 return selected;
David Garcia Quintas4fb049b2015-09-03 17:26:06 -0700184 }
Craig Tillera82950e2015-09-22 12:33:20 -0700185 }
David Garcia Quintas4fb049b2015-09-03 17:26:06 -0700186 return NULL;
187}
188
189/** Advance the \a ready_list picking head. */
Craig Tillera82950e2015-09-22 12:33:20 -0700190static void advance_last_picked_locked(round_robin_lb_policy *p) {
191 if (p->ready_list_last_pick->next != NULL) { /* non-empty list */
192 p->ready_list_last_pick = p->ready_list_last_pick->next;
193 if (p->ready_list_last_pick == &p->ready_list) {
194 /* skip dummy root */
David Garcia Quintas4fb049b2015-09-03 17:26:06 -0700195 p->ready_list_last_pick = p->ready_list_last_pick->next;
196 }
Craig Tillera82950e2015-09-22 12:33:20 -0700197 } else { /* should be an empty list */
198 GPR_ASSERT(p->ready_list_last_pick == &p->ready_list);
199 }
David Garcia Quintas4fb049b2015-09-03 17:26:06 -0700200
Craig Tillera82950e2015-09-22 12:33:20 -0700201 if (grpc_lb_round_robin_trace) {
David Garcia Quintas98da61b2016-10-29 08:46:31 +0200202 gpr_log(GPR_DEBUG,
203 "[READYLIST, RR: %p] ADVANCED LAST PICK. NOW AT NODE %p (SC %p, "
204 "CSC %p)",
205 (void *)p, (void *)p->ready_list_last_pick,
206 (void *)p->ready_list_last_pick->subchannel,
207 (void *)grpc_subchannel_get_connected_subchannel(
208 p->ready_list_last_pick->subchannel));
Craig Tillera82950e2015-09-22 12:33:20 -0700209 }
David Garcia Quintas4fb049b2015-09-03 17:26:06 -0700210}
211
212/** Prepends (relative to the root at p->ready_list) the connected subchannel \a
213 * csc to the list of ready subchannels. */
Craig Tillera82950e2015-09-22 12:33:20 -0700214static ready_list *add_connected_sc_locked(round_robin_lb_policy *p,
David Garcia Quintas5b0e9462016-08-15 19:38:39 -0700215 subchannel_data *sd) {
Craig Tillera82950e2015-09-22 12:33:20 -0700216 ready_list *new_elem = gpr_malloc(sizeof(ready_list));
David Garcia Quintas5b0e9462016-08-15 19:38:39 -0700217 memset(new_elem, 0, sizeof(ready_list));
218 new_elem->subchannel = sd->subchannel;
David Garcia Quintas331b9c02016-09-12 18:37:05 -0700219 new_elem->user_data = sd->user_data;
Craig Tillera82950e2015-09-22 12:33:20 -0700220 if (p->ready_list.prev == NULL) {
221 /* first element */
222 new_elem->next = &p->ready_list;
223 new_elem->prev = &p->ready_list;
224 p->ready_list.next = new_elem;
225 p->ready_list.prev = new_elem;
226 } else {
227 new_elem->next = &p->ready_list;
228 new_elem->prev = p->ready_list.prev;
229 p->ready_list.prev->next = new_elem;
230 p->ready_list.prev = new_elem;
231 }
232 if (grpc_lb_round_robin_trace) {
David Garcia Quintas5b0e9462016-08-15 19:38:39 -0700233 gpr_log(GPR_DEBUG, "[READYLIST] ADDING NODE %p (Conn. SC %p)",
234 (void *)new_elem, (void *)sd->subchannel);
Craig Tillera82950e2015-09-22 12:33:20 -0700235 }
David Garcia Quintas4fb049b2015-09-03 17:26:06 -0700236 return new_elem;
237}
238
239/** Removes \a node from the list of connected subchannels */
Craig Tillera82950e2015-09-22 12:33:20 -0700240static void remove_disconnected_sc_locked(round_robin_lb_policy *p,
241 ready_list *node) {
242 if (node == NULL) {
243 return;
244 }
245 if (node == p->ready_list_last_pick) {
David Garcia Quintas02008702016-06-02 21:40:45 -0700246 p->ready_list_last_pick = p->ready_list_last_pick->prev;
Craig Tillera82950e2015-09-22 12:33:20 -0700247 }
David Garcia Quintas4fb049b2015-09-03 17:26:06 -0700248
249 /* removing last item */
Craig Tillera82950e2015-09-22 12:33:20 -0700250 if (node->next == &p->ready_list && node->prev == &p->ready_list) {
251 GPR_ASSERT(p->ready_list.next == node);
252 GPR_ASSERT(p->ready_list.prev == node);
253 p->ready_list.next = NULL;
254 p->ready_list.prev = NULL;
255 } else {
256 node->prev->next = node->next;
257 node->next->prev = node->prev;
258 }
David Garcia Quintas4fb049b2015-09-03 17:26:06 -0700259
Craig Tillera82950e2015-09-22 12:33:20 -0700260 if (grpc_lb_round_robin_trace) {
David Garcia Quintas331b9c02016-09-12 18:37:05 -0700261 gpr_log(GPR_DEBUG, "[READYLIST] REMOVED NODE %p (SC %p)", (void *)node,
David Garcia Quintas5b0e9462016-08-15 19:38:39 -0700262 (void *)node->subchannel);
Craig Tillera82950e2015-09-22 12:33:20 -0700263 }
David Garcia Quintas4fb049b2015-09-03 17:26:06 -0700264
265 node->next = NULL;
266 node->prev = NULL;
267 node->subchannel = NULL;
268
Craig Tillera82950e2015-09-22 12:33:20 -0700269 gpr_free(node);
David Garcia Quintas4fb049b2015-09-03 17:26:06 -0700270}
271
David Garcia Quintasa9cf87d2016-11-07 17:43:15 -0800272static bool is_ready_list_empty(round_robin_lb_policy *p) {
273 return p->ready_list.prev == NULL;
274}
275
Craig Tillerfb433852016-03-29 08:51:07 -0700276static void rr_destroy(grpc_exec_ctx *exec_ctx, grpc_lb_policy *pol) {
Craig Tillera82950e2015-09-22 12:33:20 -0700277 round_robin_lb_policy *p = (round_robin_lb_policy *)pol;
David Garcia Quintas4fb049b2015-09-03 17:26:06 -0700278 ready_list *elem;
David Garcia Quintas98da61b2016-10-29 08:46:31 +0200279
280 if (grpc_lb_round_robin_trace) {
David Garcia Quintas2ff81802016-11-01 21:58:16 -0700281 gpr_log(GPR_DEBUG, "Destroying Round Robin policy at %p", (void *)pol);
David Garcia Quintas98da61b2016-10-29 08:46:31 +0200282 }
283
David Garcia Quintas331b9c02016-09-12 18:37:05 -0700284 for (size_t i = 0; i < p->num_subchannels; i++) {
Craig Tillere2a65102015-11-30 17:51:49 -0800285 subchannel_data *sd = p->subchannels[i];
David Garcia Quintasa9cf87d2016-11-07 17:43:15 -0800286 GRPC_SUBCHANNEL_UNREF(exec_ctx, sd->subchannel, "rr_destroy");
David Garcia Quintas246c5642016-11-01 11:16:52 -0700287 if (sd->user_data != NULL) {
David Garcia Quintase224a762016-11-01 13:00:58 -0700288 GPR_ASSERT(sd->user_data_vtable != NULL);
Craig Tiller87a7e1f2016-11-09 09:42:19 -0800289 sd->user_data_vtable->destroy(exec_ctx, sd->user_data);
David Garcia Quintas7ec29132016-11-01 04:09:05 +0100290 }
Craig Tillere2a65102015-11-30 17:51:49 -0800291 gpr_free(sd);
Craig Tillera82950e2015-09-22 12:33:20 -0700292 }
David Garcia Quintas4fb049b2015-09-03 17:26:06 -0700293
Craig Tillera82950e2015-09-22 12:33:20 -0700294 grpc_connectivity_state_destroy(exec_ctx, &p->state_tracker);
295 gpr_free(p->subchannels);
296 gpr_mu_destroy(&p->mu);
David Garcia Quintas4fb049b2015-09-03 17:26:06 -0700297
298 elem = p->ready_list.next;
Craig Tillera82950e2015-09-22 12:33:20 -0700299 while (elem != NULL && elem != &p->ready_list) {
300 ready_list *tmp;
301 tmp = elem->next;
302 elem->next = NULL;
303 elem->prev = NULL;
304 elem->subchannel = NULL;
305 gpr_free(elem);
306 elem = tmp;
307 }
David Garcia Quintas5b0e9462016-08-15 19:38:39 -0700308
Craig Tillera82950e2015-09-22 12:33:20 -0700309 gpr_free(p);
David Garcia Quintas4fb049b2015-09-03 17:26:06 -0700310}
311
Craig Tillerfb433852016-03-29 08:51:07 -0700312static void rr_shutdown(grpc_exec_ctx *exec_ctx, grpc_lb_policy *pol) {
Craig Tillera82950e2015-09-22 12:33:20 -0700313 round_robin_lb_policy *p = (round_robin_lb_policy *)pol;
David Garcia Quintas4fb049b2015-09-03 17:26:06 -0700314 pending_pick *pp;
Craig Tiller2a1bb7f2015-11-29 21:54:26 -0800315 size_t i;
316
Craig Tillera82950e2015-09-22 12:33:20 -0700317 gpr_mu_lock(&p->mu);
David Garcia Quintas98da61b2016-10-29 08:46:31 +0200318 if (grpc_lb_round_robin_trace) {
David Garcia Quintas7ec29132016-11-01 04:09:05 +0100319 gpr_log(GPR_DEBUG, "Shutting down Round Robin policy at %p", (void *)pol);
David Garcia Quintas98da61b2016-10-29 08:46:31 +0200320 }
David Garcia Quintas4fb049b2015-09-03 17:26:06 -0700321
322 p->shutdown = 1;
Craig Tillera82950e2015-09-22 12:33:20 -0700323 while ((pp = p->pending_picks)) {
324 p->pending_picks = pp->next;
325 *pp->target = NULL;
Craig Tiller91031da2016-12-28 15:44:25 -0800326 grpc_closure_sched(exec_ctx, pp->on_complete,
327 GRPC_ERROR_CREATE("Channel Shutdown"));
Craig Tillera82950e2015-09-22 12:33:20 -0700328 gpr_free(pp);
329 }
Craig Tiller804ff712016-05-05 16:25:40 -0700330 grpc_connectivity_state_set(
Craig Tillerd925c932016-06-06 08:38:50 -0700331 exec_ctx, &p->state_tracker, GRPC_CHANNEL_SHUTDOWN,
David Garcia Quintas98da61b2016-10-29 08:46:31 +0200332 GRPC_ERROR_CREATE("Channel Shutdown"), "rr_shutdown");
Craig Tiller2a1bb7f2015-11-29 21:54:26 -0800333 for (i = 0; i < p->num_subchannels; i++) {
Craig Tillere2a65102015-11-30 17:51:49 -0800334 subchannel_data *sd = p->subchannels[i];
Craig Tiller1d881fb2015-12-01 07:39:04 -0800335 grpc_subchannel_notify_on_state_change(exec_ctx, sd->subchannel, NULL, NULL,
Craig Tillere2a65102015-11-30 17:51:49 -0800336 &sd->connectivity_changed_closure);
Craig Tiller2a1bb7f2015-11-29 21:54:26 -0800337 }
Craig Tillera82950e2015-09-22 12:33:20 -0700338 gpr_mu_unlock(&p->mu);
David Garcia Quintas4fb049b2015-09-03 17:26:06 -0700339}
340
Craig Tiller577c9b22015-11-02 14:11:15 -0800341static void rr_cancel_pick(grpc_exec_ctx *exec_ctx, grpc_lb_policy *pol,
Mark D. Roth5f844002016-09-08 08:20:53 -0700342 grpc_connected_subchannel **target,
343 grpc_error *error) {
Craig Tiller577c9b22015-11-02 14:11:15 -0800344 round_robin_lb_policy *p = (round_robin_lb_policy *)pol;
345 pending_pick *pp;
Craig Tiller577c9b22015-11-02 14:11:15 -0800346 gpr_mu_lock(&p->mu);
347 pp = p->pending_picks;
348 p->pending_picks = NULL;
349 while (pp != NULL) {
350 pending_pick *next = pp->next;
351 if (pp->target == target) {
Craig Tiller577c9b22015-11-02 14:11:15 -0800352 *target = NULL;
Craig Tiller91031da2016-12-28 15:44:25 -0800353 grpc_closure_sched(
Mark D. Roth932b10c2016-09-09 08:44:30 -0700354 exec_ctx, pp->on_complete,
Craig Tiller91031da2016-12-28 15:44:25 -0800355 GRPC_ERROR_CREATE_REFERENCING("Pick cancelled", &error, 1));
Craig Tiller577c9b22015-11-02 14:11:15 -0800356 gpr_free(pp);
357 } else {
358 pp->next = p->pending_picks;
359 p->pending_picks = pp;
360 }
361 pp = next;
362 }
363 gpr_mu_unlock(&p->mu);
Mark D. Roth5f844002016-09-08 08:20:53 -0700364 GRPC_ERROR_UNREF(error);
Craig Tiller577c9b22015-11-02 14:11:15 -0800365}
366
Craig Tiller8c0d96f2016-03-11 14:27:52 -0800367static void rr_cancel_picks(grpc_exec_ctx *exec_ctx, grpc_lb_policy *pol,
368 uint32_t initial_metadata_flags_mask,
Mark D. Rothe65ff112016-09-09 13:48:38 -0700369 uint32_t initial_metadata_flags_eq,
370 grpc_error *error) {
Craig Tiller8c0d96f2016-03-11 14:27:52 -0800371 round_robin_lb_policy *p = (round_robin_lb_policy *)pol;
372 pending_pick *pp;
373 gpr_mu_lock(&p->mu);
374 pp = p->pending_picks;
375 p->pending_picks = NULL;
376 while (pp != NULL) {
377 pending_pick *next = pp->next;
378 if ((pp->initial_metadata_flags & initial_metadata_flags_mask) ==
379 initial_metadata_flags_eq) {
Craig Tiller8c0d96f2016-03-11 14:27:52 -0800380 *pp->target = NULL;
Craig Tiller91031da2016-12-28 15:44:25 -0800381 grpc_closure_sched(
Mark D. Roth58f52b72016-09-09 13:55:18 -0700382 exec_ctx, pp->on_complete,
Craig Tiller91031da2016-12-28 15:44:25 -0800383 GRPC_ERROR_CREATE_REFERENCING("Pick cancelled", &error, 1));
Craig Tiller8c0d96f2016-03-11 14:27:52 -0800384 gpr_free(pp);
385 } else {
386 pp->next = p->pending_picks;
387 p->pending_picks = pp;
388 }
389 pp = next;
390 }
391 gpr_mu_unlock(&p->mu);
Mark D. Rothe65ff112016-09-09 13:48:38 -0700392 GRPC_ERROR_UNREF(error);
Craig Tiller8c0d96f2016-03-11 14:27:52 -0800393}
394
Craig Tillera82950e2015-09-22 12:33:20 -0700395static void start_picking(grpc_exec_ctx *exec_ctx, round_robin_lb_policy *p) {
David Garcia Quintas4fb049b2015-09-03 17:26:06 -0700396 size_t i;
397 p->started_picking = 1;
398
Craig Tillera82950e2015-09-22 12:33:20 -0700399 for (i = 0; i < p->num_subchannels; i++) {
Craig Tillere2a65102015-11-30 17:51:49 -0800400 subchannel_data *sd = p->subchannels[i];
David Garcia Quintasa9cf87d2016-11-07 17:43:15 -0800401 /* use some sentinel value outside of the range of grpc_connectivity_state
402 * to signal an undefined previous state. We won't be referring to this
403 * value again and it'll be overwritten after the first call to
404 * rr_connectivity_changed */
David Garcia Quintasea6689d2016-11-08 09:46:41 -0800405 sd->prev_connectivity_state = GRPC_CHANNEL_INIT;
David Garcia Quintasa9cf87d2016-11-07 17:43:15 -0800406 sd->curr_connectivity_state = GRPC_CHANNEL_IDLE;
407 GRPC_LB_POLICY_WEAK_REF(&p->base, "rr_connectivity");
Craig Tiller1d881fb2015-12-01 07:39:04 -0800408 grpc_subchannel_notify_on_state_change(
Craig Tiller69b093b2016-02-25 19:04:07 -0800409 exec_ctx, sd->subchannel, p->base.interested_parties,
David Garcia Quintasa9cf87d2016-11-07 17:43:15 -0800410 &sd->curr_connectivity_state, &sd->connectivity_changed_closure);
Craig Tillera82950e2015-09-22 12:33:20 -0700411 }
David Garcia Quintas4fb049b2015-09-03 17:26:06 -0700412}
413
Craig Tillerfb433852016-03-29 08:51:07 -0700414static void rr_exit_idle(grpc_exec_ctx *exec_ctx, grpc_lb_policy *pol) {
Craig Tillera82950e2015-09-22 12:33:20 -0700415 round_robin_lb_policy *p = (round_robin_lb_policy *)pol;
416 gpr_mu_lock(&p->mu);
417 if (!p->started_picking) {
418 start_picking(exec_ctx, p);
419 }
420 gpr_mu_unlock(&p->mu);
David Garcia Quintas4fb049b2015-09-03 17:26:06 -0700421}
422
Craig Tillerfb433852016-03-29 08:51:07 -0700423static int rr_pick(grpc_exec_ctx *exec_ctx, grpc_lb_policy *pol,
David Garcia Quintas8aace512016-08-15 14:55:12 -0700424 const grpc_lb_policy_pick_args *pick_args,
David Garcia Quintas331b9c02016-09-12 18:37:05 -0700425 grpc_connected_subchannel **target, void **user_data,
Craig Tillerfb433852016-03-29 08:51:07 -0700426 grpc_closure *on_complete) {
Craig Tillera82950e2015-09-22 12:33:20 -0700427 round_robin_lb_policy *p = (round_robin_lb_policy *)pol;
David Garcia Quintas4fb049b2015-09-03 17:26:06 -0700428 pending_pick *pp;
429 ready_list *selected;
Craig Tillera82950e2015-09-22 12:33:20 -0700430 gpr_mu_lock(&p->mu);
David Garcia Quintas98da61b2016-10-29 08:46:31 +0200431
432 if (grpc_lb_round_robin_trace) {
David Garcia Quintas7ec29132016-11-01 04:09:05 +0100433 gpr_log(GPR_INFO, "Round Robin %p trying to pick", (void *)pol);
David Garcia Quintas98da61b2016-10-29 08:46:31 +0200434 }
435
Craig Tillera82950e2015-09-22 12:33:20 -0700436 if ((selected = peek_next_connected_locked(p))) {
David Garcia Quintas5b0e9462016-08-15 19:38:39 -0700437 /* readily available, report right away */
Craig Tiller693d3942016-10-27 16:51:25 -0700438 *target = GRPC_CONNECTED_SUBCHANNEL_REF(
439 grpc_subchannel_get_connected_subchannel(selected->subchannel),
David Garcia Quintase9448df2016-11-09 15:55:17 -0800440 "rr_picked");
David Garcia Quintas155b8202016-09-15 16:14:15 -0700441
442 if (user_data != NULL) {
443 *user_data = selected->user_data;
444 }
Craig Tillera82950e2015-09-22 12:33:20 -0700445 if (grpc_lb_round_robin_trace) {
Craig Tillerab33b482015-11-21 08:11:04 -0800446 gpr_log(GPR_DEBUG,
David Garcia Quintas5b0e9462016-08-15 19:38:39 -0700447 "[RR PICK] TARGET <-- CONNECTED SUBCHANNEL %p (NODE %p)",
448 (void *)*target, (void *)selected);
David Garcia Quintas4fb049b2015-09-03 17:26:06 -0700449 }
Craig Tillera82950e2015-09-22 12:33:20 -0700450 /* only advance the last picked pointer if the selection was used */
451 advance_last_picked_locked(p);
David Garcia Quintas90712d52016-10-13 19:33:04 -0700452 gpr_mu_unlock(&p->mu);
Craig Tiller577c9b22015-11-02 14:11:15 -0800453 return 1;
Craig Tillera82950e2015-09-22 12:33:20 -0700454 } else {
David Garcia Quintas5b0e9462016-08-15 19:38:39 -0700455 /* no pick currently available. Save for later in list of pending picks */
Craig Tillera82950e2015-09-22 12:33:20 -0700456 if (!p->started_picking) {
457 start_picking(exec_ctx, p);
David Garcia Quintas4fb049b2015-09-03 17:26:06 -0700458 }
Craig Tillera82950e2015-09-22 12:33:20 -0700459 pp = gpr_malloc(sizeof(*pp));
460 pp->next = p->pending_picks;
Craig Tillera82950e2015-09-22 12:33:20 -0700461 pp->target = target;
462 pp->on_complete = on_complete;
David Garcia Quintas8aace512016-08-15 14:55:12 -0700463 pp->initial_metadata_flags = pick_args->initial_metadata_flags;
David Garcia Quintas331b9c02016-09-12 18:37:05 -0700464 pp->user_data = user_data;
Craig Tillera82950e2015-09-22 12:33:20 -0700465 p->pending_picks = pp;
466 gpr_mu_unlock(&p->mu);
Craig Tiller577c9b22015-11-02 14:11:15 -0800467 return 0;
Craig Tillera82950e2015-09-22 12:33:20 -0700468 }
David Garcia Quintas4fb049b2015-09-03 17:26:06 -0700469}
470
David Garcia Quintasa9cf87d2016-11-07 17:43:15 -0800471static void update_state_counters(subchannel_data *sd) {
472 round_robin_lb_policy *p = sd->policy;
473
474 /* update p->num_transient_failures (resp. p->num_idle): if the previous
475 * state was TRANSIENT_FAILURE (resp. IDLE), decrement
476 * p->num_transient_failures (resp. p->num_idle). */
477 if (sd->prev_connectivity_state == GRPC_CHANNEL_TRANSIENT_FAILURE) {
478 GPR_ASSERT(p->num_transient_failures > 0);
479 --p->num_transient_failures;
480 } else if (sd->prev_connectivity_state == GRPC_CHANNEL_IDLE) {
481 GPR_ASSERT(p->num_idle > 0);
482 --p->num_idle;
483 }
484}
485
486/* sd is the subchannel_data associted with the updated subchannel.
487 * shutdown_error will only be used upon policy transition to TRANSIENT_FAILURE
488 * or SHUTDOWN */
489static grpc_connectivity_state update_lb_connectivity_status(
490 grpc_exec_ctx *exec_ctx, subchannel_data *sd, grpc_error *error) {
491 /* In priority order. The first rule to match terminates the search (ie, if we
492 * are on rule n, all previous rules were unfulfilled).
493 *
494 * 1) RULE: ANY subchannel is READY => policy is READY.
495 * CHECK: At least one subchannel is ready iff p->ready_list is NOT empty.
496 *
497 * 2) RULE: ANY subchannel is CONNECTING => policy is CONNECTING.
498 * CHECK: sd->curr_connectivity_state == CONNECTING.
499 *
500 * 3) RULE: ALL subchannels are SHUTDOWN => policy is SHUTDOWN.
501 * CHECK: p->num_subchannels = 0.
502 *
503 * 4) RULE: ALL subchannels are TRANSIENT_FAILURE => policy is
504 * TRANSIENT_FAILURE.
505 * CHECK: p->num_transient_failures == p->num_subchannels.
506 *
507 * 5) RULE: ALL subchannels are IDLE => policy is IDLE.
508 * CHECK: p->num_idle == p->num_subchannels.
509 */
510 round_robin_lb_policy *p = sd->policy;
511 if (!is_ready_list_empty(p)) { /* 1) READY */
512 grpc_connectivity_state_set(exec_ctx, &p->state_tracker, GRPC_CHANNEL_READY,
513 GRPC_ERROR_NONE, "rr_ready");
514 return GRPC_CHANNEL_READY;
515 } else if (sd->curr_connectivity_state ==
516 GRPC_CHANNEL_CONNECTING) { /* 2) CONNECTING */
517 grpc_connectivity_state_set(exec_ctx, &p->state_tracker,
518 GRPC_CHANNEL_CONNECTING, GRPC_ERROR_NONE,
519 "rr_connecting");
520 return GRPC_CHANNEL_CONNECTING;
521 } else if (p->num_subchannels == 0) { /* 3) SHUTDOWN */
522 grpc_connectivity_state_set(exec_ctx, &p->state_tracker,
523 GRPC_CHANNEL_SHUTDOWN, GRPC_ERROR_REF(error),
524 "rr_shutdown");
525 return GRPC_CHANNEL_SHUTDOWN;
526 } else if (p->num_transient_failures ==
527 p->num_subchannels) { /* 4) TRANSIENT_FAILURE */
528 grpc_connectivity_state_set(exec_ctx, &p->state_tracker,
529 GRPC_CHANNEL_TRANSIENT_FAILURE,
530 GRPC_ERROR_REF(error), "rr_transient_failure");
531 return GRPC_CHANNEL_TRANSIENT_FAILURE;
532 } else if (p->num_idle == p->num_subchannels) { /* 5) IDLE */
533 grpc_connectivity_state_set(exec_ctx, &p->state_tracker, GRPC_CHANNEL_IDLE,
534 GRPC_ERROR_NONE, "rr_idle");
535 return GRPC_CHANNEL_IDLE;
536 }
537 /* no change */
538 return sd->curr_connectivity_state;
539}
540
Craig Tillera82950e2015-09-22 12:33:20 -0700541static void rr_connectivity_changed(grpc_exec_ctx *exec_ctx, void *arg,
Craig Tiller804ff712016-05-05 16:25:40 -0700542 grpc_error *error) {
Craig Tillere2a65102015-11-30 17:51:49 -0800543 subchannel_data *sd = arg;
544 round_robin_lb_policy *p = sd->policy;
David Garcia Quintas4fb049b2015-09-03 17:26:06 -0700545 pending_pick *pp;
David Garcia Quintas4fb049b2015-09-03 17:26:06 -0700546
Craig Tillerf707d622016-05-06 14:26:12 -0700547 GRPC_ERROR_REF(error);
Craig Tillera82950e2015-09-22 12:33:20 -0700548 gpr_mu_lock(&p->mu);
David Garcia Quintas4fb049b2015-09-03 17:26:06 -0700549
Craig Tillera82950e2015-09-22 12:33:20 -0700550 if (p->shutdown) {
David Garcia Quintasa9cf87d2016-11-07 17:43:15 -0800551 gpr_mu_unlock(&p->mu);
552 GRPC_LB_POLICY_WEAK_UNREF(exec_ctx, &p->base, "rr_connectivity");
553 GRPC_ERROR_UNREF(error);
554 return;
555 }
556 switch (sd->curr_connectivity_state) {
David Garcia Quintasea6689d2016-11-08 09:46:41 -0800557 case GRPC_CHANNEL_INIT:
Jan Tattermuschb0fb2d22016-11-16 14:04:05 +0100558 GPR_UNREACHABLE_CODE(return );
David Garcia Quintasa9cf87d2016-11-07 17:43:15 -0800559 case GRPC_CHANNEL_READY:
560 /* add the newly connected subchannel to the list of connected ones.
561 * Note that it goes to the "end of the line". */
562 sd->ready_list_node = add_connected_sc_locked(p, sd);
563 /* at this point we know there's at least one suitable subchannel. Go
564 * ahead and pick one and notify the pending suitors in
565 * p->pending_picks. This preemtively replicates rr_pick()'s actions. */
566 ready_list *selected = peek_next_connected_locked(p);
567 GPR_ASSERT(selected != NULL);
568 if (p->pending_picks != NULL) {
569 /* if the selected subchannel is going to be used for the pending
570 * picks, update the last picked pointer */
571 advance_last_picked_locked(p);
572 }
573 while ((pp = p->pending_picks)) {
574 p->pending_picks = pp->next;
575 *pp->target = GRPC_CONNECTED_SUBCHANNEL_REF(
576 grpc_subchannel_get_connected_subchannel(selected->subchannel),
577 "rr_picked");
578 if (pp->user_data != NULL) {
579 *pp->user_data = selected->user_data;
Craig Tillera82950e2015-09-22 12:33:20 -0700580 }
David Garcia Quintasa9cf87d2016-11-07 17:43:15 -0800581 if (grpc_lb_round_robin_trace) {
582 gpr_log(GPR_DEBUG,
583 "[RR CONN CHANGED] TARGET <-- SUBCHANNEL %p (NODE %p)",
584 (void *)selected->subchannel, (void *)selected);
585 }
Craig Tiller91031da2016-12-28 15:44:25 -0800586 grpc_closure_sched(exec_ctx, pp->on_complete, GRPC_ERROR_NONE);
David Garcia Quintasa9cf87d2016-11-07 17:43:15 -0800587 gpr_free(pp);
588 }
David Garcia Quintase9448df2016-11-09 15:55:17 -0800589 update_lb_connectivity_status(exec_ctx, sd, error);
590 sd->prev_connectivity_state = sd->curr_connectivity_state;
David Garcia Quintasa9cf87d2016-11-07 17:43:15 -0800591 /* renew notification: reuses the "rr_connectivity" weak ref */
592 grpc_subchannel_notify_on_state_change(
593 exec_ctx, sd->subchannel, p->base.interested_parties,
594 &sd->curr_connectivity_state, &sd->connectivity_changed_closure);
David Garcia Quintasa9cf87d2016-11-07 17:43:15 -0800595 break;
596 case GRPC_CHANNEL_IDLE:
597 ++p->num_idle;
598 /* fallthrough */
599 case GRPC_CHANNEL_CONNECTING:
600 update_state_counters(sd);
David Garcia Quintase9448df2016-11-09 15:55:17 -0800601 update_lb_connectivity_status(exec_ctx, sd, error);
602 sd->prev_connectivity_state = sd->curr_connectivity_state;
David Garcia Quintasa9cf87d2016-11-07 17:43:15 -0800603 /* renew notification: reuses the "rr_connectivity" weak ref */
604 grpc_subchannel_notify_on_state_change(
605 exec_ctx, sd->subchannel, p->base.interested_parties,
606 &sd->curr_connectivity_state, &sd->connectivity_changed_closure);
David Garcia Quintasa9cf87d2016-11-07 17:43:15 -0800607 break;
608 case GRPC_CHANNEL_TRANSIENT_FAILURE:
609 ++p->num_transient_failures;
610 /* remove from ready list if still present */
611 if (sd->ready_list_node != NULL) {
612 remove_disconnected_sc_locked(p, sd->ready_list_node);
613 sd->ready_list_node = NULL;
614 }
David Garcia Quintase9448df2016-11-09 15:55:17 -0800615 update_lb_connectivity_status(exec_ctx, sd, error);
616 sd->prev_connectivity_state = sd->curr_connectivity_state;
David Garcia Quintasa9cf87d2016-11-07 17:43:15 -0800617 /* renew notification: reuses the "rr_connectivity" weak ref */
618 grpc_subchannel_notify_on_state_change(
619 exec_ctx, sd->subchannel, p->base.interested_parties,
620 &sd->curr_connectivity_state, &sd->connectivity_changed_closure);
David Garcia Quintasa9cf87d2016-11-07 17:43:15 -0800621 break;
622 case GRPC_CHANNEL_SHUTDOWN:
623 update_state_counters(sd);
624 if (sd->ready_list_node != NULL) {
625 remove_disconnected_sc_locked(p, sd->ready_list_node);
626 sd->ready_list_node = NULL;
627 }
628 --p->num_subchannels;
629 GPR_SWAP(subchannel_data *, p->subchannels[sd->index],
630 p->subchannels[p->num_subchannels]);
631 GRPC_SUBCHANNEL_UNREF(exec_ctx, sd->subchannel, "rr_subchannel_shutdown");
632 p->subchannels[sd->index]->index = sd->index;
633 if (update_lb_connectivity_status(exec_ctx, sd, error) ==
634 GRPC_CHANNEL_SHUTDOWN) {
635 /* the policy is shutting down. Flush all the pending picks... */
Craig Tillera82950e2015-09-22 12:33:20 -0700636 while ((pp = p->pending_picks)) {
637 p->pending_picks = pp->next;
David Garcia Quintasa9cf87d2016-11-07 17:43:15 -0800638 *pp->target = NULL;
Craig Tiller91031da2016-12-28 15:44:25 -0800639 grpc_closure_sched(exec_ctx, pp->on_complete, GRPC_ERROR_NONE);
Craig Tillera82950e2015-09-22 12:33:20 -0700640 gpr_free(pp);
641 }
David Garcia Quintasa9cf87d2016-11-07 17:43:15 -0800642 }
643 gpr_free(sd);
644 /* unref the "rr_connectivity" weak ref from start_picking */
645 GRPC_LB_POLICY_WEAK_UNREF(exec_ctx, &p->base, "rr_connectivity");
646 break;
Craig Tillera82950e2015-09-22 12:33:20 -0700647 }
David Garcia Quintasa9cf87d2016-11-07 17:43:15 -0800648 gpr_mu_unlock(&p->mu);
Craig Tillerf707d622016-05-06 14:26:12 -0700649 GRPC_ERROR_UNREF(error);
David Garcia Quintas4fb049b2015-09-03 17:26:06 -0700650}
651
Craig Tillera82950e2015-09-22 12:33:20 -0700652static grpc_connectivity_state rr_check_connectivity(grpc_exec_ctx *exec_ctx,
Craig Tiller804ff712016-05-05 16:25:40 -0700653 grpc_lb_policy *pol,
654 grpc_error **error) {
Craig Tillera82950e2015-09-22 12:33:20 -0700655 round_robin_lb_policy *p = (round_robin_lb_policy *)pol;
David Garcia Quintas4fb049b2015-09-03 17:26:06 -0700656 grpc_connectivity_state st;
Craig Tillera82950e2015-09-22 12:33:20 -0700657 gpr_mu_lock(&p->mu);
Craig Tiller613dafa2017-02-09 12:00:43 -0800658 st = grpc_connectivity_state_get(&p->state_tracker, error);
Craig Tillera82950e2015-09-22 12:33:20 -0700659 gpr_mu_unlock(&p->mu);
David Garcia Quintas4fb049b2015-09-03 17:26:06 -0700660 return st;
661}
662
Craig Tillera82950e2015-09-22 12:33:20 -0700663static void rr_notify_on_state_change(grpc_exec_ctx *exec_ctx,
664 grpc_lb_policy *pol,
665 grpc_connectivity_state *current,
666 grpc_closure *notify) {
667 round_robin_lb_policy *p = (round_robin_lb_policy *)pol;
668 gpr_mu_lock(&p->mu);
669 grpc_connectivity_state_notify_on_state_change(exec_ctx, &p->state_tracker,
670 current, notify);
671 gpr_mu_unlock(&p->mu);
David Garcia Quintas4fb049b2015-09-03 17:26:06 -0700672}
673
Craig Tiller28bf8912015-12-07 16:07:04 -0800674static void rr_ping_one(grpc_exec_ctx *exec_ctx, grpc_lb_policy *pol,
675 grpc_closure *closure) {
676 round_robin_lb_policy *p = (round_robin_lb_policy *)pol;
677 ready_list *selected;
678 grpc_connected_subchannel *target;
679 gpr_mu_lock(&p->mu);
680 if ((selected = peek_next_connected_locked(p))) {
681 gpr_mu_unlock(&p->mu);
Craig Tiller693d3942016-10-27 16:51:25 -0700682 target = GRPC_CONNECTED_SUBCHANNEL_REF(
683 grpc_subchannel_get_connected_subchannel(selected->subchannel),
David Garcia Quintasa9cf87d2016-11-07 17:43:15 -0800684 "rr_picked");
Craig Tiller28bf8912015-12-07 16:07:04 -0800685 grpc_connected_subchannel_ping(exec_ctx, target, closure);
David Garcia Quintasa9cf87d2016-11-07 17:43:15 -0800686 GRPC_CONNECTED_SUBCHANNEL_UNREF(exec_ctx, target, "rr_picked");
Craig Tiller28bf8912015-12-07 16:07:04 -0800687 } else {
688 gpr_mu_unlock(&p->mu);
Craig Tiller91031da2016-12-28 15:44:25 -0800689 grpc_closure_sched(exec_ctx, closure,
690 GRPC_ERROR_CREATE("Round Robin not connected"));
Craig Tiller28bf8912015-12-07 16:07:04 -0800691 }
692}
693
David Garcia Quintas4fb049b2015-09-03 17:26:06 -0700694static const grpc_lb_policy_vtable round_robin_lb_policy_vtable = {
Craig Tillerc5ff7812016-03-28 12:45:55 -0700695 rr_destroy, rr_shutdown, rr_pick,
696 rr_cancel_pick, rr_cancel_picks, rr_ping_one,
697 rr_exit_idle, rr_check_connectivity, rr_notify_on_state_change};
David Garcia Quintas4fb049b2015-09-03 17:26:06 -0700698
Craig Tillera82950e2015-09-22 12:33:20 -0700699static void round_robin_factory_ref(grpc_lb_policy_factory *factory) {}
David Garcia Quintas4fb049b2015-09-03 17:26:06 -0700700
Craig Tillera82950e2015-09-22 12:33:20 -0700701static void round_robin_factory_unref(grpc_lb_policy_factory *factory) {}
David Garcia Quintas4fb049b2015-09-03 17:26:06 -0700702
David Garcia Quintas02008702016-06-02 21:40:45 -0700703static grpc_lb_policy *round_robin_create(grpc_exec_ctx *exec_ctx,
David Garcia Quintas67c0d042016-03-25 01:37:53 -0700704 grpc_lb_policy_factory *factory,
Craig Tillera82950e2015-09-22 12:33:20 -0700705 grpc_lb_policy_args *args) {
David Garcia Quintas86fcfcc2016-03-31 23:22:28 -0700706 GPR_ASSERT(args->client_channel_factory != NULL);
David Garcia Quintas4fb049b2015-09-03 17:26:06 -0700707
Mark D. Rothe011b1e2016-09-07 08:28:00 -0700708 /* Find the number of backend addresses. We ignore balancer
709 * addresses, since we don't know how to handle them. */
Mark D. Roth201db7d2016-12-12 09:36:02 -0800710 const grpc_arg *arg =
711 grpc_channel_args_find(args->args, GRPC_ARG_LB_ADDRESSES);
Mark D. Roth5bd7be02016-10-21 14:19:50 -0700712 GPR_ASSERT(arg != NULL && arg->type == GRPC_ARG_POINTER);
Mark D. Roth557c9902016-10-24 11:12:05 -0700713 grpc_lb_addresses *addresses = arg->value.pointer.p;
Mark D. Rothf655c852016-09-06 10:40:38 -0700714 size_t num_addrs = 0;
Mark D. Roth5bd7be02016-10-21 14:19:50 -0700715 for (size_t i = 0; i < addresses->num_addresses; i++) {
716 if (!addresses->addresses[i].is_balancer) ++num_addrs;
Mark D. Rothf655c852016-09-06 10:40:38 -0700717 }
718 if (num_addrs == 0) return NULL;
David Garcia Quintas4fb049b2015-09-03 17:26:06 -0700719
David Garcia Quintas67c0d042016-03-25 01:37:53 -0700720 round_robin_lb_policy *p = gpr_malloc(sizeof(*p));
721 memset(p, 0, sizeof(*p));
722
Mark D. Rothc5c38782016-09-16 08:51:01 -0700723 p->num_addresses = num_addrs;
Mark D. Roth989cdcd2016-09-06 13:28:28 -0700724 p->subchannels = gpr_malloc(sizeof(*p->subchannels) * num_addrs);
Mark D. Rothf655c852016-09-06 10:40:38 -0700725 memset(p->subchannels, 0, sizeof(*p->subchannels) * num_addrs);
David Garcia Quintas67c0d042016-03-25 01:37:53 -0700726
727 grpc_subchannel_args sc_args;
728 size_t subchannel_idx = 0;
Mark D. Roth5bd7be02016-10-21 14:19:50 -0700729 for (size_t i = 0; i < addresses->num_addresses; i++) {
Mark D. Rothe011b1e2016-09-07 08:28:00 -0700730 /* Skip balancer addresses, since we only know how to handle backends. */
Mark D. Roth5bd7be02016-10-21 14:19:50 -0700731 if (addresses->addresses[i].is_balancer) continue;
Mark D. Rothf655c852016-09-06 10:40:38 -0700732
David Garcia Quintas67c0d042016-03-25 01:37:53 -0700733 memset(&sc_args, 0, sizeof(grpc_subchannel_args));
Mark D. Rothdf8f1222017-01-13 22:59:39 +0000734 grpc_arg addr_arg =
735 grpc_create_subchannel_address_arg(&addresses->addresses[i].address);
Mark D. Roth0748f392017-01-13 09:22:44 -0800736 grpc_channel_args *new_args =
737 grpc_channel_args_copy_and_add(args->args, &addr_arg, 1);
738 gpr_free(addr_arg.value.string);
739 sc_args.args = new_args;
David Garcia Quintas86fcfcc2016-03-31 23:22:28 -0700740 grpc_subchannel *subchannel = grpc_client_channel_factory_create_subchannel(
741 exec_ctx, args->client_channel_factory, &sc_args);
David Garcia Quintas01291502017-02-07 13:26:41 -0800742 if (grpc_lb_round_robin_trace) {
743 char *address_uri =
744 grpc_sockaddr_to_uri(&addresses->addresses[i].address);
745 gpr_log(GPR_DEBUG, "Created subchannel %p for address uri %s",
746 (void *)subchannel, address_uri);
747 gpr_free(address_uri);
748 }
Mark D. Roth0748f392017-01-13 09:22:44 -0800749 grpc_channel_args_destroy(exec_ctx, new_args);
David Garcia Quintas67c0d042016-03-25 01:37:53 -0700750
751 if (subchannel != NULL) {
752 subchannel_data *sd = gpr_malloc(sizeof(*sd));
753 memset(sd, 0, sizeof(*sd));
754 p->subchannels[subchannel_idx] = sd;
755 sd->policy = p;
756 sd->index = subchannel_idx;
757 sd->subchannel = subchannel;
David Garcia Quintas7ec29132016-11-01 04:09:05 +0100758 sd->user_data_vtable = addresses->user_data_vtable;
David Garcia Quintas5bdcd232016-11-02 15:47:02 -0700759 if (sd->user_data_vtable != NULL) {
760 sd->user_data =
761 sd->user_data_vtable->copy(addresses->addresses[i].user_data);
762 }
David Garcia Quintas67c0d042016-03-25 01:37:53 -0700763 ++subchannel_idx;
764 grpc_closure_init(&sd->connectivity_changed_closure,
Craig Tiller91031da2016-12-28 15:44:25 -0800765 rr_connectivity_changed, sd, grpc_schedule_on_exec_ctx);
David Garcia Quintas67c0d042016-03-25 01:37:53 -0700766 }
Craig Tillera82950e2015-09-22 12:33:20 -0700767 }
David Garcia Quintas67c0d042016-03-25 01:37:53 -0700768 if (subchannel_idx == 0) {
David Garcia Quintas5b0e9462016-08-15 19:38:39 -0700769 /* couldn't create any subchannel. Bail out */
David Garcia Quintas67c0d042016-03-25 01:37:53 -0700770 gpr_free(p->subchannels);
771 gpr_free(p);
772 return NULL;
773 }
774 p->num_subchannels = subchannel_idx;
David Garcia Quintas4fb049b2015-09-03 17:26:06 -0700775
776 /* The (dummy node) root of the ready list */
777 p->ready_list.subchannel = NULL;
778 p->ready_list.prev = NULL;
779 p->ready_list.next = NULL;
780 p->ready_list_last_pick = &p->ready_list;
781
David Garcia Quintas67c0d042016-03-25 01:37:53 -0700782 grpc_lb_policy_init(&p->base, &round_robin_lb_policy_vtable);
783 grpc_connectivity_state_init(&p->state_tracker, GRPC_CHANNEL_IDLE,
784 "round_robin");
David Garcia Quintasa9cf87d2016-11-07 17:43:15 -0800785
786 if (grpc_lb_round_robin_trace) {
787 gpr_log(GPR_DEBUG, "Created RR policy at %p with %lu subchannels",
788 (void *)p, (unsigned long)p->num_subchannels);
789 }
David Garcia Quintas67c0d042016-03-25 01:37:53 -0700790 gpr_mu_init(&p->mu);
David Garcia Quintas4fb049b2015-09-03 17:26:06 -0700791 return &p->base;
792}
793
794static const grpc_lb_policy_factory_vtable round_robin_factory_vtable = {
David Garcia Quintas02008702016-06-02 21:40:45 -0700795 round_robin_factory_ref, round_robin_factory_unref, round_robin_create,
Craig Tillera82950e2015-09-22 12:33:20 -0700796 "round_robin"};
David Garcia Quintas4fb049b2015-09-03 17:26:06 -0700797
798static grpc_lb_policy_factory round_robin_lb_policy_factory = {
Craig Tillera82950e2015-09-22 12:33:20 -0700799 &round_robin_factory_vtable};
David Garcia Quintas4fb049b2015-09-03 17:26:06 -0700800
Craig Tillerfb433852016-03-29 08:51:07 -0700801static grpc_lb_policy_factory *round_robin_lb_factory_create() {
David Garcia Quintas4fb049b2015-09-03 17:26:06 -0700802 return &round_robin_lb_policy_factory;
803}
Craig Tillerfb433852016-03-29 08:51:07 -0700804
805/* Plugin registration */
806
807void grpc_lb_policy_round_robin_init() {
Craig Tiller3113ef42016-03-29 09:03:14 -0700808 grpc_register_lb_policy(round_robin_lb_factory_create());
Craig Tillerfb433852016-03-29 08:51:07 -0700809 grpc_register_tracer("round_robin", &grpc_lb_round_robin_trace);
810}
811
812void grpc_lb_policy_round_robin_shutdown() {}