blob: e1a75adcb6e2b73c7e1684be8d5963bdd426d53b [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;
Nicolas Nobleb7ebd3b2014-11-26 16:33:03 -080084 case GRPC_NO_OP:
Nicolas Nobleb7ebd3b2014-11-26 16:33:03 -080085 case GRPC_OP_BEGIN_MESSAGE:
86 break;
87 }
88 }
89}
90
Craig Tillere3018e62015-02-13 17:05:19 -080091static void expandto(grpc_stream_op_buffer *sopb, size_t new_capacity) {
92 sopb->capacity = new_capacity;
93 if (sopb->ops == sopb->inlined_ops) {
94 sopb->ops = gpr_malloc(sizeof(grpc_stream_op) * new_capacity);
95 memcpy(sopb->ops, sopb->inlined_ops, sopb->nops * sizeof(grpc_stream_op));
96 } else {
97 sopb->ops = gpr_realloc(sopb->ops, sizeof(grpc_stream_op) * new_capacity);
98 }
Nicolas Nobleb7ebd3b2014-11-26 16:33:03 -080099}
100
101static grpc_stream_op *add(grpc_stream_op_buffer *sopb) {
102 grpc_stream_op *out;
103
Craig Tillerfbf5be22015-04-22 16:17:09 -0700104 GPR_ASSERT(sopb->nops <= sopb->capacity);
Nicolas Nobleb7ebd3b2014-11-26 16:33:03 -0800105 if (sopb->nops == sopb->capacity) {
Craig Tillere3018e62015-02-13 17:05:19 -0800106 expandto(sopb, GROW(sopb->capacity));
Nicolas Nobleb7ebd3b2014-11-26 16:33:03 -0800107 }
108 out = sopb->ops + sopb->nops;
109 sopb->nops++;
110 return out;
111}
112
113void grpc_sopb_add_no_op(grpc_stream_op_buffer *sopb) {
114 add(sopb)->type = GRPC_NO_OP;
115}
116
117void grpc_sopb_add_begin_message(grpc_stream_op_buffer *sopb, gpr_uint32 length,
118 gpr_uint32 flags) {
119 grpc_stream_op *op = add(sopb);
120 op->type = GRPC_OP_BEGIN_MESSAGE;
121 op->data.begin_message.length = length;
122 op->data.begin_message.flags = flags;
123}
124
Craig Tiller76f5d462015-04-17 14:58:12 -0700125void grpc_sopb_add_metadata(grpc_stream_op_buffer *sopb,
126 grpc_metadata_batch b) {
Nicolas Nobleb7ebd3b2014-11-26 16:33:03 -0800127 grpc_stream_op *op = add(sopb);
Nicolas Nobleb7ebd3b2014-11-26 16:33:03 -0800128 op->type = GRPC_OP_METADATA;
Craig Tiller9c1043e2015-04-16 16:20:38 -0700129 op->data.metadata = b;
Nicolas Nobleb7ebd3b2014-11-26 16:33:03 -0800130}
131
132void grpc_sopb_add_slice(grpc_stream_op_buffer *sopb, gpr_slice slice) {
133 grpc_stream_op *op = add(sopb);
134 op->type = GRPC_OP_SLICE;
135 op->data.slice = slice;
136}
137
Nicolas Nobleb7ebd3b2014-11-26 16:33:03 -0800138void grpc_sopb_append(grpc_stream_op_buffer *sopb, grpc_stream_op *ops,
139 size_t nops) {
140 size_t orig_nops = sopb->nops;
141 size_t new_nops = orig_nops + nops;
142
143 if (new_nops > sopb->capacity) {
Craig Tillere3018e62015-02-13 17:05:19 -0800144 expandto(sopb, GPR_MAX(GROW(sopb->capacity), new_nops));
Nicolas Nobleb7ebd3b2014-11-26 16:33:03 -0800145 }
146
147 memcpy(sopb->ops + orig_nops, ops, sizeof(grpc_stream_op) * nops);
148 sopb->nops = new_nops;
Craig Tiller190d3602015-02-18 09:23:38 -0800149}
Craig Tiller205aee12015-04-16 14:46:41 -0700150
Craig Tiller205aee12015-04-16 14:46:41 -0700151static void assert_valid_list(grpc_mdelem_list *list) {
Craig Tillerb116c4f2015-04-20 10:07:36 -0700152#ifndef NDEBUG
Craig Tiller205aee12015-04-16 14:46:41 -0700153 grpc_linked_mdelem *l;
154
155 GPR_ASSERT((list->head == NULL) == (list->tail == NULL));
156 if (!list->head) return;
157 GPR_ASSERT(list->head->prev == NULL);
158 GPR_ASSERT(list->tail->next == NULL);
159 GPR_ASSERT((list->head == list->tail) == (list->head->next == NULL));
160
161 for (l = list->head; l; l = l->next) {
Craig Tiller9c1043e2015-04-16 16:20:38 -0700162 GPR_ASSERT(l->md);
Craig Tiller205aee12015-04-16 14:46:41 -0700163 GPR_ASSERT((l->prev == NULL) == (l == list->head));
164 GPR_ASSERT((l->next == NULL) == (l == list->tail));
165 if (l->next) GPR_ASSERT(l->next->prev == l);
166 if (l->prev) GPR_ASSERT(l->prev->next == l);
167 }
Craig Tilleree152342015-04-21 11:51:27 -0700168#endif /* NDEBUG */
Craig Tiller205aee12015-04-16 14:46:41 -0700169}
170
Craig Tillerb116c4f2015-04-20 10:07:36 -0700171#ifndef NDEBUG
Craig Tiller9c1043e2015-04-16 16:20:38 -0700172void grpc_metadata_batch_assert_ok(grpc_metadata_batch *comd) {
173 assert_valid_list(&comd->list);
174 assert_valid_list(&comd->garbage);
175}
Craig Tilleree152342015-04-21 11:51:27 -0700176#endif /* NDEBUG */
Craig Tiller9c1043e2015-04-16 16:20:38 -0700177
Craig Tiller76f5d462015-04-17 14:58:12 -0700178void grpc_metadata_batch_init(grpc_metadata_batch *comd) {
179 comd->list.head = comd->list.tail = comd->garbage.head = comd->garbage.tail =
180 NULL;
Craig Tiller8b282cb2015-04-17 14:57:44 -0700181 comd->deadline = gpr_inf_future;
182}
Craig Tiller205aee12015-04-16 14:46:41 -0700183
Craig Tiller76f5d462015-04-17 14:58:12 -0700184void grpc_metadata_batch_destroy(grpc_metadata_batch *comd) {
Craig Tiller8b282cb2015-04-17 14:57:44 -0700185 grpc_linked_mdelem *l;
186 for (l = comd->list.head; l; l = l->next) {
187 grpc_mdelem_unref(l->md);
188 }
189 for (l = comd->garbage.head; l; l = l->next) {
190 grpc_mdelem_unref(l->md);
191 }
Craig Tiller205aee12015-04-16 14:46:41 -0700192}
193
194void grpc_metadata_batch_add_head(grpc_metadata_batch *comd,
Craig Tiller76f5d462015-04-17 14:58:12 -0700195 grpc_linked_mdelem *storage,
196 grpc_mdelem *elem_to_add) {
Craig Tiller9c1043e2015-04-16 16:20:38 -0700197 GPR_ASSERT(elem_to_add);
Craig Tiller205aee12015-04-16 14:46:41 -0700198 storage->md = elem_to_add;
199 grpc_metadata_batch_link_head(comd, storage);
200}
201
202static void link_head(grpc_mdelem_list *list, grpc_linked_mdelem *storage) {
203 assert_valid_list(list);
Craig Tiller9c1043e2015-04-16 16:20:38 -0700204 GPR_ASSERT(storage->md);
Craig Tiller205aee12015-04-16 14:46:41 -0700205 storage->prev = NULL;
206 storage->next = list->head;
207 if (list->head != NULL) {
208 list->head->prev = storage;
209 } else {
210 list->tail = storage;
211 }
212 list->head = storage;
213 assert_valid_list(list);
214}
215
216void grpc_metadata_batch_link_head(grpc_metadata_batch *comd,
Craig Tiller76f5d462015-04-17 14:58:12 -0700217 grpc_linked_mdelem *storage) {
Craig Tiller205aee12015-04-16 14:46:41 -0700218 link_head(&comd->list, storage);
219}
220
221void grpc_metadata_batch_add_tail(grpc_metadata_batch *comd,
Craig Tiller76f5d462015-04-17 14:58:12 -0700222 grpc_linked_mdelem *storage,
223 grpc_mdelem *elem_to_add) {
Craig Tiller9c1043e2015-04-16 16:20:38 -0700224 GPR_ASSERT(elem_to_add);
Craig Tiller205aee12015-04-16 14:46:41 -0700225 storage->md = elem_to_add;
226 grpc_metadata_batch_link_tail(comd, storage);
227}
228
229static void link_tail(grpc_mdelem_list *list, grpc_linked_mdelem *storage) {
230 assert_valid_list(list);
Craig Tiller9c1043e2015-04-16 16:20:38 -0700231 GPR_ASSERT(storage->md);
Craig Tiller205aee12015-04-16 14:46:41 -0700232 storage->prev = list->tail;
233 storage->next = NULL;
234 if (list->tail != NULL) {
235 list->tail->next = storage;
236 } else {
237 list->head = storage;
238 }
239 list->tail = storage;
240 assert_valid_list(list);
241}
242
243void grpc_metadata_batch_link_tail(grpc_metadata_batch *comd,
Craig Tiller76f5d462015-04-17 14:58:12 -0700244 grpc_linked_mdelem *storage) {
Craig Tiller205aee12015-04-16 14:46:41 -0700245 link_tail(&comd->list, storage);
246}
247
Craig Tiller8b282cb2015-04-17 14:57:44 -0700248void grpc_metadata_batch_merge(grpc_metadata_batch *target,
Craig Tiller76f5d462015-04-17 14:58:12 -0700249 grpc_metadata_batch *add) {
Craig Tiller8b282cb2015-04-17 14:57:44 -0700250 grpc_linked_mdelem *l;
251 grpc_linked_mdelem *next;
252 for (l = add->list.head; l; l = next) {
253 next = l->next;
254 link_tail(&target->list, l);
Craig Tiller76f5d462015-04-17 14:58:12 -0700255 }
Craig Tiller8b282cb2015-04-17 14:57:44 -0700256 for (l = add->garbage.head; l; l = next) {
257 next = l->next;
258 link_tail(&target->garbage, l);
Craig Tiller76f5d462015-04-17 14:58:12 -0700259 }
Craig Tiller8b282cb2015-04-17 14:57:44 -0700260}
261
Craig Tiller205aee12015-04-16 14:46:41 -0700262void grpc_metadata_batch_filter(grpc_metadata_batch *comd,
Craig Tiller76f5d462015-04-17 14:58:12 -0700263 grpc_mdelem *(*filter)(void *user_data,
264 grpc_mdelem *elem),
265 void *user_data) {
Craig Tiller205aee12015-04-16 14:46:41 -0700266 grpc_linked_mdelem *l;
267 grpc_linked_mdelem *next;
268
269 assert_valid_list(&comd->list);
270 assert_valid_list(&comd->garbage);
271 for (l = comd->list.head; l; l = next) {
272 grpc_mdelem *orig = l->md;
273 grpc_mdelem *filt = filter(user_data, orig);
274 next = l->next;
275 if (filt == NULL) {
276 if (l->prev) {
277 l->prev->next = l->next;
278 }
279 if (l->next) {
280 l->next->prev = l->prev;
281 }
282 if (comd->list.head == l) {
283 comd->list.head = l->next;
284 }
285 if (comd->list.tail == l) {
286 comd->list.tail = l->prev;
287 }
288 assert_valid_list(&comd->list);
289 link_head(&comd->garbage, l);
290 } else if (filt != orig) {
291 grpc_mdelem_unref(orig);
292 l->md = filt;
293 }
294 }
295 assert_valid_list(&comd->list);
296 assert_valid_list(&comd->garbage);
297}