blob: 2cb03829c7903589a80227b185670bd03189d8bb [file] [log] [blame]
ctiller82e275f2014-12-12 08:43:28 -08001/*
2 *
Craig Tiller06059952015-02-18 08:34:56 -08003 * Copyright 2015, Google Inc.
ctiller82e275f2014-12-12 08:43:28 -08004 * 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
34#include "src/core/channel/child_channel.h"
35#include "src/core/iomgr/iomgr.h"
36#include <grpc/support/alloc.h>
37
38/* Link back filter: passes up calls to the client channel, pushes down calls
39 down */
40
ctillerc6d61c42014-12-15 14:52:08 -080041static void maybe_destroy_channel(grpc_child_channel *channel);
ctiller82e275f2014-12-12 08:43:28 -080042
43typedef struct {
44 gpr_mu mu;
45 gpr_cv cv;
46 grpc_channel_element *back;
ctillerc6d61c42014-12-15 14:52:08 -080047 /* # of active calls on the channel */
48 gpr_uint32 active_calls;
49 /* has grpc_child_channel_destroy been called? */
50 gpr_uint8 destroyed;
51 /* has the transport reported itself disconnected? */
52 gpr_uint8 disconnected;
53 /* are we calling 'back' - our parent channel */
54 gpr_uint8 calling_back;
55 /* have we or our parent sent goaway yet? - dup suppression */
56 gpr_uint8 sent_goaway;
57 /* are we currently sending farewell (in this file: goaway + disconnect) */
58 gpr_uint8 sending_farewell;
59 /* have we sent farewell (goaway + disconnect) */
60 gpr_uint8 sent_farewell;
ctiller82e275f2014-12-12 08:43:28 -080061} lb_channel_data;
62
63typedef struct {
64 grpc_call_element *back;
ctiller82e275f2014-12-12 08:43:28 -080065 grpc_child_channel *channel;
66} lb_call_data;
67
68static void lb_call_op(grpc_call_element *elem, grpc_call_element *from_elem,
69 grpc_call_op *op) {
70 lb_call_data *calld = elem->call_data;
71
72 switch (op->dir) {
73 case GRPC_CALL_UP:
74 calld->back->filter->call_op(calld->back, elem, op);
75 break;
76 case GRPC_CALL_DOWN:
77 grpc_call_next_op(elem, op);
78 break;
79 }
80}
81
ctiller82e275f2014-12-12 08:43:28 -080082/* Currently we assume all channel operations should just be pushed up. */
83static void lb_channel_op(grpc_channel_element *elem,
84 grpc_channel_element *from_elem,
85 grpc_channel_op *op) {
86 lb_channel_data *chand = elem->channel_data;
87 grpc_channel_element *back;
ctiller58393c22015-01-07 14:03:30 -080088 int calling_back = 0;
ctiller82e275f2014-12-12 08:43:28 -080089
90 switch (op->dir) {
91 case GRPC_CALL_UP:
92 gpr_mu_lock(&chand->mu);
93 back = chand->back;
ctiller58393c22015-01-07 14:03:30 -080094 if (back) {
95 chand->calling_back++;
96 calling_back = 1;
97 }
ctiller82e275f2014-12-12 08:43:28 -080098 gpr_mu_unlock(&chand->mu);
99 if (back) {
100 back->filter->channel_op(chand->back, elem, op);
ctillerc6d61c42014-12-15 14:52:08 -0800101 } else if (op->type == GRPC_TRANSPORT_GOAWAY) {
102 gpr_slice_unref(op->data.goaway.message);
ctiller82e275f2014-12-12 08:43:28 -0800103 }
104 break;
105 case GRPC_CALL_DOWN:
106 grpc_channel_next_op(elem, op);
107 break;
108 }
109
ctiller58393c22015-01-07 14:03:30 -0800110 gpr_mu_lock(&chand->mu);
ctiller82e275f2014-12-12 08:43:28 -0800111 switch (op->type) {
112 case GRPC_TRANSPORT_CLOSED:
ctillerc6d61c42014-12-15 14:52:08 -0800113 chand->disconnected = 1;
114 maybe_destroy_channel(grpc_channel_stack_from_top_element(elem));
ctiller82e275f2014-12-12 08:43:28 -0800115 break;
116 case GRPC_CHANNEL_GOAWAY:
ctiller82e275f2014-12-12 08:43:28 -0800117 chand->sent_goaway = 1;
ctiller82e275f2014-12-12 08:43:28 -0800118 break;
119 case GRPC_CHANNEL_DISCONNECT:
120 case GRPC_TRANSPORT_GOAWAY:
121 case GRPC_ACCEPT_CALL:
122 break;
123 }
ctiller58393c22015-01-07 14:03:30 -0800124
125 if (calling_back) {
126 chand->calling_back--;
127 gpr_cv_signal(&chand->cv);
128 maybe_destroy_channel(grpc_channel_stack_from_top_element(elem));
129 }
130 gpr_mu_unlock(&chand->mu);
ctiller82e275f2014-12-12 08:43:28 -0800131}
132
133/* Constructor for call_data */
134static void lb_init_call_elem(grpc_call_element *elem,
135 const void *server_transport_data) {}
136
137/* Destructor for call_data */
138static void lb_destroy_call_elem(grpc_call_element *elem) {}
139
140/* Constructor for channel_data */
141static void lb_init_channel_elem(grpc_channel_element *elem,
142 const grpc_channel_args *args,
143 grpc_mdctx *metadata_context, int is_first,
144 int is_last) {
145 lb_channel_data *chand = elem->channel_data;
146 GPR_ASSERT(is_first);
147 GPR_ASSERT(!is_last);
148 gpr_mu_init(&chand->mu);
149 gpr_cv_init(&chand->cv);
ctiller82e275f2014-12-12 08:43:28 -0800150 chand->back = NULL;
ctillerc6d61c42014-12-15 14:52:08 -0800151 chand->destroyed = 0;
152 chand->disconnected = 0;
153 chand->active_calls = 0;
ctiller82e275f2014-12-12 08:43:28 -0800154 chand->sent_goaway = 0;
155 chand->calling_back = 0;
ctillerc6d61c42014-12-15 14:52:08 -0800156 chand->sending_farewell = 0;
157 chand->sent_farewell = 0;
ctiller82e275f2014-12-12 08:43:28 -0800158}
159
160/* Destructor for channel_data */
161static void lb_destroy_channel_elem(grpc_channel_element *elem) {
162 lb_channel_data *chand = elem->channel_data;
163 gpr_mu_destroy(&chand->mu);
164 gpr_cv_destroy(&chand->cv);
165}
166
167const grpc_channel_filter grpc_child_channel_top_filter = {
Yang Gao5fd0d292015-01-26 00:19:48 -0800168 lb_call_op, lb_channel_op, sizeof(lb_call_data),
169 lb_init_call_elem, lb_destroy_call_elem, sizeof(lb_channel_data),
170 lb_init_channel_elem, lb_destroy_channel_elem, "child-channel", };
ctiller82e275f2014-12-12 08:43:28 -0800171
172/* grpc_child_channel proper */
173
174#define LINK_BACK_ELEM_FROM_CHANNEL(channel) \
175 grpc_channel_stack_element((channel), 0)
176
177#define LINK_BACK_ELEM_FROM_CALL(call) grpc_call_stack_element((call), 0)
178
ctiller58393c22015-01-07 14:03:30 -0800179static void finally_destroy_channel(void *c, int success) {
180 /* ignore success or not... this is a destruction callback and will only
181 happen once - the only purpose here is to release resources */
ctillerc6d61c42014-12-15 14:52:08 -0800182 grpc_child_channel *channel = c;
183 lb_channel_data *chand = LINK_BACK_ELEM_FROM_CHANNEL(channel)->channel_data;
184 /* wait for the initiator to leave the mutex */
185 gpr_mu_lock(&chand->mu);
186 gpr_mu_unlock(&chand->mu);
187 grpc_channel_stack_destroy(channel);
188 gpr_free(channel);
189}
190
ctiller58393c22015-01-07 14:03:30 -0800191static void send_farewells(void *c, int success) {
ctillerc6d61c42014-12-15 14:52:08 -0800192 grpc_child_channel *channel = c;
193 grpc_channel_element *lbelem = LINK_BACK_ELEM_FROM_CHANNEL(channel);
194 lb_channel_data *chand = lbelem->channel_data;
195 int send_goaway;
196 grpc_channel_op op;
197
198 gpr_mu_lock(&chand->mu);
199 send_goaway = !chand->sent_goaway;
200 chand->sent_goaway = 1;
201 gpr_mu_unlock(&chand->mu);
202
203 if (send_goaway) {
204 op.type = GRPC_CHANNEL_GOAWAY;
205 op.dir = GRPC_CALL_DOWN;
206 op.data.goaway.status = GRPC_STATUS_OK;
207 op.data.goaway.message = gpr_slice_from_copied_string("Client disconnect");
208 grpc_channel_next_op(lbelem, &op);
209 }
210
211 op.type = GRPC_CHANNEL_DISCONNECT;
212 op.dir = GRPC_CALL_DOWN;
213 grpc_channel_next_op(lbelem, &op);
214
215 gpr_mu_lock(&chand->mu);
216 chand->sending_farewell = 0;
217 chand->sent_farewell = 1;
218 maybe_destroy_channel(channel);
219 gpr_mu_unlock(&chand->mu);
220}
221
222static void maybe_destroy_channel(grpc_child_channel *channel) {
223 lb_channel_data *chand = LINK_BACK_ELEM_FROM_CHANNEL(channel)->channel_data;
224 if (chand->destroyed && chand->disconnected && chand->active_calls == 0 &&
ctiller58393c22015-01-07 14:03:30 -0800225 !chand->sending_farewell && !chand->calling_back) {
ctillerc6d61c42014-12-15 14:52:08 -0800226 grpc_iomgr_add_callback(finally_destroy_channel, channel);
227 } else if (chand->destroyed && !chand->disconnected &&
228 chand->active_calls == 0 && !chand->sending_farewell &&
229 !chand->sent_farewell) {
230 chand->sending_farewell = 1;
231 grpc_iomgr_add_callback(send_farewells, channel);
ctiller82e275f2014-12-12 08:43:28 -0800232 }
233}
234
ctiller82e275f2014-12-12 08:43:28 -0800235grpc_child_channel *grpc_child_channel_create(
236 grpc_channel_element *parent, const grpc_channel_filter **filters,
237 size_t filter_count, const grpc_channel_args *args,
238 grpc_mdctx *metadata_context) {
239 grpc_channel_stack *stk =
240 gpr_malloc(grpc_channel_stack_size(filters, filter_count));
241 lb_channel_data *lb;
242
243 grpc_channel_stack_init(filters, filter_count, args, metadata_context, stk);
244
245 lb = LINK_BACK_ELEM_FROM_CHANNEL(stk)->channel_data;
246 gpr_mu_lock(&lb->mu);
247 lb->back = parent;
248 gpr_mu_unlock(&lb->mu);
249
ctillerc6d61c42014-12-15 14:52:08 -0800250 return stk;
ctiller82e275f2014-12-12 08:43:28 -0800251}
252
ctiller58393c22015-01-07 14:03:30 -0800253void grpc_child_channel_destroy(grpc_child_channel *channel,
254 int wait_for_callbacks) {
ctiller82e275f2014-12-12 08:43:28 -0800255 grpc_channel_element *lbelem = LINK_BACK_ELEM_FROM_CHANNEL(channel);
256 lb_channel_data *chand = lbelem->channel_data;
257
258 gpr_mu_lock(&chand->mu);
ctiller58393c22015-01-07 14:03:30 -0800259 while (wait_for_callbacks && chand->calling_back) {
ctiller82e275f2014-12-12 08:43:28 -0800260 gpr_cv_wait(&chand->cv, &chand->mu, gpr_inf_future);
261 }
ctiller58393c22015-01-07 14:03:30 -0800262
ctiller82e275f2014-12-12 08:43:28 -0800263 chand->back = NULL;
ctillerc6d61c42014-12-15 14:52:08 -0800264 chand->destroyed = 1;
265 maybe_destroy_channel(channel);
ctiller82e275f2014-12-12 08:43:28 -0800266 gpr_mu_unlock(&chand->mu);
ctiller82e275f2014-12-12 08:43:28 -0800267}
268
269void grpc_child_channel_handle_op(grpc_child_channel *channel,
270 grpc_channel_op *op) {
271 grpc_channel_next_op(LINK_BACK_ELEM_FROM_CHANNEL(channel), op);
272}
273
274grpc_child_call *grpc_child_channel_create_call(grpc_child_channel *channel,
275 grpc_call_element *parent) {
276 grpc_call_stack *stk = gpr_malloc((channel)->call_stack_size);
ctillerc6d61c42014-12-15 14:52:08 -0800277 grpc_call_element *lbelem;
ctiller82e275f2014-12-12 08:43:28 -0800278 lb_call_data *lbcalld;
ctillerc6d61c42014-12-15 14:52:08 -0800279 lb_channel_data *lbchand;
ctiller82e275f2014-12-12 08:43:28 -0800280
281 grpc_call_stack_init(channel, NULL, stk);
ctillerc6d61c42014-12-15 14:52:08 -0800282 lbelem = LINK_BACK_ELEM_FROM_CALL(stk);
283 lbchand = lbelem->channel_data;
284 lbcalld = lbelem->call_data;
ctiller82e275f2014-12-12 08:43:28 -0800285 lbcalld->back = parent;
286 lbcalld->channel = channel;
287
ctillerc6d61c42014-12-15 14:52:08 -0800288 gpr_mu_lock(&lbchand->mu);
289 lbchand->active_calls++;
290 gpr_mu_unlock(&lbchand->mu);
291
292 return stk;
ctiller82e275f2014-12-12 08:43:28 -0800293}
294
ctillerc6d61c42014-12-15 14:52:08 -0800295void grpc_child_call_destroy(grpc_child_call *call) {
296 grpc_call_element *lbelem = LINK_BACK_ELEM_FROM_CALL(call);
297 lb_call_data *calld = lbelem->call_data;
298 lb_channel_data *chand = lbelem->channel_data;
299 grpc_child_channel *channel = calld->channel;
300 grpc_call_stack_destroy(call);
301 gpr_free(call);
302 gpr_mu_lock(&chand->mu);
303 chand->active_calls--;
304 maybe_destroy_channel(channel);
305 gpr_mu_unlock(&chand->mu);
306}
ctiller82e275f2014-12-12 08:43:28 -0800307
308grpc_call_element *grpc_child_call_get_top_element(grpc_child_call *call) {
309 return LINK_BACK_ELEM_FROM_CALL(call);
Craig Tiller190d3602015-02-18 09:23:38 -0800310}