blob: d7a51f3899fa622ba0f6c079fd48acb32f34bdf0 [file] [log] [blame]
Craig Tiller19482442016-01-25 09:59:20 -08001//
2//
Jan Tattermusch7897ae92017-06-07 22:57:36 +02003// Copyright 2016 gRPC authors.
Craig Tiller19482442016-01-25 09:59:20 -08004//
Jan Tattermusch7897ae92017-06-07 22:57:36 +02005// Licensed under the Apache License, Version 2.0 (the "License");
6// you may not use this file except in compliance with the License.
7// You may obtain a copy of the License at
Craig Tiller19482442016-01-25 09:59:20 -08008//
Jan Tattermusch7897ae92017-06-07 22:57:36 +02009// http://www.apache.org/licenses/LICENSE-2.0
Craig Tiller19482442016-01-25 09:59:20 -080010//
Jan Tattermusch7897ae92017-06-07 22:57:36 +020011// Unless required by applicable law or agreed to in writing, software
12// distributed under the License is distributed on an "AS IS" BASIS,
13// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
14// See the License for the specific language governing permissions and
15// limitations under the License.
Craig Tiller19482442016-01-25 09:59:20 -080016//
17//
Craig Tiller694cf8b2016-01-15 21:13:25 -080018
Craig Tiller9eb0fde2017-03-31 16:59:30 -070019#include "src/core/ext/filters/client_channel/subchannel_index.h"
Craig Tiller7391f132016-01-22 06:39:54 -080020
Craig Tiller8cdba662016-01-22 20:01:55 -080021#include <stdbool.h>
Craig Tiller7391f132016-01-22 06:39:54 -080022#include <string.h>
23
24#include <grpc/support/alloc.h>
25#include <grpc/support/avl.h>
Mark D. Roth2d7387c2016-08-17 13:51:05 -070026#include <grpc/support/string_util.h>
Craig Tiller7391f132016-01-22 06:39:54 -080027#include <grpc/support/tls.h>
28
Craig Tiller9533d042016-03-25 17:11:06 -070029#include "src/core/lib/channel/channel_args.h"
Craig Tiller7391f132016-01-22 06:39:54 -080030
Craig Tiller19482442016-01-25 09:59:20 -080031// a map of subchannel_key --> subchannel, used for detecting connections
32// to the same destination in order to share them
Craig Tiller694cf8b2016-01-15 21:13:25 -080033static gpr_avl g_subchannel_index;
34
35static gpr_mu g_mu;
36
Juanli Shen6502ecc2017-09-13 13:10:54 -070037static gpr_refcount g_refcount;
38
Craig Tiller7391f132016-01-22 06:39:54 -080039struct grpc_subchannel_key {
Craig Tiller5de79ee2016-01-25 08:16:02 -080040 grpc_subchannel_args args;
Craig Tiller694cf8b2016-01-15 21:13:25 -080041};
42
David Garcia Quintas9a4ed682017-07-13 16:12:30 -070043static bool g_force_creation = false;
44
Craig Tiller5de79ee2016-01-25 08:16:02 -080045static grpc_subchannel_key *create_key(
David Garcia Quintas87d5a312017-06-06 19:45:58 -070046 const grpc_subchannel_args *args,
Craig Tiller5de79ee2016-01-25 08:16:02 -080047 grpc_channel_args *(*copy_channel_args)(const grpc_channel_args *args)) {
Yash Tibrewalca3c1c02017-09-07 22:47:16 -070048 grpc_subchannel_key *k = (grpc_subchannel_key *)gpr_malloc(sizeof(*k));
Craig Tiller7391f132016-01-22 06:39:54 -080049 k->args.filter_count = args->filter_count;
Craig Tiller525654a2016-05-03 22:38:41 -070050 if (k->args.filter_count > 0) {
Yash Tibrewalca3c1c02017-09-07 22:47:16 -070051 k->args.filters = (const grpc_channel_filter **)gpr_malloc(
52 sizeof(*k->args.filters) * k->args.filter_count);
Craig Tiller525654a2016-05-03 22:38:41 -070053 memcpy((grpc_channel_filter *)k->args.filters, args->filters,
54 sizeof(*k->args.filters) * k->args.filter_count);
55 } else {
56 k->args.filters = NULL;
57 }
Craig Tiller7391f132016-01-22 06:39:54 -080058 k->args.args = copy_channel_args(args->args);
Craig Tiller694cf8b2016-01-15 21:13:25 -080059 return k;
60}
61
Mark D. Rothe3a21002016-10-24 13:29:05 -070062grpc_subchannel_key *grpc_subchannel_key_create(
David Garcia Quintas87d5a312017-06-06 19:45:58 -070063 const grpc_subchannel_args *args) {
64 return create_key(args, grpc_channel_args_normalize);
Craig Tiller694cf8b2016-01-15 21:13:25 -080065}
66
Craig Tiller7391f132016-01-22 06:39:54 -080067static grpc_subchannel_key *subchannel_key_copy(grpc_subchannel_key *k) {
David Garcia Quintas87d5a312017-06-06 19:45:58 -070068 return create_key(&k->args, grpc_channel_args_copy);
Craig Tiller694cf8b2016-01-15 21:13:25 -080069}
70
David Garcia Quintas87d5a312017-06-06 19:45:58 -070071int grpc_subchannel_key_compare(const grpc_subchannel_key *a,
72 const grpc_subchannel_key *b) {
David Garcia Quintas9a4ed682017-07-13 16:12:30 -070073 if (g_force_creation) return false;
David Garcia Quintas87d5a312017-06-06 19:45:58 -070074 int c = GPR_ICMP(a->args.filter_count, b->args.filter_count);
Craig Tiller7391f132016-01-22 06:39:54 -080075 if (c != 0) return c;
Craig Tiller525654a2016-05-03 22:38:41 -070076 if (a->args.filter_count > 0) {
77 c = memcmp(a->args.filters, b->args.filters,
78 a->args.filter_count * sizeof(*a->args.filters));
79 if (c != 0) return c;
80 }
Craig Tiller7391f132016-01-22 06:39:54 -080081 return grpc_channel_args_compare(a->args.args, b->args.args);
82}
83
Craig Tiller19482442016-01-25 09:59:20 -080084void grpc_subchannel_key_destroy(grpc_exec_ctx *exec_ctx,
85 grpc_subchannel_key *k) {
Craig Tillerfdb603f2016-01-25 11:56:24 -080086 gpr_free((grpc_channel_args *)k->args.filters);
Craig Tiller4cc1c352016-12-27 08:48:01 -080087 grpc_channel_args_destroy(exec_ctx, (grpc_channel_args *)k->args.args);
Craig Tiller694cf8b2016-01-15 21:13:25 -080088 gpr_free(k);
89}
90
yang-g59ef6482017-07-17 13:52:24 -070091static void sck_avl_destroy(void *p, void *user_data) {
92 grpc_exec_ctx *exec_ctx = (grpc_exec_ctx *)user_data;
Yash Tibrewalbc130da2017-09-12 22:44:08 -070093 grpc_subchannel_key_destroy(exec_ctx, (grpc_subchannel_key *)p);
Craig Tiller19482442016-01-25 09:59:20 -080094}
Craig Tiller694cf8b2016-01-15 21:13:25 -080095
yang-g59ef6482017-07-17 13:52:24 -070096static void *sck_avl_copy(void *p, void *unused) {
Yash Tibrewalbc130da2017-09-12 22:44:08 -070097 return subchannel_key_copy((grpc_subchannel_key *)p);
yang-g59ef6482017-07-17 13:52:24 -070098}
Craig Tiller694cf8b2016-01-15 21:13:25 -080099
yang-g59ef6482017-07-17 13:52:24 -0700100static long sck_avl_compare(void *a, void *b, void *unused) {
Yash Tibrewalbc130da2017-09-12 22:44:08 -0700101 return grpc_subchannel_key_compare((grpc_subchannel_key *)a,
102 (grpc_subchannel_key *)b);
Craig Tiller694cf8b2016-01-15 21:13:25 -0800103}
104
yang-g59ef6482017-07-17 13:52:24 -0700105static void scv_avl_destroy(void *p, void *user_data) {
106 grpc_exec_ctx *exec_ctx = (grpc_exec_ctx *)user_data;
Yash Tibrewalbc130da2017-09-12 22:44:08 -0700107 GRPC_SUBCHANNEL_WEAK_UNREF(exec_ctx, (grpc_subchannel *)p,
108 "subchannel_index");
Craig Tiller694cf8b2016-01-15 21:13:25 -0800109}
110
yang-g59ef6482017-07-17 13:52:24 -0700111static void *scv_avl_copy(void *p, void *unused) {
Yash Tibrewalbc130da2017-09-12 22:44:08 -0700112 GRPC_SUBCHANNEL_WEAK_REF((grpc_subchannel *)p, "subchannel_index");
Craig Tiller5de79ee2016-01-25 08:16:02 -0800113 return p;
Craig Tiller694cf8b2016-01-15 21:13:25 -0800114}
115
116static const gpr_avl_vtable subchannel_avl_vtable = {
Craig Tiller5de79ee2016-01-25 08:16:02 -0800117 .destroy_key = sck_avl_destroy,
118 .copy_key = sck_avl_copy,
119 .compare_keys = sck_avl_compare,
120 .destroy_value = scv_avl_destroy,
121 .copy_value = scv_avl_copy};
Craig Tiller694cf8b2016-01-15 21:13:25 -0800122
Craig Tiller8cdba662016-01-22 20:01:55 -0800123void grpc_subchannel_index_init(void) {
Craig Tiller5de79ee2016-01-25 08:16:02 -0800124 g_subchannel_index = gpr_avl_create(&subchannel_avl_vtable);
125 gpr_mu_init(&g_mu);
Juanli Shen6502ecc2017-09-13 13:10:54 -0700126 gpr_ref_init(&g_refcount, 1);
Craig Tiller8cdba662016-01-22 20:01:55 -0800127}
128
129void grpc_subchannel_index_shutdown(void) {
Juanli Shen6502ecc2017-09-13 13:10:54 -0700130 // TODO(juanlishen): This refcounting mechanism may lead to memory leackage.
131 // To solve that, we should force polling to flush any pending callbacks, then
132 // shutdown safely.
133 grpc_subchannel_index_unref();
Craig Tiller8cdba662016-01-22 20:01:55 -0800134}
135
Juanli Shen6502ecc2017-09-13 13:10:54 -0700136void grpc_subchannel_index_unref(void) {
137 if (gpr_unref(&g_refcount)) {
138 grpc_exec_ctx exec_ctx = GRPC_EXEC_CTX_INIT;
139 gpr_mu_destroy(&g_mu);
140 gpr_avl_unref(g_subchannel_index, &exec_ctx);
141 grpc_exec_ctx_finish(&exec_ctx);
142 }
143}
144
145void grpc_subchannel_index_ref(void) { gpr_ref_non_zero(&g_refcount); }
146
Craig Tiller5de79ee2016-01-25 08:16:02 -0800147grpc_subchannel *grpc_subchannel_index_find(grpc_exec_ctx *exec_ctx,
148 grpc_subchannel_key *key) {
Craig Tiller19482442016-01-25 09:59:20 -0800149 // Lock, and take a reference to the subchannel index.
150 // We don't need to do the search under a lock as avl's are immutable.
Craig Tiller5de79ee2016-01-25 08:16:02 -0800151 gpr_mu_lock(&g_mu);
yang-g59ef6482017-07-17 13:52:24 -0700152 gpr_avl index = gpr_avl_ref(g_subchannel_index, exec_ctx);
Craig Tiller5de79ee2016-01-25 08:16:02 -0800153 gpr_mu_unlock(&g_mu);
Craig Tiller694cf8b2016-01-15 21:13:25 -0800154
Yash Tibrewal7cdd99c2017-09-08 16:04:12 -0700155 grpc_subchannel *c = GRPC_SUBCHANNEL_REF_FROM_WEAK_REF(
156 (grpc_subchannel *)gpr_avl_get(index, key, exec_ctx), "index_find");
yang-g59ef6482017-07-17 13:52:24 -0700157 gpr_avl_unref(index, exec_ctx);
Craig Tiller694cf8b2016-01-15 21:13:25 -0800158
Craig Tiller5de79ee2016-01-25 08:16:02 -0800159 return c;
Craig Tiller694cf8b2016-01-15 21:13:25 -0800160}
161
Craig Tiller5de79ee2016-01-25 08:16:02 -0800162grpc_subchannel *grpc_subchannel_index_register(grpc_exec_ctx *exec_ctx,
163 grpc_subchannel_key *key,
164 grpc_subchannel *constructed) {
Craig Tiller5de79ee2016-01-25 08:16:02 -0800165 grpc_subchannel *c = NULL;
David Garcia Quintas6d8ca692017-05-11 14:29:34 -0700166 bool need_to_unref_constructed;
Craig Tiller694cf8b2016-01-15 21:13:25 -0800167
Craig Tiller5de79ee2016-01-25 08:16:02 -0800168 while (c == NULL) {
David Garcia Quintas6d8ca692017-05-11 14:29:34 -0700169 need_to_unref_constructed = false;
170
Craig Tiller19482442016-01-25 09:59:20 -0800171 // Compare and swap loop:
172 // - take a reference to the current index
Craig Tiller5de79ee2016-01-25 08:16:02 -0800173 gpr_mu_lock(&g_mu);
yang-g59ef6482017-07-17 13:52:24 -0700174 gpr_avl index = gpr_avl_ref(g_subchannel_index, exec_ctx);
Craig Tiller5de79ee2016-01-25 08:16:02 -0800175 gpr_mu_unlock(&g_mu);
Craig Tiller694cf8b2016-01-15 21:13:25 -0800176
Craig Tiller19482442016-01-25 09:59:20 -0800177 // - Check to see if a subchannel already exists
Yash Tibrewalca3c1c02017-09-07 22:47:16 -0700178 c = (grpc_subchannel *)gpr_avl_get(index, key, exec_ctx);
Craig Tiller5de79ee2016-01-25 08:16:02 -0800179 if (c != NULL) {
David Garcia Quintas6d8ca692017-05-11 14:29:34 -0700180 c = GRPC_SUBCHANNEL_REF_FROM_WEAK_REF(c, "index_register");
181 }
182 if (c != NULL) {
Craig Tiller19482442016-01-25 09:59:20 -0800183 // yes -> we're done
David Garcia Quintas6d8ca692017-05-11 14:29:34 -0700184 need_to_unref_constructed = true;
Craig Tiller5de79ee2016-01-25 08:16:02 -0800185 } else {
Craig Tiller19482442016-01-25 09:59:20 -0800186 // no -> update the avl and compare/swap
yang-g59ef6482017-07-17 13:52:24 -0700187 gpr_avl updated = gpr_avl_add(
188 gpr_avl_ref(index, exec_ctx), subchannel_key_copy(key),
189 GRPC_SUBCHANNEL_WEAK_REF(constructed, "index_register"), exec_ctx);
Craig Tiller694cf8b2016-01-15 21:13:25 -0800190
Craig Tiller19482442016-01-25 09:59:20 -0800191 // it may happen (but it's expected to be unlikely)
192 // that some other thread has changed the index:
193 // compare/swap here to check that, and retry as necessary
Craig Tiller5de79ee2016-01-25 08:16:02 -0800194 gpr_mu_lock(&g_mu);
195 if (index.root == g_subchannel_index.root) {
196 GPR_SWAP(gpr_avl, updated, g_subchannel_index);
197 c = constructed;
198 }
199 gpr_mu_unlock(&g_mu);
Craig Tiller19482442016-01-25 09:59:20 -0800200
yang-g59ef6482017-07-17 13:52:24 -0700201 gpr_avl_unref(updated, exec_ctx);
Craig Tiller5de79ee2016-01-25 08:16:02 -0800202 }
yang-g59ef6482017-07-17 13:52:24 -0700203 gpr_avl_unref(index, exec_ctx);
Craig Tiller5de79ee2016-01-25 08:16:02 -0800204 }
Craig Tiller694cf8b2016-01-15 21:13:25 -0800205
David Garcia Quintas6d8ca692017-05-11 14:29:34 -0700206 if (need_to_unref_constructed) {
207 GRPC_SUBCHANNEL_UNREF(exec_ctx, constructed, "index_register");
208 }
209
Craig Tiller5de79ee2016-01-25 08:16:02 -0800210 return c;
Craig Tiller694cf8b2016-01-15 21:13:25 -0800211}
Craig Tiller8cdba662016-01-22 20:01:55 -0800212
Craig Tiller5de79ee2016-01-25 08:16:02 -0800213void grpc_subchannel_index_unregister(grpc_exec_ctx *exec_ctx,
214 grpc_subchannel_key *key,
215 grpc_subchannel *constructed) {
Craig Tiller5de79ee2016-01-25 08:16:02 -0800216 bool done = false;
217 while (!done) {
Craig Tiller19482442016-01-25 09:59:20 -0800218 // Compare and swap loop:
219 // - take a reference to the current index
Craig Tiller5de79ee2016-01-25 08:16:02 -0800220 gpr_mu_lock(&g_mu);
yang-g59ef6482017-07-17 13:52:24 -0700221 gpr_avl index = gpr_avl_ref(g_subchannel_index, exec_ctx);
Craig Tiller5de79ee2016-01-25 08:16:02 -0800222 gpr_mu_unlock(&g_mu);
Craig Tiller8cdba662016-01-22 20:01:55 -0800223
Craig Tiller19482442016-01-25 09:59:20 -0800224 // Check to see if this key still refers to the previously
225 // registered subchannel
Yash Tibrewalca3c1c02017-09-07 22:47:16 -0700226 grpc_subchannel *c = (grpc_subchannel *)gpr_avl_get(index, key, exec_ctx);
Craig Tiller5de79ee2016-01-25 08:16:02 -0800227 if (c != constructed) {
yang-g59ef6482017-07-17 13:52:24 -0700228 gpr_avl_unref(index, exec_ctx);
Craig Tiller5de79ee2016-01-25 08:16:02 -0800229 break;
230 }
Craig Tiller8cdba662016-01-22 20:01:55 -0800231
Craig Tiller19482442016-01-25 09:59:20 -0800232 // compare and swap the update (some other thread may have
233 // mutated the index behind us)
yang-g59ef6482017-07-17 13:52:24 -0700234 gpr_avl updated =
235 gpr_avl_remove(gpr_avl_ref(index, exec_ctx), key, exec_ctx);
Craig Tiller8cdba662016-01-22 20:01:55 -0800236
Craig Tiller5de79ee2016-01-25 08:16:02 -0800237 gpr_mu_lock(&g_mu);
238 if (index.root == g_subchannel_index.root) {
239 GPR_SWAP(gpr_avl, updated, g_subchannel_index);
240 done = true;
Craig Tiller5de79ee2016-01-25 08:16:02 -0800241 }
242 gpr_mu_unlock(&g_mu);
Craig Tiller8cdba662016-01-22 20:01:55 -0800243
yang-g59ef6482017-07-17 13:52:24 -0700244 gpr_avl_unref(updated, exec_ctx);
245 gpr_avl_unref(index, exec_ctx);
Craig Tiller5de79ee2016-01-25 08:16:02 -0800246 }
Craig Tiller8cdba662016-01-22 20:01:55 -0800247}
David Garcia Quintas9a4ed682017-07-13 16:12:30 -0700248
249void grpc_subchannel_index_test_only_set_force_creation(bool force_creation) {
250 g_force_creation = force_creation;
251}