blob: 882c078d51237901a6f15b1a8a42d579fec9d95c [file] [log] [blame]
Nicolas Nobleb7ebd3b2014-11-26 16:33:03 -08001/*
2 *
Craig Tiller06059952015-02-18 08:34:56 -08003 * Copyright 2015, Google Inc.
Nicolas Nobleb7ebd3b2014-11-26 16:33:03 -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/transport/stream_op.h"
35
Craig Tiller8b282cb2015-04-17 14:57:44 -070036#include <string.h>
37
Nicolas Nobleb7ebd3b2014-11-26 16:33:03 -080038#include <grpc/support/alloc.h>
39#include <grpc/support/log.h>
40
Nicolas Nobleb7ebd3b2014-11-26 16:33:03 -080041/* Exponential growth function: Given x, return a larger x.
Craig Tillere3018e62015-02-13 17:05:19 -080042 Currently we grow by 1.5 times upon reallocation. */
Nicolas Nobleb7ebd3b2014-11-26 16:33:03 -080043#define GROW(x) (3 * (x) / 2)
44
45void grpc_sopb_init(grpc_stream_op_buffer *sopb) {
Craig Tillere3018e62015-02-13 17:05:19 -080046 sopb->ops = sopb->inlined_ops;
Nicolas Nobleb7ebd3b2014-11-26 16:33:03 -080047 sopb->nops = 0;
Craig Tillere3018e62015-02-13 17:05:19 -080048 sopb->capacity = GRPC_SOPB_INLINE_ELEMENTS;
Nicolas Nobleb7ebd3b2014-11-26 16:33:03 -080049}
50
51void grpc_sopb_destroy(grpc_stream_op_buffer *sopb) {
52 grpc_stream_ops_unref_owned_objects(sopb->ops, sopb->nops);
Craig Tillere3018e62015-02-13 17:05:19 -080053 if (sopb->ops != sopb->inlined_ops) gpr_free(sopb->ops);
Nicolas Nobleb7ebd3b2014-11-26 16:33:03 -080054}
55
56void grpc_sopb_reset(grpc_stream_op_buffer *sopb) {
57 grpc_stream_ops_unref_owned_objects(sopb->ops, sopb->nops);
58 sopb->nops = 0;
59}
60
Craig Tillere3018e62015-02-13 17:05:19 -080061void grpc_sopb_swap(grpc_stream_op_buffer *a, grpc_stream_op_buffer *b) {
62 grpc_stream_op_buffer temp = *a;
63 *a = *b;
64 *b = temp;
65
66 if (a->ops == b->inlined_ops) {
67 a->ops = a->inlined_ops;
68 }
69 if (b->ops == a->inlined_ops) {
70 b->ops = b->inlined_ops;
71 }
72}
73
Nicolas Nobleb7ebd3b2014-11-26 16:33:03 -080074void grpc_stream_ops_unref_owned_objects(grpc_stream_op *ops, size_t nops) {
Craig Tiller0c0b60c2015-01-21 15:49:28 -080075 size_t i;
Nicolas Nobleb7ebd3b2014-11-26 16:33:03 -080076 for (i = 0; i < nops; i++) {
77 switch (ops[i].type) {
78 case GRPC_OP_SLICE:
79 gpr_slice_unref(ops[i].data.slice);
80 break;
81 case GRPC_OP_METADATA:
Craig Tillereb40a532015-04-17 16:46:20 -070082 grpc_metadata_batch_destroy(&ops[i].data.metadata);
Nicolas Nobleb7ebd3b2014-11-26 16:33:03 -080083 break;
84 case GRPC_OP_FLOW_CTL_CB:
85 ops[i].data.flow_ctl_cb.cb(ops[i].data.flow_ctl_cb.arg, GRPC_OP_ERROR);
86 break;
87 case GRPC_NO_OP:
Nicolas Nobleb7ebd3b2014-11-26 16:33:03 -080088 case GRPC_OP_BEGIN_MESSAGE:
89 break;
90 }
91 }
92}
93
Craig Tiller8b282cb2015-04-17 14:57:44 -070094static void assert_contained_metadata_ok(grpc_stream_op *ops, size_t nops) {
Craig Tillerb116c4f2015-04-20 10:07:36 -070095#ifndef NDEBUG
Craig Tiller8b282cb2015-04-17 14:57:44 -070096 size_t i;
97 for (i = 0; i < nops; i++) {
98 if (ops[i].type == GRPC_OP_METADATA) {
99 grpc_metadata_batch_assert_ok(&ops[i].data.metadata);
100 }
101 }
Craig Tilleree152342015-04-21 11:51:27 -0700102#endif /* NDEBUG */
Craig Tiller8b282cb2015-04-17 14:57:44 -0700103}
104
Craig Tillere3018e62015-02-13 17:05:19 -0800105static void expandto(grpc_stream_op_buffer *sopb, size_t new_capacity) {
106 sopb->capacity = new_capacity;
Craig Tiller8b282cb2015-04-17 14:57:44 -0700107 assert_contained_metadata_ok(sopb->ops, sopb->nops);
Craig Tillere3018e62015-02-13 17:05:19 -0800108 if (sopb->ops == sopb->inlined_ops) {
109 sopb->ops = gpr_malloc(sizeof(grpc_stream_op) * new_capacity);
110 memcpy(sopb->ops, sopb->inlined_ops, sopb->nops * sizeof(grpc_stream_op));
111 } else {
112 sopb->ops = gpr_realloc(sopb->ops, sizeof(grpc_stream_op) * new_capacity);
113 }
Craig Tiller8b282cb2015-04-17 14:57:44 -0700114 assert_contained_metadata_ok(sopb->ops, sopb->nops);
Nicolas Nobleb7ebd3b2014-11-26 16:33:03 -0800115}
116
117static grpc_stream_op *add(grpc_stream_op_buffer *sopb) {
118 grpc_stream_op *out;
119
Craig Tiller8b282cb2015-04-17 14:57:44 -0700120 assert_contained_metadata_ok(sopb->ops, sopb->nops);
121
Nicolas Nobleb7ebd3b2014-11-26 16:33:03 -0800122 if (sopb->nops == sopb->capacity) {
Craig Tillere3018e62015-02-13 17:05:19 -0800123 expandto(sopb, GROW(sopb->capacity));
Nicolas Nobleb7ebd3b2014-11-26 16:33:03 -0800124 }
125 out = sopb->ops + sopb->nops;
126 sopb->nops++;
127 return out;
128}
129
130void grpc_sopb_add_no_op(grpc_stream_op_buffer *sopb) {
131 add(sopb)->type = GRPC_NO_OP;
Craig Tiller8b282cb2015-04-17 14:57:44 -0700132 assert_contained_metadata_ok(sopb->ops, sopb->nops);
Nicolas Nobleb7ebd3b2014-11-26 16:33:03 -0800133}
134
135void grpc_sopb_add_begin_message(grpc_stream_op_buffer *sopb, gpr_uint32 length,
136 gpr_uint32 flags) {
137 grpc_stream_op *op = add(sopb);
138 op->type = GRPC_OP_BEGIN_MESSAGE;
139 op->data.begin_message.length = length;
140 op->data.begin_message.flags = flags;
Craig Tiller8b282cb2015-04-17 14:57:44 -0700141 assert_contained_metadata_ok(sopb->ops, sopb->nops);
Nicolas Nobleb7ebd3b2014-11-26 16:33:03 -0800142}
143
Craig Tiller76f5d462015-04-17 14:58:12 -0700144void grpc_sopb_add_metadata(grpc_stream_op_buffer *sopb,
145 grpc_metadata_batch b) {
Nicolas Nobleb7ebd3b2014-11-26 16:33:03 -0800146 grpc_stream_op *op = add(sopb);
Craig Tiller9c1043e2015-04-16 16:20:38 -0700147 grpc_metadata_batch_assert_ok(&b);
Nicolas Nobleb7ebd3b2014-11-26 16:33:03 -0800148 op->type = GRPC_OP_METADATA;
Craig Tiller9c1043e2015-04-16 16:20:38 -0700149 op->data.metadata = b;
Craig Tiller8b282cb2015-04-17 14:57:44 -0700150 grpc_metadata_batch_assert_ok(&op->data.metadata);
151 assert_contained_metadata_ok(sopb->ops, sopb->nops);
Nicolas Nobleb7ebd3b2014-11-26 16:33:03 -0800152}
153
154void grpc_sopb_add_slice(grpc_stream_op_buffer *sopb, gpr_slice slice) {
155 grpc_stream_op *op = add(sopb);
156 op->type = GRPC_OP_SLICE;
157 op->data.slice = slice;
Craig Tiller8b282cb2015-04-17 14:57:44 -0700158 assert_contained_metadata_ok(sopb->ops, sopb->nops);
Nicolas Nobleb7ebd3b2014-11-26 16:33:03 -0800159}
160
161void grpc_sopb_add_flow_ctl_cb(grpc_stream_op_buffer *sopb,
162 void (*cb)(void *arg, grpc_op_error error),
163 void *arg) {
164 grpc_stream_op *op = add(sopb);
165 op->type = GRPC_OP_FLOW_CTL_CB;
166 op->data.flow_ctl_cb.cb = cb;
167 op->data.flow_ctl_cb.arg = arg;
Craig Tiller8b282cb2015-04-17 14:57:44 -0700168 assert_contained_metadata_ok(sopb->ops, sopb->nops);
Nicolas Nobleb7ebd3b2014-11-26 16:33:03 -0800169}
170
171void grpc_sopb_append(grpc_stream_op_buffer *sopb, grpc_stream_op *ops,
172 size_t nops) {
173 size_t orig_nops = sopb->nops;
174 size_t new_nops = orig_nops + nops;
175
Craig Tiller8b282cb2015-04-17 14:57:44 -0700176 assert_contained_metadata_ok(ops, nops);
177 assert_contained_metadata_ok(sopb->ops, sopb->nops);
Nicolas Nobleb7ebd3b2014-11-26 16:33:03 -0800178 if (new_nops > sopb->capacity) {
Craig Tillere3018e62015-02-13 17:05:19 -0800179 expandto(sopb, GPR_MAX(GROW(sopb->capacity), new_nops));
Nicolas Nobleb7ebd3b2014-11-26 16:33:03 -0800180 }
181
182 memcpy(sopb->ops + orig_nops, ops, sizeof(grpc_stream_op) * nops);
183 sopb->nops = new_nops;
Craig Tiller8b282cb2015-04-17 14:57:44 -0700184 assert_contained_metadata_ok(sopb->ops, sopb->nops);
Craig Tiller190d3602015-02-18 09:23:38 -0800185}
Craig Tiller205aee12015-04-16 14:46:41 -0700186
Craig Tiller205aee12015-04-16 14:46:41 -0700187static void assert_valid_list(grpc_mdelem_list *list) {
Craig Tillerb116c4f2015-04-20 10:07:36 -0700188#ifndef NDEBUG
Craig Tiller205aee12015-04-16 14:46:41 -0700189 grpc_linked_mdelem *l;
190
191 GPR_ASSERT((list->head == NULL) == (list->tail == NULL));
192 if (!list->head) return;
193 GPR_ASSERT(list->head->prev == NULL);
194 GPR_ASSERT(list->tail->next == NULL);
195 GPR_ASSERT((list->head == list->tail) == (list->head->next == NULL));
196
197 for (l = list->head; l; l = l->next) {
Craig Tiller9c1043e2015-04-16 16:20:38 -0700198 GPR_ASSERT(l->md);
Craig Tiller205aee12015-04-16 14:46:41 -0700199 GPR_ASSERT((l->prev == NULL) == (l == list->head));
200 GPR_ASSERT((l->next == NULL) == (l == list->tail));
201 if (l->next) GPR_ASSERT(l->next->prev == l);
202 if (l->prev) GPR_ASSERT(l->prev->next == l);
203 }
Craig Tilleree152342015-04-21 11:51:27 -0700204#endif /* NDEBUG */
Craig Tiller205aee12015-04-16 14:46:41 -0700205}
206
Craig Tillerb116c4f2015-04-20 10:07:36 -0700207#ifndef NDEBUG
Craig Tiller9c1043e2015-04-16 16:20:38 -0700208void grpc_metadata_batch_assert_ok(grpc_metadata_batch *comd) {
209 assert_valid_list(&comd->list);
210 assert_valid_list(&comd->garbage);
211}
Craig Tilleree152342015-04-21 11:51:27 -0700212#endif /* NDEBUG */
Craig Tiller9c1043e2015-04-16 16:20:38 -0700213
Craig Tiller76f5d462015-04-17 14:58:12 -0700214void grpc_metadata_batch_init(grpc_metadata_batch *comd) {
215 comd->list.head = comd->list.tail = comd->garbage.head = comd->garbage.tail =
216 NULL;
Craig Tiller8b282cb2015-04-17 14:57:44 -0700217 comd->deadline = gpr_inf_future;
218}
Craig Tiller205aee12015-04-16 14:46:41 -0700219
Craig Tiller76f5d462015-04-17 14:58:12 -0700220void grpc_metadata_batch_destroy(grpc_metadata_batch *comd) {
Craig Tiller8b282cb2015-04-17 14:57:44 -0700221 grpc_linked_mdelem *l;
222 for (l = comd->list.head; l; l = l->next) {
223 grpc_mdelem_unref(l->md);
224 }
225 for (l = comd->garbage.head; l; l = l->next) {
226 grpc_mdelem_unref(l->md);
227 }
Craig Tiller205aee12015-04-16 14:46:41 -0700228}
229
230void grpc_metadata_batch_add_head(grpc_metadata_batch *comd,
Craig Tiller76f5d462015-04-17 14:58:12 -0700231 grpc_linked_mdelem *storage,
232 grpc_mdelem *elem_to_add) {
Craig Tiller9c1043e2015-04-16 16:20:38 -0700233 GPR_ASSERT(elem_to_add);
Craig Tiller205aee12015-04-16 14:46:41 -0700234 storage->md = elem_to_add;
235 grpc_metadata_batch_link_head(comd, storage);
236}
237
238static void link_head(grpc_mdelem_list *list, grpc_linked_mdelem *storage) {
239 assert_valid_list(list);
Craig Tiller9c1043e2015-04-16 16:20:38 -0700240 GPR_ASSERT(storage->md);
Craig Tiller205aee12015-04-16 14:46:41 -0700241 storage->prev = NULL;
242 storage->next = list->head;
243 if (list->head != NULL) {
244 list->head->prev = storage;
245 } else {
246 list->tail = storage;
247 }
248 list->head = storage;
249 assert_valid_list(list);
250}
251
252void grpc_metadata_batch_link_head(grpc_metadata_batch *comd,
Craig Tiller76f5d462015-04-17 14:58:12 -0700253 grpc_linked_mdelem *storage) {
Craig Tiller205aee12015-04-16 14:46:41 -0700254 link_head(&comd->list, storage);
255}
256
257void grpc_metadata_batch_add_tail(grpc_metadata_batch *comd,
Craig Tiller76f5d462015-04-17 14:58:12 -0700258 grpc_linked_mdelem *storage,
259 grpc_mdelem *elem_to_add) {
Craig Tiller9c1043e2015-04-16 16:20:38 -0700260 GPR_ASSERT(elem_to_add);
Craig Tiller205aee12015-04-16 14:46:41 -0700261 storage->md = elem_to_add;
262 grpc_metadata_batch_link_tail(comd, storage);
263}
264
265static void link_tail(grpc_mdelem_list *list, grpc_linked_mdelem *storage) {
266 assert_valid_list(list);
Craig Tiller9c1043e2015-04-16 16:20:38 -0700267 GPR_ASSERT(storage->md);
Craig Tiller205aee12015-04-16 14:46:41 -0700268 storage->prev = list->tail;
269 storage->next = NULL;
270 if (list->tail != NULL) {
271 list->tail->next = storage;
272 } else {
273 list->head = storage;
274 }
275 list->tail = storage;
276 assert_valid_list(list);
277}
278
279void grpc_metadata_batch_link_tail(grpc_metadata_batch *comd,
Craig Tiller76f5d462015-04-17 14:58:12 -0700280 grpc_linked_mdelem *storage) {
Craig Tiller205aee12015-04-16 14:46:41 -0700281 link_tail(&comd->list, storage);
282}
283
Craig Tiller8b282cb2015-04-17 14:57:44 -0700284void grpc_metadata_batch_merge(grpc_metadata_batch *target,
Craig Tiller76f5d462015-04-17 14:58:12 -0700285 grpc_metadata_batch *add) {
Craig Tiller8b282cb2015-04-17 14:57:44 -0700286 grpc_linked_mdelem *l;
287 grpc_linked_mdelem *next;
288 for (l = add->list.head; l; l = next) {
289 next = l->next;
290 link_tail(&target->list, l);
Craig Tiller76f5d462015-04-17 14:58:12 -0700291 }
Craig Tiller8b282cb2015-04-17 14:57:44 -0700292 for (l = add->garbage.head; l; l = next) {
293 next = l->next;
294 link_tail(&target->garbage, l);
Craig Tiller76f5d462015-04-17 14:58:12 -0700295 }
Craig Tiller8b282cb2015-04-17 14:57:44 -0700296}
297
Craig Tiller205aee12015-04-16 14:46:41 -0700298void grpc_metadata_batch_filter(grpc_metadata_batch *comd,
Craig Tiller76f5d462015-04-17 14:58:12 -0700299 grpc_mdelem *(*filter)(void *user_data,
300 grpc_mdelem *elem),
301 void *user_data) {
Craig Tiller205aee12015-04-16 14:46:41 -0700302 grpc_linked_mdelem *l;
303 grpc_linked_mdelem *next;
304
305 assert_valid_list(&comd->list);
306 assert_valid_list(&comd->garbage);
307 for (l = comd->list.head; l; l = next) {
308 grpc_mdelem *orig = l->md;
309 grpc_mdelem *filt = filter(user_data, orig);
310 next = l->next;
311 if (filt == NULL) {
312 if (l->prev) {
313 l->prev->next = l->next;
314 }
315 if (l->next) {
316 l->next->prev = l->prev;
317 }
318 if (comd->list.head == l) {
319 comd->list.head = l->next;
320 }
321 if (comd->list.tail == l) {
322 comd->list.tail = l->prev;
323 }
324 assert_valid_list(&comd->list);
325 link_head(&comd->garbage, l);
326 } else if (filt != orig) {
327 grpc_mdelem_unref(orig);
328 l->md = filt;
329 }
330 }
331 assert_valid_list(&comd->list);
332 assert_valid_list(&comd->garbage);
333}