blob: 687df170ad7975d9a44489acd828dd6eac6723ba [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"
Craig Tiller2400bf52017-02-09 16:25:19 -080070#include "src/core/lib/iomgr/combiner.h"
Mark D. Roth0748f392017-01-13 09:22:44 -080071#include "src/core/lib/iomgr/sockaddr_utils.h"
Craig Tiller9533d042016-03-25 17:11:06 -070072#include "src/core/lib/transport/connectivity_state.h"
David Garcia Quintas5b0e9462016-08-15 19:38:39 -070073#include "src/core/lib/transport/static_metadata.h"
David Garcia Quintas4fb049b2015-09-03 17:26:06 -070074
Craig Tillere2a65102015-11-30 17:51:49 -080075typedef struct round_robin_lb_policy round_robin_lb_policy;
76
David Garcia Quintas4fb049b2015-09-03 17:26:06 -070077int grpc_lb_round_robin_trace = 0;
78
79/** List of entities waiting for a pick.
80 *
81 * Once a pick is available, \a target is updated and \a on_complete called. */
Craig Tillera82950e2015-09-22 12:33:20 -070082typedef struct pending_pick {
David Garcia Quintas4fb049b2015-09-03 17:26:06 -070083 struct pending_pick *next;
David Garcia Quintas5b0e9462016-08-15 19:38:39 -070084
David Garcia Quintas331b9c02016-09-12 18:37:05 -070085 /* output argument where to store the pick()ed user_data. It'll be NULL if no
86 * such data is present or there's an error (the definite test for errors is
87 * \a target being NULL). */
88 void **user_data;
David Garcia Quintas5b0e9462016-08-15 19:38:39 -070089
90 /* bitmask passed to pick() and used for selective cancelling. See
91 * grpc_lb_policy_cancel_picks() */
Craig Tiller8c0d96f2016-03-11 14:27:52 -080092 uint32_t initial_metadata_flags;
David Garcia Quintas5b0e9462016-08-15 19:38:39 -070093
94 /* output argument where to store the pick()ed connected subchannel, or NULL
95 * upon error. */
Craig Tillerb5585d42015-11-17 07:18:31 -080096 grpc_connected_subchannel **target;
David Garcia Quintas5b0e9462016-08-15 19:38:39 -070097
98 /* to be invoked once the pick() has completed (regardless of success) */
Craig Tiller10ee2742015-09-22 09:25:57 -070099 grpc_closure *on_complete;
David Garcia Quintas4fb049b2015-09-03 17:26:06 -0700100} pending_pick;
101
102/** List of subchannels in a connectivity READY state */
Craig Tillera82950e2015-09-22 12:33:20 -0700103typedef struct ready_list {
David Garcia Quintas4fb049b2015-09-03 17:26:06 -0700104 grpc_subchannel *subchannel;
David Garcia Quintas5b0e9462016-08-15 19:38:39 -0700105 /* references namesake entry in subchannel_data */
David Garcia Quintas331b9c02016-09-12 18:37:05 -0700106 void *user_data;
David Garcia Quintas4fb049b2015-09-03 17:26:06 -0700107 struct ready_list *next;
108 struct ready_list *prev;
109} ready_list;
110
Craig Tillera82950e2015-09-22 12:33:20 -0700111typedef struct {
Craig Tillere2a65102015-11-30 17:51:49 -0800112 /** index within policy->subchannels */
113 size_t index;
114 /** backpointer to owning policy */
115 round_robin_lb_policy *policy;
116 /** subchannel itself */
117 grpc_subchannel *subchannel;
118 /** notification that connectivity has changed on subchannel */
119 grpc_closure connectivity_changed_closure;
120 /** this subchannels current position in subchannel->ready_list */
121 ready_list *ready_list_node;
David Garcia Quintasa9cf87d2016-11-07 17:43:15 -0800122 /** last observed connectivity. Not updated by
123 * \a grpc_subchannel_notify_on_state_change. Used to determine the previous
124 * state while processing the new state in \a rr_connectivity_changed */
125 grpc_connectivity_state prev_connectivity_state;
126 /** current connectivity state. Updated by \a
127 * grpc_subchannel_notify_on_state_change */
128 grpc_connectivity_state curr_connectivity_state;
David Garcia Quintas331b9c02016-09-12 18:37:05 -0700129 /** the subchannel's target user data */
130 void *user_data;
David Garcia Quintas98da61b2016-10-29 08:46:31 +0200131 /** vtable to operate over \a user_data */
David Garcia Quintas7ec29132016-11-01 04:09:05 +0100132 const grpc_lb_user_data_vtable *user_data_vtable;
Craig Tillere2a65102015-11-30 17:51:49 -0800133} subchannel_data;
David Garcia Quintas4fb049b2015-09-03 17:26:06 -0700134
Craig Tillere2a65102015-11-30 17:51:49 -0800135struct round_robin_lb_policy {
David Garcia Quintas4fb049b2015-09-03 17:26:06 -0700136 /** base policy: must be first */
137 grpc_lb_policy base;
138
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);
David Garcia Quintas4fb049b2015-09-03 17:26:06 -0700296
297 elem = p->ready_list.next;
Craig Tillera82950e2015-09-22 12:33:20 -0700298 while (elem != NULL && elem != &p->ready_list) {
299 ready_list *tmp;
300 tmp = elem->next;
301 elem->next = NULL;
302 elem->prev = NULL;
303 elem->subchannel = NULL;
304 gpr_free(elem);
305 elem = tmp;
306 }
David Garcia Quintas5b0e9462016-08-15 19:38:39 -0700307
Craig Tillera82950e2015-09-22 12:33:20 -0700308 gpr_free(p);
David Garcia Quintas4fb049b2015-09-03 17:26:06 -0700309}
310
Craig Tiller2400bf52017-02-09 16:25:19 -0800311static void rr_shutdown_locked(grpc_exec_ctx *exec_ctx, grpc_lb_policy *pol) {
Craig Tillera82950e2015-09-22 12:33:20 -0700312 round_robin_lb_policy *p = (round_robin_lb_policy *)pol;
David Garcia Quintas4fb049b2015-09-03 17:26:06 -0700313 pending_pick *pp;
Craig Tiller2a1bb7f2015-11-29 21:54:26 -0800314 size_t i;
315
David Garcia Quintas98da61b2016-10-29 08:46:31 +0200316 if (grpc_lb_round_robin_trace) {
David Garcia Quintas7ec29132016-11-01 04:09:05 +0100317 gpr_log(GPR_DEBUG, "Shutting down Round Robin policy at %p", (void *)pol);
David Garcia Quintas98da61b2016-10-29 08:46:31 +0200318 }
David Garcia Quintas4fb049b2015-09-03 17:26:06 -0700319
320 p->shutdown = 1;
Craig Tillera82950e2015-09-22 12:33:20 -0700321 while ((pp = p->pending_picks)) {
322 p->pending_picks = pp->next;
323 *pp->target = NULL;
Craig Tiller91031da2016-12-28 15:44:25 -0800324 grpc_closure_sched(exec_ctx, pp->on_complete,
325 GRPC_ERROR_CREATE("Channel Shutdown"));
Craig Tillera82950e2015-09-22 12:33:20 -0700326 gpr_free(pp);
327 }
Craig Tiller804ff712016-05-05 16:25:40 -0700328 grpc_connectivity_state_set(
Craig Tillerd925c932016-06-06 08:38:50 -0700329 exec_ctx, &p->state_tracker, GRPC_CHANNEL_SHUTDOWN,
David Garcia Quintas98da61b2016-10-29 08:46:31 +0200330 GRPC_ERROR_CREATE("Channel Shutdown"), "rr_shutdown");
Craig Tiller2a1bb7f2015-11-29 21:54:26 -0800331 for (i = 0; i < p->num_subchannels; i++) {
Craig Tillere2a65102015-11-30 17:51:49 -0800332 subchannel_data *sd = p->subchannels[i];
Craig Tiller1d881fb2015-12-01 07:39:04 -0800333 grpc_subchannel_notify_on_state_change(exec_ctx, sd->subchannel, NULL, NULL,
Craig Tillere2a65102015-11-30 17:51:49 -0800334 &sd->connectivity_changed_closure);
Craig Tiller2a1bb7f2015-11-29 21:54:26 -0800335 }
David Garcia Quintas4fb049b2015-09-03 17:26:06 -0700336}
337
Craig Tiller2400bf52017-02-09 16:25:19 -0800338static void rr_cancel_pick_locked(grpc_exec_ctx *exec_ctx, grpc_lb_policy *pol,
339 grpc_connected_subchannel **target,
340 grpc_error *error) {
Craig Tiller577c9b22015-11-02 14:11:15 -0800341 round_robin_lb_policy *p = (round_robin_lb_policy *)pol;
342 pending_pick *pp;
Craig Tiller577c9b22015-11-02 14:11:15 -0800343 pp = p->pending_picks;
344 p->pending_picks = NULL;
345 while (pp != NULL) {
346 pending_pick *next = pp->next;
347 if (pp->target == target) {
Craig Tiller577c9b22015-11-02 14:11:15 -0800348 *target = NULL;
Craig Tiller91031da2016-12-28 15:44:25 -0800349 grpc_closure_sched(
Mark D. Roth932b10c2016-09-09 08:44:30 -0700350 exec_ctx, pp->on_complete,
Craig Tiller91031da2016-12-28 15:44:25 -0800351 GRPC_ERROR_CREATE_REFERENCING("Pick cancelled", &error, 1));
Craig Tiller577c9b22015-11-02 14:11:15 -0800352 gpr_free(pp);
353 } else {
354 pp->next = p->pending_picks;
355 p->pending_picks = pp;
356 }
357 pp = next;
358 }
Mark D. Roth5f844002016-09-08 08:20:53 -0700359 GRPC_ERROR_UNREF(error);
Craig Tiller577c9b22015-11-02 14:11:15 -0800360}
361
Craig Tiller2400bf52017-02-09 16:25:19 -0800362static void rr_cancel_picks_locked(grpc_exec_ctx *exec_ctx, grpc_lb_policy *pol,
363 uint32_t initial_metadata_flags_mask,
364 uint32_t initial_metadata_flags_eq,
365 grpc_error *error) {
Craig Tiller8c0d96f2016-03-11 14:27:52 -0800366 round_robin_lb_policy *p = (round_robin_lb_policy *)pol;
367 pending_pick *pp;
Craig Tiller8c0d96f2016-03-11 14:27:52 -0800368 pp = p->pending_picks;
369 p->pending_picks = NULL;
370 while (pp != NULL) {
371 pending_pick *next = pp->next;
372 if ((pp->initial_metadata_flags & initial_metadata_flags_mask) ==
373 initial_metadata_flags_eq) {
Craig Tiller8c0d96f2016-03-11 14:27:52 -0800374 *pp->target = NULL;
Craig Tiller91031da2016-12-28 15:44:25 -0800375 grpc_closure_sched(
Mark D. Roth58f52b72016-09-09 13:55:18 -0700376 exec_ctx, pp->on_complete,
Craig Tiller91031da2016-12-28 15:44:25 -0800377 GRPC_ERROR_CREATE_REFERENCING("Pick cancelled", &error, 1));
Craig Tiller8c0d96f2016-03-11 14:27:52 -0800378 gpr_free(pp);
379 } else {
380 pp->next = p->pending_picks;
381 p->pending_picks = pp;
382 }
383 pp = next;
384 }
Mark D. Rothe65ff112016-09-09 13:48:38 -0700385 GRPC_ERROR_UNREF(error);
Craig Tiller8c0d96f2016-03-11 14:27:52 -0800386}
387
Craig Tiller2400bf52017-02-09 16:25:19 -0800388static void start_picking_locked(grpc_exec_ctx *exec_ctx,
389 round_robin_lb_policy *p) {
David Garcia Quintas4fb049b2015-09-03 17:26:06 -0700390 size_t i;
391 p->started_picking = 1;
392
Craig Tillera82950e2015-09-22 12:33:20 -0700393 for (i = 0; i < p->num_subchannels; i++) {
Craig Tillere2a65102015-11-30 17:51:49 -0800394 subchannel_data *sd = p->subchannels[i];
David Garcia Quintasa9cf87d2016-11-07 17:43:15 -0800395 /* use some sentinel value outside of the range of grpc_connectivity_state
396 * to signal an undefined previous state. We won't be referring to this
397 * value again and it'll be overwritten after the first call to
398 * rr_connectivity_changed */
David Garcia Quintasea6689d2016-11-08 09:46:41 -0800399 sd->prev_connectivity_state = GRPC_CHANNEL_INIT;
David Garcia Quintasa9cf87d2016-11-07 17:43:15 -0800400 sd->curr_connectivity_state = GRPC_CHANNEL_IDLE;
401 GRPC_LB_POLICY_WEAK_REF(&p->base, "rr_connectivity");
Craig Tiller1d881fb2015-12-01 07:39:04 -0800402 grpc_subchannel_notify_on_state_change(
Craig Tiller69b093b2016-02-25 19:04:07 -0800403 exec_ctx, sd->subchannel, p->base.interested_parties,
David Garcia Quintasa9cf87d2016-11-07 17:43:15 -0800404 &sd->curr_connectivity_state, &sd->connectivity_changed_closure);
Craig Tillera82950e2015-09-22 12:33:20 -0700405 }
David Garcia Quintas4fb049b2015-09-03 17:26:06 -0700406}
407
Craig Tiller2400bf52017-02-09 16:25:19 -0800408static void rr_exit_idle_locked(grpc_exec_ctx *exec_ctx, grpc_lb_policy *pol) {
Craig Tillera82950e2015-09-22 12:33:20 -0700409 round_robin_lb_policy *p = (round_robin_lb_policy *)pol;
Craig Tillera82950e2015-09-22 12:33:20 -0700410 if (!p->started_picking) {
Craig Tiller2400bf52017-02-09 16:25:19 -0800411 start_picking_locked(exec_ctx, p);
Craig Tillera82950e2015-09-22 12:33:20 -0700412 }
David Garcia Quintas4fb049b2015-09-03 17:26:06 -0700413}
414
Craig Tiller2400bf52017-02-09 16:25:19 -0800415static int rr_pick_locked(grpc_exec_ctx *exec_ctx, grpc_lb_policy *pol,
416 const grpc_lb_policy_pick_args *pick_args,
417 grpc_connected_subchannel **target, void **user_data,
418 grpc_closure *on_complete) {
Craig Tillera82950e2015-09-22 12:33:20 -0700419 round_robin_lb_policy *p = (round_robin_lb_policy *)pol;
David Garcia Quintas4fb049b2015-09-03 17:26:06 -0700420 pending_pick *pp;
421 ready_list *selected;
David Garcia Quintas98da61b2016-10-29 08:46:31 +0200422
423 if (grpc_lb_round_robin_trace) {
David Garcia Quintas7ec29132016-11-01 04:09:05 +0100424 gpr_log(GPR_INFO, "Round Robin %p trying to pick", (void *)pol);
David Garcia Quintas98da61b2016-10-29 08:46:31 +0200425 }
426
Craig Tillera82950e2015-09-22 12:33:20 -0700427 if ((selected = peek_next_connected_locked(p))) {
David Garcia Quintas5b0e9462016-08-15 19:38:39 -0700428 /* readily available, report right away */
Craig Tiller693d3942016-10-27 16:51:25 -0700429 *target = GRPC_CONNECTED_SUBCHANNEL_REF(
430 grpc_subchannel_get_connected_subchannel(selected->subchannel),
David Garcia Quintase9448df2016-11-09 15:55:17 -0800431 "rr_picked");
David Garcia Quintas155b8202016-09-15 16:14:15 -0700432
433 if (user_data != NULL) {
434 *user_data = selected->user_data;
435 }
Craig Tillera82950e2015-09-22 12:33:20 -0700436 if (grpc_lb_round_robin_trace) {
Craig Tillerab33b482015-11-21 08:11:04 -0800437 gpr_log(GPR_DEBUG,
David Garcia Quintas5b0e9462016-08-15 19:38:39 -0700438 "[RR PICK] TARGET <-- CONNECTED SUBCHANNEL %p (NODE %p)",
439 (void *)*target, (void *)selected);
David Garcia Quintas4fb049b2015-09-03 17:26:06 -0700440 }
Craig Tillera82950e2015-09-22 12:33:20 -0700441 /* only advance the last picked pointer if the selection was used */
442 advance_last_picked_locked(p);
Craig Tiller577c9b22015-11-02 14:11:15 -0800443 return 1;
Craig Tillera82950e2015-09-22 12:33:20 -0700444 } else {
David Garcia Quintas5b0e9462016-08-15 19:38:39 -0700445 /* no pick currently available. Save for later in list of pending picks */
Craig Tillera82950e2015-09-22 12:33:20 -0700446 if (!p->started_picking) {
Craig Tiller2400bf52017-02-09 16:25:19 -0800447 start_picking_locked(exec_ctx, p);
David Garcia Quintas4fb049b2015-09-03 17:26:06 -0700448 }
Craig Tillera82950e2015-09-22 12:33:20 -0700449 pp = gpr_malloc(sizeof(*pp));
450 pp->next = p->pending_picks;
Craig Tillera82950e2015-09-22 12:33:20 -0700451 pp->target = target;
452 pp->on_complete = on_complete;
David Garcia Quintas8aace512016-08-15 14:55:12 -0700453 pp->initial_metadata_flags = pick_args->initial_metadata_flags;
David Garcia Quintas331b9c02016-09-12 18:37:05 -0700454 pp->user_data = user_data;
Craig Tillera82950e2015-09-22 12:33:20 -0700455 p->pending_picks = pp;
Craig Tiller577c9b22015-11-02 14:11:15 -0800456 return 0;
Craig Tillera82950e2015-09-22 12:33:20 -0700457 }
David Garcia Quintas4fb049b2015-09-03 17:26:06 -0700458}
459
David Garcia Quintasa9cf87d2016-11-07 17:43:15 -0800460static void update_state_counters(subchannel_data *sd) {
461 round_robin_lb_policy *p = sd->policy;
462
463 /* update p->num_transient_failures (resp. p->num_idle): if the previous
464 * state was TRANSIENT_FAILURE (resp. IDLE), decrement
465 * p->num_transient_failures (resp. p->num_idle). */
466 if (sd->prev_connectivity_state == GRPC_CHANNEL_TRANSIENT_FAILURE) {
467 GPR_ASSERT(p->num_transient_failures > 0);
468 --p->num_transient_failures;
469 } else if (sd->prev_connectivity_state == GRPC_CHANNEL_IDLE) {
470 GPR_ASSERT(p->num_idle > 0);
471 --p->num_idle;
472 }
473}
474
475/* sd is the subchannel_data associted with the updated subchannel.
476 * shutdown_error will only be used upon policy transition to TRANSIENT_FAILURE
477 * or SHUTDOWN */
478static grpc_connectivity_state update_lb_connectivity_status(
479 grpc_exec_ctx *exec_ctx, subchannel_data *sd, grpc_error *error) {
480 /* In priority order. The first rule to match terminates the search (ie, if we
481 * are on rule n, all previous rules were unfulfilled).
482 *
483 * 1) RULE: ANY subchannel is READY => policy is READY.
484 * CHECK: At least one subchannel is ready iff p->ready_list is NOT empty.
485 *
486 * 2) RULE: ANY subchannel is CONNECTING => policy is CONNECTING.
487 * CHECK: sd->curr_connectivity_state == CONNECTING.
488 *
489 * 3) RULE: ALL subchannels are SHUTDOWN => policy is SHUTDOWN.
490 * CHECK: p->num_subchannels = 0.
491 *
492 * 4) RULE: ALL subchannels are TRANSIENT_FAILURE => policy is
493 * TRANSIENT_FAILURE.
494 * CHECK: p->num_transient_failures == p->num_subchannels.
495 *
496 * 5) RULE: ALL subchannels are IDLE => policy is IDLE.
497 * CHECK: p->num_idle == p->num_subchannels.
498 */
499 round_robin_lb_policy *p = sd->policy;
500 if (!is_ready_list_empty(p)) { /* 1) READY */
501 grpc_connectivity_state_set(exec_ctx, &p->state_tracker, GRPC_CHANNEL_READY,
502 GRPC_ERROR_NONE, "rr_ready");
503 return GRPC_CHANNEL_READY;
504 } else if (sd->curr_connectivity_state ==
505 GRPC_CHANNEL_CONNECTING) { /* 2) CONNECTING */
506 grpc_connectivity_state_set(exec_ctx, &p->state_tracker,
507 GRPC_CHANNEL_CONNECTING, GRPC_ERROR_NONE,
508 "rr_connecting");
509 return GRPC_CHANNEL_CONNECTING;
510 } else if (p->num_subchannels == 0) { /* 3) SHUTDOWN */
511 grpc_connectivity_state_set(exec_ctx, &p->state_tracker,
512 GRPC_CHANNEL_SHUTDOWN, GRPC_ERROR_REF(error),
513 "rr_shutdown");
514 return GRPC_CHANNEL_SHUTDOWN;
515 } else if (p->num_transient_failures ==
516 p->num_subchannels) { /* 4) TRANSIENT_FAILURE */
517 grpc_connectivity_state_set(exec_ctx, &p->state_tracker,
518 GRPC_CHANNEL_TRANSIENT_FAILURE,
519 GRPC_ERROR_REF(error), "rr_transient_failure");
520 return GRPC_CHANNEL_TRANSIENT_FAILURE;
521 } else if (p->num_idle == p->num_subchannels) { /* 5) IDLE */
522 grpc_connectivity_state_set(exec_ctx, &p->state_tracker, GRPC_CHANNEL_IDLE,
523 GRPC_ERROR_NONE, "rr_idle");
524 return GRPC_CHANNEL_IDLE;
525 }
526 /* no change */
527 return sd->curr_connectivity_state;
528}
529
Craig Tiller2400bf52017-02-09 16:25:19 -0800530static void rr_connectivity_changed_locked(grpc_exec_ctx *exec_ctx, void *arg,
531 grpc_error *error) {
Craig Tillere2a65102015-11-30 17:51:49 -0800532 subchannel_data *sd = arg;
533 round_robin_lb_policy *p = sd->policy;
David Garcia Quintas4fb049b2015-09-03 17:26:06 -0700534 pending_pick *pp;
David Garcia Quintas4fb049b2015-09-03 17:26:06 -0700535
Craig Tillerf707d622016-05-06 14:26:12 -0700536 GRPC_ERROR_REF(error);
David Garcia Quintas4fb049b2015-09-03 17:26:06 -0700537
Craig Tillera82950e2015-09-22 12:33:20 -0700538 if (p->shutdown) {
David Garcia Quintasa9cf87d2016-11-07 17:43:15 -0800539 GRPC_LB_POLICY_WEAK_UNREF(exec_ctx, &p->base, "rr_connectivity");
540 GRPC_ERROR_UNREF(error);
541 return;
542 }
543 switch (sd->curr_connectivity_state) {
David Garcia Quintasea6689d2016-11-08 09:46:41 -0800544 case GRPC_CHANNEL_INIT:
Jan Tattermuschb0fb2d22016-11-16 14:04:05 +0100545 GPR_UNREACHABLE_CODE(return );
David Garcia Quintasa9cf87d2016-11-07 17:43:15 -0800546 case GRPC_CHANNEL_READY:
547 /* add the newly connected subchannel to the list of connected ones.
548 * Note that it goes to the "end of the line". */
549 sd->ready_list_node = add_connected_sc_locked(p, sd);
550 /* at this point we know there's at least one suitable subchannel. Go
551 * ahead and pick one and notify the pending suitors in
552 * p->pending_picks. This preemtively replicates rr_pick()'s actions. */
553 ready_list *selected = peek_next_connected_locked(p);
554 GPR_ASSERT(selected != NULL);
555 if (p->pending_picks != NULL) {
556 /* if the selected subchannel is going to be used for the pending
557 * picks, update the last picked pointer */
558 advance_last_picked_locked(p);
559 }
560 while ((pp = p->pending_picks)) {
561 p->pending_picks = pp->next;
562 *pp->target = GRPC_CONNECTED_SUBCHANNEL_REF(
563 grpc_subchannel_get_connected_subchannel(selected->subchannel),
564 "rr_picked");
565 if (pp->user_data != NULL) {
566 *pp->user_data = selected->user_data;
Craig Tillera82950e2015-09-22 12:33:20 -0700567 }
David Garcia Quintasa9cf87d2016-11-07 17:43:15 -0800568 if (grpc_lb_round_robin_trace) {
569 gpr_log(GPR_DEBUG,
570 "[RR CONN CHANGED] TARGET <-- SUBCHANNEL %p (NODE %p)",
571 (void *)selected->subchannel, (void *)selected);
572 }
Craig Tiller91031da2016-12-28 15:44:25 -0800573 grpc_closure_sched(exec_ctx, pp->on_complete, GRPC_ERROR_NONE);
David Garcia Quintasa9cf87d2016-11-07 17:43:15 -0800574 gpr_free(pp);
575 }
David Garcia Quintase9448df2016-11-09 15:55:17 -0800576 update_lb_connectivity_status(exec_ctx, sd, error);
577 sd->prev_connectivity_state = sd->curr_connectivity_state;
David Garcia Quintasa9cf87d2016-11-07 17:43:15 -0800578 /* renew notification: reuses the "rr_connectivity" weak ref */
579 grpc_subchannel_notify_on_state_change(
580 exec_ctx, sd->subchannel, p->base.interested_parties,
581 &sd->curr_connectivity_state, &sd->connectivity_changed_closure);
David Garcia Quintasa9cf87d2016-11-07 17:43:15 -0800582 break;
583 case GRPC_CHANNEL_IDLE:
584 ++p->num_idle;
585 /* fallthrough */
586 case GRPC_CHANNEL_CONNECTING:
587 update_state_counters(sd);
David Garcia Quintase9448df2016-11-09 15:55:17 -0800588 update_lb_connectivity_status(exec_ctx, sd, error);
589 sd->prev_connectivity_state = sd->curr_connectivity_state;
David Garcia Quintasa9cf87d2016-11-07 17:43:15 -0800590 /* renew notification: reuses the "rr_connectivity" weak ref */
591 grpc_subchannel_notify_on_state_change(
592 exec_ctx, sd->subchannel, p->base.interested_parties,
593 &sd->curr_connectivity_state, &sd->connectivity_changed_closure);
David Garcia Quintasa9cf87d2016-11-07 17:43:15 -0800594 break;
595 case GRPC_CHANNEL_TRANSIENT_FAILURE:
596 ++p->num_transient_failures;
597 /* remove from ready list if still present */
598 if (sd->ready_list_node != NULL) {
599 remove_disconnected_sc_locked(p, sd->ready_list_node);
600 sd->ready_list_node = NULL;
601 }
David Garcia Quintase9448df2016-11-09 15:55:17 -0800602 update_lb_connectivity_status(exec_ctx, sd, error);
603 sd->prev_connectivity_state = sd->curr_connectivity_state;
David Garcia Quintasa9cf87d2016-11-07 17:43:15 -0800604 /* renew notification: reuses the "rr_connectivity" weak ref */
605 grpc_subchannel_notify_on_state_change(
606 exec_ctx, sd->subchannel, p->base.interested_parties,
607 &sd->curr_connectivity_state, &sd->connectivity_changed_closure);
David Garcia Quintasa9cf87d2016-11-07 17:43:15 -0800608 break;
609 case GRPC_CHANNEL_SHUTDOWN:
610 update_state_counters(sd);
611 if (sd->ready_list_node != NULL) {
612 remove_disconnected_sc_locked(p, sd->ready_list_node);
613 sd->ready_list_node = NULL;
614 }
615 --p->num_subchannels;
616 GPR_SWAP(subchannel_data *, p->subchannels[sd->index],
617 p->subchannels[p->num_subchannels]);
618 GRPC_SUBCHANNEL_UNREF(exec_ctx, sd->subchannel, "rr_subchannel_shutdown");
619 p->subchannels[sd->index]->index = sd->index;
620 if (update_lb_connectivity_status(exec_ctx, sd, error) ==
621 GRPC_CHANNEL_SHUTDOWN) {
622 /* the policy is shutting down. Flush all the pending picks... */
Craig Tillera82950e2015-09-22 12:33:20 -0700623 while ((pp = p->pending_picks)) {
624 p->pending_picks = pp->next;
David Garcia Quintasa9cf87d2016-11-07 17:43:15 -0800625 *pp->target = NULL;
Craig Tiller91031da2016-12-28 15:44:25 -0800626 grpc_closure_sched(exec_ctx, pp->on_complete, GRPC_ERROR_NONE);
Craig Tillera82950e2015-09-22 12:33:20 -0700627 gpr_free(pp);
628 }
David Garcia Quintasa9cf87d2016-11-07 17:43:15 -0800629 }
630 gpr_free(sd);
631 /* unref the "rr_connectivity" weak ref from start_picking */
632 GRPC_LB_POLICY_WEAK_UNREF(exec_ctx, &p->base, "rr_connectivity");
633 break;
Craig Tillera82950e2015-09-22 12:33:20 -0700634 }
Craig Tillerf707d622016-05-06 14:26:12 -0700635 GRPC_ERROR_UNREF(error);
David Garcia Quintas4fb049b2015-09-03 17:26:06 -0700636}
637
Craig Tiller2400bf52017-02-09 16:25:19 -0800638static grpc_connectivity_state rr_check_connectivity_locked(
639 grpc_exec_ctx *exec_ctx, grpc_lb_policy *pol, grpc_error **error) {
Craig Tillera82950e2015-09-22 12:33:20 -0700640 round_robin_lb_policy *p = (round_robin_lb_policy *)pol;
Craig Tiller2400bf52017-02-09 16:25:19 -0800641 return grpc_connectivity_state_get(&p->state_tracker, error);
David Garcia Quintas4fb049b2015-09-03 17:26:06 -0700642}
643
Craig Tiller2400bf52017-02-09 16:25:19 -0800644static void rr_notify_on_state_change_locked(grpc_exec_ctx *exec_ctx,
645 grpc_lb_policy *pol,
646 grpc_connectivity_state *current,
647 grpc_closure *notify) {
Craig Tillera82950e2015-09-22 12:33:20 -0700648 round_robin_lb_policy *p = (round_robin_lb_policy *)pol;
Craig Tillera82950e2015-09-22 12:33:20 -0700649 grpc_connectivity_state_notify_on_state_change(exec_ctx, &p->state_tracker,
650 current, notify);
David Garcia Quintas4fb049b2015-09-03 17:26:06 -0700651}
652
Craig Tiller2400bf52017-02-09 16:25:19 -0800653static void rr_ping_one_locked(grpc_exec_ctx *exec_ctx, grpc_lb_policy *pol,
654 grpc_closure *closure) {
Craig Tiller28bf8912015-12-07 16:07:04 -0800655 round_robin_lb_policy *p = (round_robin_lb_policy *)pol;
656 ready_list *selected;
657 grpc_connected_subchannel *target;
Craig Tiller28bf8912015-12-07 16:07:04 -0800658 if ((selected = peek_next_connected_locked(p))) {
Craig Tiller693d3942016-10-27 16:51:25 -0700659 target = GRPC_CONNECTED_SUBCHANNEL_REF(
660 grpc_subchannel_get_connected_subchannel(selected->subchannel),
David Garcia Quintasa9cf87d2016-11-07 17:43:15 -0800661 "rr_picked");
Craig Tiller28bf8912015-12-07 16:07:04 -0800662 grpc_connected_subchannel_ping(exec_ctx, target, closure);
David Garcia Quintasa9cf87d2016-11-07 17:43:15 -0800663 GRPC_CONNECTED_SUBCHANNEL_UNREF(exec_ctx, target, "rr_picked");
Craig Tiller28bf8912015-12-07 16:07:04 -0800664 } else {
Craig Tiller91031da2016-12-28 15:44:25 -0800665 grpc_closure_sched(exec_ctx, closure,
666 GRPC_ERROR_CREATE("Round Robin not connected"));
Craig Tiller28bf8912015-12-07 16:07:04 -0800667 }
668}
669
David Garcia Quintas4fb049b2015-09-03 17:26:06 -0700670static const grpc_lb_policy_vtable round_robin_lb_policy_vtable = {
Craig Tiller2400bf52017-02-09 16:25:19 -0800671 rr_destroy,
672 rr_shutdown_locked,
673 rr_pick_locked,
674 rr_cancel_pick_locked,
675 rr_cancel_picks_locked,
676 rr_ping_one_locked,
677 rr_exit_idle_locked,
678 rr_check_connectivity_locked,
679 rr_notify_on_state_change_locked};
David Garcia Quintas4fb049b2015-09-03 17:26:06 -0700680
Craig Tillera82950e2015-09-22 12:33:20 -0700681static void round_robin_factory_ref(grpc_lb_policy_factory *factory) {}
David Garcia Quintas4fb049b2015-09-03 17:26:06 -0700682
Craig Tillera82950e2015-09-22 12:33:20 -0700683static void round_robin_factory_unref(grpc_lb_policy_factory *factory) {}
David Garcia Quintas4fb049b2015-09-03 17:26:06 -0700684
David Garcia Quintas02008702016-06-02 21:40:45 -0700685static grpc_lb_policy *round_robin_create(grpc_exec_ctx *exec_ctx,
David Garcia Quintas67c0d042016-03-25 01:37:53 -0700686 grpc_lb_policy_factory *factory,
Craig Tillera82950e2015-09-22 12:33:20 -0700687 grpc_lb_policy_args *args) {
David Garcia Quintas86fcfcc2016-03-31 23:22:28 -0700688 GPR_ASSERT(args->client_channel_factory != NULL);
David Garcia Quintas4fb049b2015-09-03 17:26:06 -0700689
Mark D. Rothe011b1e2016-09-07 08:28:00 -0700690 /* Find the number of backend addresses. We ignore balancer
691 * addresses, since we don't know how to handle them. */
Mark D. Roth201db7d2016-12-12 09:36:02 -0800692 const grpc_arg *arg =
693 grpc_channel_args_find(args->args, GRPC_ARG_LB_ADDRESSES);
Mark D. Roth5bd7be02016-10-21 14:19:50 -0700694 GPR_ASSERT(arg != NULL && arg->type == GRPC_ARG_POINTER);
Mark D. Roth557c9902016-10-24 11:12:05 -0700695 grpc_lb_addresses *addresses = arg->value.pointer.p;
Mark D. Rothf655c852016-09-06 10:40:38 -0700696 size_t num_addrs = 0;
Mark D. Roth5bd7be02016-10-21 14:19:50 -0700697 for (size_t i = 0; i < addresses->num_addresses; i++) {
698 if (!addresses->addresses[i].is_balancer) ++num_addrs;
Mark D. Rothf655c852016-09-06 10:40:38 -0700699 }
700 if (num_addrs == 0) return NULL;
David Garcia Quintas4fb049b2015-09-03 17:26:06 -0700701
David Garcia Quintas67c0d042016-03-25 01:37:53 -0700702 round_robin_lb_policy *p = gpr_malloc(sizeof(*p));
703 memset(p, 0, sizeof(*p));
704
Mark D. Rothc5c38782016-09-16 08:51:01 -0700705 p->num_addresses = num_addrs;
Mark D. Roth989cdcd2016-09-06 13:28:28 -0700706 p->subchannels = gpr_malloc(sizeof(*p->subchannels) * num_addrs);
Mark D. Rothf655c852016-09-06 10:40:38 -0700707 memset(p->subchannels, 0, sizeof(*p->subchannels) * num_addrs);
David Garcia Quintas67c0d042016-03-25 01:37:53 -0700708
709 grpc_subchannel_args sc_args;
710 size_t subchannel_idx = 0;
Mark D. Roth5bd7be02016-10-21 14:19:50 -0700711 for (size_t i = 0; i < addresses->num_addresses; i++) {
Mark D. Rothe011b1e2016-09-07 08:28:00 -0700712 /* Skip balancer addresses, since we only know how to handle backends. */
Mark D. Roth5bd7be02016-10-21 14:19:50 -0700713 if (addresses->addresses[i].is_balancer) continue;
Mark D. Rothf655c852016-09-06 10:40:38 -0700714
David Garcia Quintas67c0d042016-03-25 01:37:53 -0700715 memset(&sc_args, 0, sizeof(grpc_subchannel_args));
Mark D. Rothdf8f1222017-01-13 22:59:39 +0000716 grpc_arg addr_arg =
717 grpc_create_subchannel_address_arg(&addresses->addresses[i].address);
Mark D. Roth0748f392017-01-13 09:22:44 -0800718 grpc_channel_args *new_args =
719 grpc_channel_args_copy_and_add(args->args, &addr_arg, 1);
720 gpr_free(addr_arg.value.string);
721 sc_args.args = new_args;
David Garcia Quintas86fcfcc2016-03-31 23:22:28 -0700722 grpc_subchannel *subchannel = grpc_client_channel_factory_create_subchannel(
723 exec_ctx, args->client_channel_factory, &sc_args);
David Garcia Quintas01291502017-02-07 13:26:41 -0800724 if (grpc_lb_round_robin_trace) {
725 char *address_uri =
726 grpc_sockaddr_to_uri(&addresses->addresses[i].address);
727 gpr_log(GPR_DEBUG, "Created subchannel %p for address uri %s",
728 (void *)subchannel, address_uri);
729 gpr_free(address_uri);
730 }
Mark D. Roth0748f392017-01-13 09:22:44 -0800731 grpc_channel_args_destroy(exec_ctx, new_args);
David Garcia Quintas67c0d042016-03-25 01:37:53 -0700732
733 if (subchannel != NULL) {
734 subchannel_data *sd = gpr_malloc(sizeof(*sd));
735 memset(sd, 0, sizeof(*sd));
736 p->subchannels[subchannel_idx] = sd;
737 sd->policy = p;
738 sd->index = subchannel_idx;
739 sd->subchannel = subchannel;
David Garcia Quintas7ec29132016-11-01 04:09:05 +0100740 sd->user_data_vtable = addresses->user_data_vtable;
David Garcia Quintas5bdcd232016-11-02 15:47:02 -0700741 if (sd->user_data_vtable != NULL) {
742 sd->user_data =
743 sd->user_data_vtable->copy(addresses->addresses[i].user_data);
744 }
David Garcia Quintas67c0d042016-03-25 01:37:53 -0700745 ++subchannel_idx;
746 grpc_closure_init(&sd->connectivity_changed_closure,
Craig Tiller2400bf52017-02-09 16:25:19 -0800747 rr_connectivity_changed_locked, sd,
Craig Tiller46dd7902017-02-23 09:42:16 -0800748 grpc_combiner_scheduler(args->combiner, false));
David Garcia Quintas67c0d042016-03-25 01:37:53 -0700749 }
Craig Tillera82950e2015-09-22 12:33:20 -0700750 }
David Garcia Quintas67c0d042016-03-25 01:37:53 -0700751 if (subchannel_idx == 0) {
David Garcia Quintas5b0e9462016-08-15 19:38:39 -0700752 /* couldn't create any subchannel. Bail out */
David Garcia Quintas67c0d042016-03-25 01:37:53 -0700753 gpr_free(p->subchannels);
754 gpr_free(p);
755 return NULL;
756 }
757 p->num_subchannels = subchannel_idx;
David Garcia Quintas4fb049b2015-09-03 17:26:06 -0700758
759 /* The (dummy node) root of the ready list */
760 p->ready_list.subchannel = NULL;
761 p->ready_list.prev = NULL;
762 p->ready_list.next = NULL;
763 p->ready_list_last_pick = &p->ready_list;
764
Craig Tiller2400bf52017-02-09 16:25:19 -0800765 grpc_lb_policy_init(&p->base, &round_robin_lb_policy_vtable, args->combiner);
David Garcia Quintas67c0d042016-03-25 01:37:53 -0700766 grpc_connectivity_state_init(&p->state_tracker, GRPC_CHANNEL_IDLE,
767 "round_robin");
David Garcia Quintasa9cf87d2016-11-07 17:43:15 -0800768
769 if (grpc_lb_round_robin_trace) {
770 gpr_log(GPR_DEBUG, "Created RR policy at %p with %lu subchannels",
771 (void *)p, (unsigned long)p->num_subchannels);
772 }
David Garcia Quintas4fb049b2015-09-03 17:26:06 -0700773 return &p->base;
774}
775
776static const grpc_lb_policy_factory_vtable round_robin_factory_vtable = {
David Garcia Quintas02008702016-06-02 21:40:45 -0700777 round_robin_factory_ref, round_robin_factory_unref, round_robin_create,
Craig Tillera82950e2015-09-22 12:33:20 -0700778 "round_robin"};
David Garcia Quintas4fb049b2015-09-03 17:26:06 -0700779
780static grpc_lb_policy_factory round_robin_lb_policy_factory = {
Craig Tillera82950e2015-09-22 12:33:20 -0700781 &round_robin_factory_vtable};
David Garcia Quintas4fb049b2015-09-03 17:26:06 -0700782
Craig Tillerfb433852016-03-29 08:51:07 -0700783static grpc_lb_policy_factory *round_robin_lb_factory_create() {
David Garcia Quintas4fb049b2015-09-03 17:26:06 -0700784 return &round_robin_lb_policy_factory;
785}
Craig Tillerfb433852016-03-29 08:51:07 -0700786
787/* Plugin registration */
788
789void grpc_lb_policy_round_robin_init() {
Craig Tiller3113ef42016-03-29 09:03:14 -0700790 grpc_register_lb_policy(round_robin_lb_factory_create());
Craig Tillerfb433852016-03-29 08:51:07 -0700791 grpc_register_tracer("round_robin", &grpc_lb_round_robin_trace);
792}
793
794void grpc_lb_policy_round_robin_shutdown() {}