1 /*
2 *
3 * Copyright 2017 gRPC authors.
4 *
5 * 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
8 *
9 * http://www.apache.org/licenses/LICENSE-2.0
10 *
11 * 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.
16 *
17 */
18
19 #include <grpc/support/port_platform.h>
20
21 #include "src/core/ext/filters/client_channel/backup_poller.h"
22
23 #include <grpc/grpc.h>
24 #include <grpc/support/alloc.h>
25 #include <grpc/support/log.h>
26 #include <grpc/support/sync.h>
27
28 #include "src/core/ext/filters/client_channel/client_channel.h"
29 #include "src/core/lib/gpr/string.h"
30 #include "src/core/lib/gprpp/global_config.h"
31 #include "src/core/lib/iomgr/error.h"
32 #include "src/core/lib/iomgr/iomgr.h"
33 #include "src/core/lib/iomgr/pollset.h"
34 #include "src/core/lib/iomgr/timer.h"
35 #include "src/core/lib/surface/channel.h"
36 #include "src/core/lib/surface/completion_queue.h"
37
38 #define DEFAULT_POLL_INTERVAL_MS 5000
39
40 namespace {
41 struct backup_poller {
42 grpc_timer polling_timer;
43 grpc_closure run_poller_closure;
44 grpc_closure shutdown_closure;
45 gpr_mu* pollset_mu;
46 grpc_pollset* pollset; // guarded by pollset_mu
47 bool shutting_down; // guarded by pollset_mu
48 gpr_refcount refs;
49 gpr_refcount shutdown_refs;
50 };
51 } // namespace
52
53 static gpr_once g_once = GPR_ONCE_INIT;
54 static gpr_mu g_poller_mu;
55 static backup_poller* g_poller = nullptr; // guarded by g_poller_mu
56 // g_poll_interval_ms is set only once at the first time
57 // grpc_client_channel_start_backup_polling() is called, after that it is
58 // treated as const.
59 static int g_poll_interval_ms = DEFAULT_POLL_INTERVAL_MS;
60
61 GPR_GLOBAL_CONFIG_DEFINE_INT32(
62 grpc_client_channel_backup_poll_interval_ms, DEFAULT_POLL_INTERVAL_MS,
63 "Declares the interval in ms between two backup polls on client channels. "
64 "These polls are run in the timer thread so that gRPC can process "
65 "connection failures while there is no active polling thread. "
66 "They help reconnect disconnected client channels (mostly due to "
67 "idleness), so that the next RPC on this channel won't fail. Set to 0 to "
68 "turn off the backup polls.");
69
grpc_client_channel_global_init_backup_polling()70 void grpc_client_channel_global_init_backup_polling() {
71 gpr_once_init(&g_once, [] { gpr_mu_init(&g_poller_mu); });
72 int32_t poll_interval_ms =
73 GPR_GLOBAL_CONFIG_GET(grpc_client_channel_backup_poll_interval_ms);
74 if (poll_interval_ms < 0) {
75 gpr_log(GPR_ERROR,
76 "Invalid GRPC_CLIENT_CHANNEL_BACKUP_POLL_INTERVAL_MS: %d, "
77 "default value %d will be used.",
78 poll_interval_ms, g_poll_interval_ms);
79 } else {
80 g_poll_interval_ms = poll_interval_ms;
81 }
82 }
83
backup_poller_shutdown_unref(backup_poller * p)84 static void backup_poller_shutdown_unref(backup_poller* p) {
85 if (gpr_unref(&p->shutdown_refs)) {
86 grpc_pollset_destroy(p->pollset);
87 gpr_free(p->pollset);
88 gpr_free(p);
89 }
90 }
91
done_poller(void * arg,grpc_error *)92 static void done_poller(void* arg, grpc_error* /*error*/) {
93 backup_poller_shutdown_unref(static_cast<backup_poller*>(arg));
94 }
95
g_poller_unref()96 static void g_poller_unref() {
97 gpr_mu_lock(&g_poller_mu);
98 if (gpr_unref(&g_poller->refs)) {
99 backup_poller* p = g_poller;
100 g_poller = nullptr;
101 gpr_mu_unlock(&g_poller_mu);
102 gpr_mu_lock(p->pollset_mu);
103 p->shutting_down = true;
104 grpc_pollset_shutdown(
105 p->pollset, GRPC_CLOSURE_INIT(&p->shutdown_closure, done_poller, p,
106 grpc_schedule_on_exec_ctx));
107 gpr_mu_unlock(p->pollset_mu);
108 grpc_timer_cancel(&p->polling_timer);
109 backup_poller_shutdown_unref(p);
110 } else {
111 gpr_mu_unlock(&g_poller_mu);
112 }
113 }
114
run_poller(void * arg,grpc_error * error)115 static void run_poller(void* arg, grpc_error* error) {
116 backup_poller* p = static_cast<backup_poller*>(arg);
117 if (error != GRPC_ERROR_NONE) {
118 if (error != GRPC_ERROR_CANCELLED) {
119 GRPC_LOG_IF_ERROR("run_poller", GRPC_ERROR_REF(error));
120 }
121 backup_poller_shutdown_unref(p);
122 return;
123 }
124 gpr_mu_lock(p->pollset_mu);
125 if (p->shutting_down) {
126 gpr_mu_unlock(p->pollset_mu);
127 backup_poller_shutdown_unref(p);
128 return;
129 }
130 grpc_error* err =
131 grpc_pollset_work(p->pollset, nullptr, grpc_core::ExecCtx::Get()->Now());
132 gpr_mu_unlock(p->pollset_mu);
133 GRPC_LOG_IF_ERROR("Run client channel backup poller", err);
134 grpc_timer_init(&p->polling_timer,
135 grpc_core::ExecCtx::Get()->Now() + g_poll_interval_ms,
136 &p->run_poller_closure);
137 }
138
g_poller_init_locked()139 static void g_poller_init_locked() {
140 if (g_poller == nullptr) {
141 g_poller = static_cast<backup_poller*>(gpr_zalloc(sizeof(backup_poller)));
142 g_poller->pollset =
143 static_cast<grpc_pollset*>(gpr_zalloc(grpc_pollset_size()));
144 g_poller->shutting_down = false;
145 grpc_pollset_init(g_poller->pollset, &g_poller->pollset_mu);
146 gpr_ref_init(&g_poller->refs, 0);
147 // one for timer cancellation, one for pollset shutdown, one for g_poller
148 gpr_ref_init(&g_poller->shutdown_refs, 3);
149 GRPC_CLOSURE_INIT(&g_poller->run_poller_closure, run_poller, g_poller,
150 grpc_schedule_on_exec_ctx);
151 grpc_timer_init(&g_poller->polling_timer,
152 grpc_core::ExecCtx::Get()->Now() + g_poll_interval_ms,
153 &g_poller->run_poller_closure);
154 }
155 }
156
grpc_client_channel_start_backup_polling(grpc_pollset_set * interested_parties)157 void grpc_client_channel_start_backup_polling(
158 grpc_pollset_set* interested_parties) {
159 if (g_poll_interval_ms == 0 || grpc_iomgr_run_in_background()) {
160 return;
161 }
162 gpr_mu_lock(&g_poller_mu);
163 g_poller_init_locked();
164 gpr_ref(&g_poller->refs);
165 /* Get a reference to g_poller->pollset before releasing g_poller_mu to make
166 * TSAN happy. Otherwise, reading from g_poller (i.e g_poller->pollset) after
167 * releasing the lock and setting g_poller to NULL in g_poller_unref() is
168 * being flagged as a data-race by TSAN */
169 grpc_pollset* pollset = g_poller->pollset;
170 gpr_mu_unlock(&g_poller_mu);
171
172 grpc_pollset_set_add_pollset(interested_parties, pollset);
173 }
174
grpc_client_channel_stop_backup_polling(grpc_pollset_set * interested_parties)175 void grpc_client_channel_stop_backup_polling(
176 grpc_pollset_set* interested_parties) {
177 if (g_poll_interval_ms == 0 || grpc_iomgr_run_in_background()) {
178 return;
179 }
180 grpc_pollset_set_del_pollset(interested_parties, g_poller->pollset);
181 g_poller_unref();
182 }
183