31
by Greg Burd
improvements and bug fixes |
1 |
/*-
|
2 |
* See the file LICENSE for redistribution information.
|
|
3 |
*
|
|
44
by Greg Burd
improvements and bug fixes |
4 |
* Copyright (c) 2005-2009 Oracle. All rights reserved.
|
31
by Greg Burd
improvements and bug fixes |
5 |
*
|
44
by Greg Burd
improvements and bug fixes |
6 |
* $Id$
|
31
by Greg Burd
improvements and bug fixes |
7 |
*/
|
8 |
||
9 |
#include "db_config.h" |
|
10 |
||
11 |
#define __INCLUDE_NETWORKING 1
|
|
12 |
#include "db_int.h" |
|
13 |
||
44
by Greg Burd
improvements and bug fixes |
14 |
static int kick_blockers __P((ENV *, REPMGR_CONNECTION *, void *)); |
15 |
static int mismatch_err __P((const ENV *)); |
|
39
by Greg Burd
improvements and bug fixes |
16 |
static int __repmgr_await_threads __P((ENV *)); |
31
by Greg Burd
improvements and bug fixes |
17 |
|
18 |
/*
|
|
19 |
* PUBLIC: int __repmgr_start __P((DB_ENV *, int, u_int32_t));
|
|
20 |
*/
|
|
21 |
int
|
|
22 |
__repmgr_start(dbenv, nthreads, flags) |
|
23 |
DB_ENV *dbenv; |
|
24 |
int nthreads; |
|
25 |
u_int32_t flags; |
|
26 |
{
|
|
27 |
DBT my_addr; |
|
39
by Greg Burd
improvements and bug fixes |
28 |
DB_REP *db_rep; |
44
by Greg Burd
improvements and bug fixes |
29 |
REP *rep; |
30 |
DB_THREAD_INFO *ip; |
|
39
by Greg Burd
improvements and bug fixes |
31 |
ENV *env; |
44
by Greg Burd
improvements and bug fixes |
32 |
REPMGR_RUNNABLE *messenger; |
33 |
int i, is_listener, locked, need_masterseek, ret; |
|
31
by Greg Burd
improvements and bug fixes |
34 |
|
39
by Greg Burd
improvements and bug fixes |
35 |
env = dbenv->env; |
36 |
db_rep = env->rep_handle; |
|
37 |
||
44
by Greg Burd
improvements and bug fixes |
38 |
switch (flags) { |
39 |
case DB_REP_CLIENT: |
|
40 |
case DB_REP_ELECTION: |
|
41 |
case DB_REP_MASTER: |
|
42 |
break; |
|
43 |
default: |
|
44 |
__db_errx(env, |
|
45 |
"repmgr_start: unrecognized flags parameter value"); |
|
46 |
return (EINVAL); |
|
47 |
}
|
|
48 |
||
49 |
ENV_REQUIRES_CONFIG_XX( |
|
50 |
env, rep_handle, "DB_ENV->repmgr_start", DB_INIT_REP); |
|
39
by Greg Burd
improvements and bug fixes |
51 |
if (!F_ISSET(env, ENV_THREAD)) { |
52 |
__db_errx(env, |
|
53 |
"Replication Manager needs an environment with DB_THREAD"); |
|
54 |
return (EINVAL); |
|
55 |
}
|
|
31
by Greg Burd
improvements and bug fixes |
56 |
|
44
by Greg Burd
improvements and bug fixes |
57 |
if (APP_IS_BASEAPI(env)) { |
58 |
__db_errx(env, |
|
59 |
"DB_ENV->repmgr_start: cannot call from base replication application"); |
|
60 |
return (EINVAL); |
|
61 |
}
|
|
62 |
||
31
by Greg Burd
improvements and bug fixes |
63 |
/* Check that the required initialization has been done. */
|
44
by Greg Burd
improvements and bug fixes |
64 |
if (db_rep->my_addr.host == NULL) { |
39
by Greg Burd
improvements and bug fixes |
65 |
__db_errx(env, |
31
by Greg Burd
improvements and bug fixes |
66 |
"repmgr_set_local_site must be called before repmgr_start"); |
67 |
return (EINVAL); |
|
68 |
}
|
|
69 |
||
70 |
if (db_rep->selector != NULL || db_rep->finished) { |
|
39
by Greg Burd
improvements and bug fixes |
71 |
__db_errx(env, |
31
by Greg Burd
improvements and bug fixes |
72 |
"DB_ENV->repmgr_start may not be called more than once"); |
73 |
return (EINVAL); |
|
74 |
}
|
|
75 |
||
44
by Greg Burd
improvements and bug fixes |
76 |
/*
|
77 |
* See if anyone else is already fulfilling the listener role. If not,
|
|
78 |
* we'll do so.
|
|
79 |
*/
|
|
80 |
rep = db_rep->region; |
|
81 |
ENV_ENTER(env, ip); |
|
82 |
MUTEX_LOCK(env, rep->mtx_repmgr); |
|
83 |
if (rep->listener == 0) { |
|
84 |
is_listener = TRUE; |
|
85 |
__os_id(dbenv, &rep->listener, NULL); |
|
86 |
} else { |
|
87 |
is_listener = FALSE; |
|
88 |
nthreads = 0; |
|
31
by Greg Burd
improvements and bug fixes |
89 |
}
|
44
by Greg Burd
improvements and bug fixes |
90 |
MUTEX_UNLOCK(env, rep->mtx_repmgr); |
91 |
ENV_LEAVE(env, ip); |
|
31
by Greg Burd
improvements and bug fixes |
92 |
|
44
by Greg Burd
improvements and bug fixes |
93 |
/*
|
94 |
* The minimum legal number of threads is either 1 or 0, depending upon
|
|
95 |
* whether we're the main process or a subordinate.
|
|
96 |
*/
|
|
97 |
locked = FALSE; |
|
98 |
if (nthreads < (is_listener ? 1 : 0)) { |
|
39
by Greg Burd
improvements and bug fixes |
99 |
__db_errx(env, |
31
by Greg Burd
improvements and bug fixes |
100 |
"repmgr_start: nthreads parameter must be >= 1"); |
44
by Greg Burd
improvements and bug fixes |
101 |
ret = EINVAL; |
102 |
goto err; |
|
31
by Greg Burd
improvements and bug fixes |
103 |
}
|
104 |
||
44
by Greg Burd
improvements and bug fixes |
105 |
if ((ret = __repmgr_init(env)) != 0) |
106 |
goto err; |
|
107 |
if (is_listener && (ret = __repmgr_listen(env)) != 0) |
|
108 |
goto err; |
|
31
by Greg Burd
improvements and bug fixes |
109 |
|
110 |
/*
|
|
111 |
* Make some sort of call to rep_start before starting other threads, to
|
|
112 |
* ensure that incoming messages being processed always have a rep
|
|
44
by Greg Burd
improvements and bug fixes |
113 |
* context properly configured. Note that in a way this is wasted, in
|
114 |
* the sense that any messages that rep_start sends won't really go
|
|
115 |
* anywhere, because we haven't started the select() thread yet, so we
|
|
116 |
* don't yet really have any connections to any remote sites. But
|
|
117 |
* trying to do it the other way ends up requiring complicated code;
|
|
118 |
* this way we know easily that by the time we receive a message, we've
|
|
119 |
* already called rep_start, so it'll be legal to call
|
|
120 |
* rep_process_message.
|
|
121 |
* Note that even if we're starting without recovery, we need a
|
|
122 |
* rep_start call in case we're using leases. Leases keep track of
|
|
123 |
* rep_start calls even within an env region lifetime.
|
|
31
by Greg Burd
improvements and bug fixes |
124 |
*/
|
44
by Greg Burd
improvements and bug fixes |
125 |
if ((ret = __rep_set_transport_int(env, SELF_EID, __repmgr_send)) != 0) |
126 |
goto err; |
|
127 |
need_masterseek = FALSE; |
|
128 |
if (!is_listener) { |
|
129 |
/* Another process currently already listening in this env. */
|
|
130 |
db_rep->master_eid = rep->master_id; |
|
131 |
} else if ((db_rep->init_policy = flags) == DB_REP_MASTER) |
|
39
by Greg Burd
improvements and bug fixes |
132 |
ret = __repmgr_become_master(env); |
31
by Greg Burd
improvements and bug fixes |
133 |
else { |
39
by Greg Burd
improvements and bug fixes |
134 |
if ((ret = __repmgr_prepare_my_addr(env, &my_addr)) != 0) |
44
by Greg Burd
improvements and bug fixes |
135 |
goto err; |
136 |
ret = __rep_start_int(env, &my_addr, DB_REP_CLIENT); |
|
39
by Greg Burd
improvements and bug fixes |
137 |
__os_free(env, my_addr.data); |
44
by Greg Burd
improvements and bug fixes |
138 |
|
139 |
if (rep->master_id == DB_EID_INVALID || |
|
140 |
rep->master_id == SELF_EID) { |
|
141 |
need_masterseek = TRUE; |
|
142 |
} else { |
|
143 |
/*
|
|
144 |
* Restarted without recovery. Use existing known
|
|
145 |
* master.
|
|
146 |
*/
|
|
147 |
db_rep->master_eid = rep->master_id; |
|
148 |
}
|
|
149 |
}
|
|
150 |
if (ret != 0) |
|
151 |
goto err; |
|
152 |
if ((ret = __repmgr_start_selector(env)) != 0) |
|
153 |
goto err; |
|
154 |
||
155 |
if (is_listener) { |
|
156 |
/*
|
|
157 |
* Since these allocated memory blocks are used by other
|
|
158 |
* threads, we have to be a bit careful about freeing them in
|
|
159 |
* case of any errors. __repmgr_await_threads (which we call in
|
|
160 |
* the err: coda below) takes care of that.
|
|
161 |
*/
|
|
162 |
if ((ret = __os_calloc(env, (u_int)nthreads, |
|
163 |
sizeof(REPMGR_RUNNABLE *), &db_rep->messengers)) != 0) |
|
164 |
goto err; |
|
165 |
db_rep->nthreads = nthreads; |
|
166 |
||
167 |
for (i = 0; i < nthreads; i++) { |
|
168 |
if ((ret = __os_calloc(env, 1, sizeof(REPMGR_RUNNABLE), |
|
169 |
&messenger)) != 0) |
|
170 |
goto err; |
|
171 |
||
172 |
messenger->env = env; |
|
173 |
messenger->run = __repmgr_msg_thread; |
|
174 |
if ((ret = __repmgr_thread_start(env, |
|
175 |
messenger)) != 0) { |
|
176 |
__os_free(env, messenger); |
|
177 |
goto err; |
|
178 |
}
|
|
179 |
db_rep->messengers[i] = messenger; |
|
180 |
}
|
|
181 |
}
|
|
182 |
||
183 |
if (need_masterseek) { |
|
184 |
LOCK_MUTEX(db_rep->mutex); |
|
185 |
locked = TRUE; |
|
186 |
if ((ret = __repmgr_init_election(env, ELECT_REPSTART)) != 0) |
|
187 |
goto err; |
|
188 |
UNLOCK_MUTEX(db_rep->mutex); |
|
189 |
locked = FALSE; |
|
190 |
}
|
|
191 |
||
192 |
return (is_listener ? 0 : DB_REP_IGNORE); |
|
193 |
||
194 |
err: |
|
195 |
/* If we couldn't succeed at everything, undo the parts we did do. */
|
|
196 |
if (locked) |
|
197 |
UNLOCK_MUTEX(db_rep->mutex); |
|
198 |
if (db_rep->selector != NULL) { |
|
199 |
(void)__repmgr_stop_threads(env); |
|
200 |
(void)__repmgr_await_threads(env); |
|
201 |
}
|
|
202 |
LOCK_MUTEX(db_rep->mutex); |
|
203 |
(void)__repmgr_net_close(env); |
|
204 |
if (REPMGR_INITED(db_rep)) |
|
205 |
(void)__repmgr_deinit(env); |
|
206 |
UNLOCK_MUTEX(db_rep->mutex); |
|
207 |
return (ret); |
|
208 |
}
|
|
209 |
||
210 |
/*
|
|
211 |
* PUBLIC: int __repmgr_autostart __P((ENV *));
|
|
212 |
*
|
|
213 |
* Preconditions: rep_start() has been called; we're within an ENV_ENTER.
|
|
214 |
* Because of this, we mustn't call __rep_set_transport(), but rather we
|
|
215 |
* poke in send() function address manually.
|
|
216 |
*/
|
|
217 |
int
|
|
218 |
__repmgr_autostart(env) |
|
219 |
ENV *env; |
|
220 |
{
|
|
221 |
DB_REP *db_rep; |
|
222 |
int ret; |
|
223 |
||
224 |
db_rep = env->rep_handle; |
|
225 |
||
226 |
DB_ASSERT(env, REP_ON(env)); |
|
227 |
LOCK_MUTEX(db_rep->mutex); |
|
228 |
||
229 |
if (REPMGR_INITED(db_rep)) |
|
230 |
ret = 0; |
|
231 |
else
|
|
232 |
ret = __repmgr_init(env); |
|
233 |
if (ret != 0) |
|
234 |
goto out; |
|
235 |
||
236 |
RPRINT(env, DB_VERB_REPMGR_MISC, |
|
237 |
(env, "Automatically joining existing repmgr env")); |
|
238 |
||
239 |
db_rep->send = __repmgr_send; |
|
240 |
||
241 |
if (db_rep->selector == NULL && !db_rep->finished) |
|
242 |
ret = __repmgr_start_selector(env); |
|
243 |
||
244 |
out: |
|
245 |
UNLOCK_MUTEX(db_rep->mutex); |
|
246 |
return (ret); |
|
247 |
}
|
|
248 |
||
249 |
/*
|
|
250 |
* PUBLIC: int __repmgr_start_selector __P((ENV *));
|
|
251 |
*/
|
|
252 |
int
|
|
253 |
__repmgr_start_selector(env) |
|
254 |
ENV *env; |
|
255 |
{
|
|
256 |
DB_REP *db_rep; |
|
257 |
REPMGR_RUNNABLE *selector; |
|
258 |
int ret; |
|
259 |
||
260 |
db_rep = env->rep_handle; |
|
39
by Greg Burd
improvements and bug fixes |
261 |
if ((ret = __os_calloc(env, 1, sizeof(REPMGR_RUNNABLE), &selector)) |
31
by Greg Burd
improvements and bug fixes |
262 |
!= 0) |
263 |
return (ret); |
|
39
by Greg Burd
improvements and bug fixes |
264 |
selector->env = env; |
31
by Greg Burd
improvements and bug fixes |
265 |
selector->run = __repmgr_select_thread; |
44
by Greg Burd
improvements and bug fixes |
266 |
|
267 |
/*
|
|
268 |
* In case the select thread ever examines db_rep->selector, set it
|
|
269 |
* before starting the thread (since once we create it we could be
|
|
270 |
* racing with it).
|
|
271 |
*/
|
|
272 |
db_rep->selector = selector; |
|
39
by Greg Burd
improvements and bug fixes |
273 |
if ((ret = __repmgr_thread_start(env, selector)) != 0) { |
274 |
__db_err(env, ret, "can't start selector thread"); |
|
275 |
__os_free(env, selector); |
|
44
by Greg Burd
improvements and bug fixes |
276 |
db_rep->selector = NULL; |
31
by Greg Burd
improvements and bug fixes |
277 |
return (ret); |
39
by Greg Burd
improvements and bug fixes |
278 |
}
|
44
by Greg Burd
improvements and bug fixes |
279 |
|
280 |
return (0); |
|
31
by Greg Burd
improvements and bug fixes |
281 |
}
|
282 |
||
283 |
/*
|
|
39
by Greg Burd
improvements and bug fixes |
284 |
* PUBLIC: int __repmgr_close __P((ENV *));
|
31
by Greg Burd
improvements and bug fixes |
285 |
*/
|
286 |
int
|
|
39
by Greg Burd
improvements and bug fixes |
287 |
__repmgr_close(env) |
288 |
ENV *env; |
|
31
by Greg Burd
improvements and bug fixes |
289 |
{
|
290 |
DB_REP *db_rep; |
|
291 |
int ret, t_ret; |
|
292 |
||
293 |
ret = 0; |
|
39
by Greg Burd
improvements and bug fixes |
294 |
db_rep = env->rep_handle; |
31
by Greg Burd
improvements and bug fixes |
295 |
if (db_rep->selector != NULL) { |
39
by Greg Burd
improvements and bug fixes |
296 |
RPRINT(env, DB_VERB_REPMGR_MISC, |
297 |
(env, "Stopping repmgr threads")); |
|
298 |
ret = __repmgr_stop_threads(env); |
|
299 |
if ((t_ret = __repmgr_await_threads(env)) != 0 && ret == 0) |
|
31
by Greg Burd
improvements and bug fixes |
300 |
ret = t_ret; |
39
by Greg Burd
improvements and bug fixes |
301 |
RPRINT(env, DB_VERB_REPMGR_MISC, |
302 |
(env, "Repmgr threads are finished")); |
|
31
by Greg Burd
improvements and bug fixes |
303 |
}
|
304 |
||
39
by Greg Burd
improvements and bug fixes |
305 |
if ((t_ret = __repmgr_net_close(env)) != 0 && ret == 0) |
31
by Greg Burd
improvements and bug fixes |
306 |
ret = t_ret; |
307 |
||
44
by Greg Burd
improvements and bug fixes |
308 |
if ((t_ret = __repmgr_deinit(env)) != 0 && ret == 0) |
31
by Greg Burd
improvements and bug fixes |
309 |
ret = t_ret; |
310 |
||
311 |
return (ret); |
|
312 |
}
|
|
313 |
||
314 |
/*
|
|
315 |
* PUBLIC: int __repmgr_set_ack_policy __P((DB_ENV *, int));
|
|
316 |
*/
|
|
317 |
int
|
|
318 |
__repmgr_set_ack_policy(dbenv, policy) |
|
319 |
DB_ENV *dbenv; |
|
320 |
int policy; |
|
321 |
{
|
|
44
by Greg Burd
improvements and bug fixes |
322 |
DB_REP *db_rep; |
39
by Greg Burd
improvements and bug fixes |
323 |
ENV *env; |
324 |
||
325 |
env = dbenv->env; |
|
44
by Greg Burd
improvements and bug fixes |
326 |
db_rep = env->rep_handle; |
327 |
||
328 |
ENV_NOT_CONFIGURED( |
|
329 |
env, db_rep->region, "DB_ENV->repmgr_set_ack_policy", DB_INIT_REP); |
|
330 |
||
331 |
if (APP_IS_BASEAPI(env)) { |
|
332 |
__db_errx(env, "%s %s", "DB_ENV->repmgr_set_ack_policy:", |
|
333 |
"cannot call from base replication application"); |
|
334 |
return (EINVAL); |
|
335 |
}
|
|
39
by Greg Burd
improvements and bug fixes |
336 |
|
31
by Greg Burd
improvements and bug fixes |
337 |
switch (policy) { |
338 |
case DB_REPMGR_ACKS_ALL: /* FALLTHROUGH */ |
|
339 |
case DB_REPMGR_ACKS_ALL_PEERS: /* FALLTHROUGH */ |
|
340 |
case DB_REPMGR_ACKS_NONE: /* FALLTHROUGH */ |
|
341 |
case DB_REPMGR_ACKS_ONE: /* FALLTHROUGH */ |
|
342 |
case DB_REPMGR_ACKS_ONE_PEER: /* FALLTHROUGH */ |
|
343 |
case DB_REPMGR_ACKS_QUORUM: |
|
39
by Greg Burd
improvements and bug fixes |
344 |
env->rep_handle->perm_policy = policy; |
44
by Greg Burd
improvements and bug fixes |
345 |
/*
|
346 |
* Setting an ack policy makes this a replication manager
|
|
347 |
* application.
|
|
348 |
*/
|
|
349 |
APP_SET_REPMGR(env); |
|
31
by Greg Burd
improvements and bug fixes |
350 |
return (0); |
351 |
default: |
|
39
by Greg Burd
improvements and bug fixes |
352 |
__db_errx(env, |
353 |
"unknown ack_policy in DB_ENV->repmgr_set_ack_policy"); |
|
31
by Greg Burd
improvements and bug fixes |
354 |
return (EINVAL); |
355 |
}
|
|
356 |
}
|
|
357 |
||
358 |
/*
|
|
359 |
* PUBLIC: int __repmgr_get_ack_policy __P((DB_ENV *, int *));
|
|
360 |
*/
|
|
361 |
int
|
|
362 |
__repmgr_get_ack_policy(dbenv, policy) |
|
363 |
DB_ENV *dbenv; |
|
364 |
int *policy; |
|
365 |
{
|
|
44
by Greg Burd
improvements and bug fixes |
366 |
DB_REP *db_rep; |
39
by Greg Burd
improvements and bug fixes |
367 |
ENV *env; |
368 |
||
369 |
env = dbenv->env; |
|
44
by Greg Burd
improvements and bug fixes |
370 |
db_rep = env->rep_handle; |
371 |
||
372 |
ENV_NOT_CONFIGURED( |
|
373 |
env, db_rep->region, "DB_ENV->repmgr_get_ack_policy", DB_INIT_REP); |
|
374 |
||
39
by Greg Burd
improvements and bug fixes |
375 |
*policy = env->rep_handle->perm_policy; |
31
by Greg Burd
improvements and bug fixes |
376 |
return (0); |
377 |
}
|
|
378 |
||
379 |
/*
|
|
39
by Greg Burd
improvements and bug fixes |
380 |
* PUBLIC: int __repmgr_env_create __P((ENV *, DB_REP *));
|
31
by Greg Burd
improvements and bug fixes |
381 |
*/
|
382 |
int
|
|
39
by Greg Burd
improvements and bug fixes |
383 |
__repmgr_env_create(env, db_rep) |
384 |
ENV *env; |
|
31
by Greg Burd
improvements and bug fixes |
385 |
DB_REP *db_rep; |
386 |
{
|
|
44
by Greg Burd
improvements and bug fixes |
387 |
COMPQUIET(env, NULL); |
31
by Greg Burd
improvements and bug fixes |
388 |
|
389 |
/* Set some default values. */
|
|
38
by Greg Burd
[#15788] Fixes a bug which could lead to slow performance of internal init under Replication Manager, as evidenced by "queue limit exceeded" messages in verbose replication diagnostic output. |
390 |
db_rep->ack_timeout = DB_REPMGR_DEFAULT_ACK_TIMEOUT; |
391 |
db_rep->connection_retry_wait = DB_REPMGR_DEFAULT_CONNECTION_RETRY; |
|
392 |
db_rep->election_retry_wait = DB_REPMGR_DEFAULT_ELECTION_RETRY; |
|
31
by Greg Burd
improvements and bug fixes |
393 |
db_rep->config_nsites = 0; |
394 |
db_rep->peer = DB_EID_INVALID; |
|
395 |
db_rep->perm_policy = DB_REPMGR_ACKS_QUORUM; |
|
396 |
||
44
by Greg Burd
improvements and bug fixes |
397 |
db_rep->listen_fd = INVALID_SOCKET; |
398 |
db_rep->master_eid = DB_EID_INVALID; |
|
399 |
TAILQ_INIT(&db_rep->connections); |
|
400 |
TAILQ_INIT(&db_rep->retries); |
|
401 |
||
402 |
db_rep->input_queue.size = 0; |
|
403 |
STAILQ_INIT(&db_rep->input_queue.header); |
|
404 |
||
405 |
__repmgr_env_create_pf(db_rep); |
|
406 |
||
407 |
return (0); |
|
31
by Greg Burd
improvements and bug fixes |
408 |
}
|
409 |
||
410 |
/*
|
|
39
by Greg Burd
improvements and bug fixes |
411 |
* PUBLIC: void __repmgr_env_destroy __P((ENV *, DB_REP *));
|
31
by Greg Burd
improvements and bug fixes |
412 |
*/
|
413 |
void
|
|
39
by Greg Burd
improvements and bug fixes |
414 |
__repmgr_env_destroy(env, db_rep) |
415 |
ENV *env; |
|
31
by Greg Burd
improvements and bug fixes |
416 |
DB_REP *db_rep; |
417 |
{
|
|
39
by Greg Burd
improvements and bug fixes |
418 |
__repmgr_queue_destroy(env); |
419 |
__repmgr_net_destroy(env, db_rep); |
|
31
by Greg Burd
improvements and bug fixes |
420 |
if (db_rep->messengers != NULL) { |
39
by Greg Burd
improvements and bug fixes |
421 |
__os_free(env, db_rep->messengers); |
31
by Greg Burd
improvements and bug fixes |
422 |
db_rep->messengers = NULL; |
423 |
}
|
|
424 |
}
|
|
425 |
||
426 |
/*
|
|
39
by Greg Burd
improvements and bug fixes |
427 |
* PUBLIC: int __repmgr_stop_threads __P((ENV *));
|
31
by Greg Burd
improvements and bug fixes |
428 |
*/
|
429 |
int
|
|
39
by Greg Burd
improvements and bug fixes |
430 |
__repmgr_stop_threads(env) |
431 |
ENV *env; |
|
31
by Greg Burd
improvements and bug fixes |
432 |
{
|
433 |
DB_REP *db_rep; |
|
434 |
int ret; |
|
435 |
||
39
by Greg Burd
improvements and bug fixes |
436 |
db_rep = env->rep_handle; |
31
by Greg Burd
improvements and bug fixes |
437 |
|
438 |
/*
|
|
439 |
* Hold mutex for the purpose of waking up threads, but then get out of
|
|
440 |
* the way to let them clean up and exit.
|
|
441 |
*/
|
|
442 |
LOCK_MUTEX(db_rep->mutex); |
|
443 |
db_rep->finished = TRUE; |
|
444 |
if (db_rep->elect_thread != NULL && |
|
445 |
(ret = __repmgr_signal(&db_rep->check_election)) != 0) |
|
446 |
goto unlock; |
|
447 |
||
448 |
if ((ret = __repmgr_signal(&db_rep->queue_nonempty)) != 0) |
|
449 |
goto unlock; |
|
38
by Greg Burd
[#15788] Fixes a bug which could lead to slow performance of internal init under Replication Manager, as evidenced by "queue limit exceeded" messages in verbose replication diagnostic output. |
450 |
|
44
by Greg Burd
improvements and bug fixes |
451 |
if ((ret = __repmgr_each_connection(env, |
452 |
kick_blockers, NULL, TRUE)) != 0) |
|
453 |
goto unlock; |
|
31
by Greg Burd
improvements and bug fixes |
454 |
UNLOCK_MUTEX(db_rep->mutex); |
455 |
||
39
by Greg Burd
improvements and bug fixes |
456 |
return (__repmgr_wake_main_thread(env)); |
31
by Greg Burd
improvements and bug fixes |
457 |
|
458 |
unlock: |
|
459 |
UNLOCK_MUTEX(db_rep->mutex); |
|
460 |
return (ret); |
|
461 |
}
|
|
462 |
||
463 |
static int |
|
44
by Greg Burd
improvements and bug fixes |
464 |
kick_blockers(env, conn, unused) |
465 |
ENV *env; |
|
466 |
REPMGR_CONNECTION *conn; |
|
467 |
void *unused; |
|
468 |
{
|
|
469 |
COMPQUIET(env, NULL); |
|
470 |
COMPQUIET(unused, NULL); |
|
471 |
||
472 |
return (conn->blockers > 0 ? __repmgr_signal(&conn->drained) : 0); |
|
473 |
}
|
|
474 |
||
475 |
static int |
|
39
by Greg Burd
improvements and bug fixes |
476 |
__repmgr_await_threads(env) |
477 |
ENV *env; |
|
31
by Greg Burd
improvements and bug fixes |
478 |
{
|
479 |
DB_REP *db_rep; |
|
480 |
REPMGR_RUNNABLE *messenger; |
|
481 |
int ret, t_ret, i; |
|
482 |
||
39
by Greg Burd
improvements and bug fixes |
483 |
db_rep = env->rep_handle; |
31
by Greg Burd
improvements and bug fixes |
484 |
ret = 0; |
485 |
if (db_rep->elect_thread != NULL) { |
|
486 |
ret = __repmgr_thread_join(db_rep->elect_thread); |
|
39
by Greg Burd
improvements and bug fixes |
487 |
__os_free(env, db_rep->elect_thread); |
31
by Greg Burd
improvements and bug fixes |
488 |
db_rep->elect_thread = NULL; |
489 |
}
|
|
490 |
||
44
by Greg Burd
improvements and bug fixes |
491 |
for (i = 0; |
492 |
i < db_rep->nthreads && db_rep->messengers[i] != NULL; i++) { |
|
31
by Greg Burd
improvements and bug fixes |
493 |
messenger = db_rep->messengers[i]; |
494 |
if ((t_ret = __repmgr_thread_join(messenger)) != 0 && ret == 0) |
|
495 |
ret = t_ret; |
|
39
by Greg Burd
improvements and bug fixes |
496 |
__os_free(env, messenger); |
31
by Greg Burd
improvements and bug fixes |
497 |
}
|
39
by Greg Burd
improvements and bug fixes |
498 |
__os_free(env, db_rep->messengers); |
31
by Greg Burd
improvements and bug fixes |
499 |
db_rep->messengers = NULL; |
500 |
||
501 |
if (db_rep->selector != NULL) { |
|
502 |
if ((t_ret = __repmgr_thread_join(db_rep->selector)) != 0 && |
|
503 |
ret == 0) |
|
504 |
ret = t_ret; |
|
39
by Greg Burd
improvements and bug fixes |
505 |
__os_free(env, db_rep->selector); |
31
by Greg Burd
improvements and bug fixes |
506 |
db_rep->selector = NULL; |
507 |
}
|
|
508 |
||
509 |
return (ret); |
|
510 |
}
|
|
511 |
||
512 |
/*
|
|
513 |
* PUBLIC: int __repmgr_set_local_site __P((DB_ENV *, const char *, u_int,
|
|
514 |
* PUBLIC: u_int32_t));
|
|
515 |
*/
|
|
516 |
int
|
|
517 |
__repmgr_set_local_site(dbenv, host, port, flags) |
|
518 |
DB_ENV *dbenv; |
|
519 |
const char *host; |
|
520 |
u_int port; |
|
521 |
u_int32_t flags; |
|
522 |
{
|
|
523 |
DB_REP *db_rep; |
|
44
by Greg Burd
improvements and bug fixes |
524 |
DB_THREAD_INFO *ip; |
39
by Greg Burd
improvements and bug fixes |
525 |
ENV *env; |
44
by Greg Burd
improvements and bug fixes |
526 |
REGENV *renv; |
527 |
REGINFO *infop; |
|
528 |
REP *rep; |
|
31
by Greg Burd
improvements and bug fixes |
529 |
repmgr_netaddr_t addr; |
44
by Greg Burd
improvements and bug fixes |
530 |
char *myhost; |
31
by Greg Burd
improvements and bug fixes |
531 |
int locked, ret; |
39
by Greg Burd
improvements and bug fixes |
532 |
|
533 |
env = dbenv->env; |
|
44
by Greg Burd
improvements and bug fixes |
534 |
db_rep = env->rep_handle; |
535 |
||
536 |
ENV_NOT_CONFIGURED( |
|
537 |
env, db_rep->region, "DB_ENV->repmgr_set_local_site", DB_INIT_REP); |
|
538 |
||
539 |
if (APP_IS_BASEAPI(env)) { |
|
540 |
__db_errx(env, "%s %s", "DB_ENV->repmgr_set_local_site:", |
|
541 |
"cannot call from base replication application"); |
|
542 |
return (EINVAL); |
|
543 |
}
|
|
544 |
||
545 |
if (db_rep->selector != NULL) { |
|
546 |
__db_errx(env, |
|
547 |
"DB_ENV->repmgr_set_local_site: must be called before DB_ENV->repmgr_start"); |
|
548 |
return (EINVAL); |
|
549 |
}
|
|
31
by Greg Burd
improvements and bug fixes |
550 |
|
551 |
if (flags != 0) |
|
39
by Greg Burd
improvements and bug fixes |
552 |
return (__db_ferr(env, "DB_ENV->repmgr_set_local_site", 0)); |
31
by Greg Burd
improvements and bug fixes |
553 |
|
44
by Greg Burd
improvements and bug fixes |
554 |
if (host == NULL || port == 0) { |
39
by Greg Burd
improvements and bug fixes |
555 |
__db_errx(env, |
44
by Greg Burd
improvements and bug fixes |
556 |
"repmgr_set_local_site: host name and port (>0) required"); |
39
by Greg Burd
improvements and bug fixes |
557 |
return (EINVAL); |
558 |
}
|
|
559 |
||
44
by Greg Burd
improvements and bug fixes |
560 |
/*
|
561 |
* If the local site address hasn't already been set, just set it from
|
|
562 |
* the given inputs. If it has, all we do is verify that it matches
|
|
563 |
* what had already been set previously.
|
|
564 |
*
|
|
565 |
* Do this in the shared region if we have one, or else just in the
|
|
566 |
* local handle.
|
|
567 |
*
|
|
568 |
* In either case, don't perturb global structures until we're sure
|
|
569 |
* everything will succeed.
|
|
570 |
*/
|
|
571 |
COMPQUIET(rep, NULL); |
|
572 |
COMPQUIET(ip, NULL); |
|
573 |
COMPQUIET(renv, NULL); |
|
574 |
locked = FALSE; |
|
575 |
ret = 0; |
|
576 |
if (REP_ON(env)) { |
|
577 |
rep = db_rep->region; |
|
578 |
ENV_ENTER(env, ip); |
|
579 |
MUTEX_LOCK(env, rep->mtx_repmgr); |
|
580 |
||
581 |
infop = env->reginfo; |
|
582 |
renv = infop->primary; |
|
583 |
MUTEX_LOCK(env, renv->mtx_regenv); |
|
31
by Greg Burd
improvements and bug fixes |
584 |
locked = TRUE; |
44
by Greg Burd
improvements and bug fixes |
585 |
if (rep->my_addr.host == INVALID_ROFF) { |
586 |
if ((ret = __repmgr_pack_netaddr(env, |
|
587 |
host, port, NULL, &addr)) != 0) |
|
588 |
goto unlock; |
|
589 |
||
590 |
if ((ret = __env_alloc(infop, |
|
591 |
strlen(host)+1, &myhost)) == 0) { |
|
592 |
(void)strcpy(myhost, host); |
|
593 |
rep->my_addr.host = R_OFFSET(infop, myhost); |
|
594 |
rep->my_addr.port = port; |
|
595 |
} else { |
|
596 |
__repmgr_cleanup_netaddr(env, &addr); |
|
597 |
goto unlock; |
|
598 |
}
|
|
599 |
memcpy(&db_rep->my_addr, &addr, sizeof(addr)); |
|
600 |
rep->siteaddr_seq++; |
|
601 |
} else { |
|
602 |
myhost = R_ADDR(infop, rep->my_addr.host); |
|
603 |
if (strcmp(myhost, host) != 0 || |
|
604 |
port != rep->my_addr.port) { |
|
605 |
ret = mismatch_err(env); |
|
606 |
goto unlock; |
|
607 |
}
|
|
608 |
}
|
|
609 |
} else { |
|
610 |
if (db_rep->my_addr.host == NULL) { |
|
611 |
if ((ret = __repmgr_pack_netaddr(env, |
|
612 |
host, port, NULL, &db_rep->my_addr)) != 0) |
|
613 |
goto unlock; |
|
614 |
} else if (strcmp(host, db_rep->my_addr.host) != 0 || |
|
615 |
port != db_rep->my_addr.port) { |
|
616 |
ret = mismatch_err(env); |
|
617 |
goto unlock; |
|
618 |
}
|
|
619 |
}
|
|
620 |
||
621 |
unlock: |
|
622 |
if (locked) { |
|
623 |
MUTEX_UNLOCK(env, renv->mtx_regenv); |
|
624 |
MUTEX_UNLOCK(env, rep->mtx_repmgr); |
|
625 |
ENV_LEAVE(env, ip); |
|
626 |
}
|
|
627 |
/*
|
|
628 |
* Setting a local site makes this a replication manager application.
|
|
629 |
*/
|
|
630 |
if (ret == 0) |
|
631 |
APP_SET_REPMGR(env); |
|
632 |
return (ret); |
|
633 |
}
|
|
634 |
||
635 |
static int |
|
636 |
mismatch_err(env) |
|
637 |
const ENV *env; |
|
638 |
{
|
|
639 |
__db_errx(env, "A (different) local site address has already been set"); |
|
640 |
return (EINVAL); |
|
31
by Greg Burd
improvements and bug fixes |
641 |
}
|
642 |
||
643 |
/*
|
|
644 |
* If the application only calls this method from a single thread (e.g., during
|
|
645 |
* its initialization), it will avoid the problems with the non-thread-safe host
|
|
646 |
* name lookup. In any case, if we relegate the blocking lookup to here it
|
|
647 |
* won't affect our select() loop.
|
|
648 |
*
|
|
649 |
* PUBLIC: int __repmgr_add_remote_site __P((DB_ENV *, const char *, u_int,
|
|
650 |
* PUBLIC: int *, u_int32_t));
|
|
651 |
*/
|
|
652 |
int
|
|
653 |
__repmgr_add_remote_site(dbenv, host, port, eidp, flags) |
|
654 |
DB_ENV *dbenv; |
|
655 |
const char *host; |
|
656 |
u_int port; |
|
657 |
int *eidp; |
|
658 |
u_int32_t flags; |
|
659 |
{
|
|
660 |
DB_REP *db_rep; |
|
39
by Greg Burd
improvements and bug fixes |
661 |
ENV *env; |
31
by Greg Burd
improvements and bug fixes |
662 |
REPMGR_SITE *site; |
663 |
int eid, locked, ret; |
|
664 |
||
39
by Greg Burd
improvements and bug fixes |
665 |
env = dbenv->env; |
44
by Greg Burd
improvements and bug fixes |
666 |
db_rep = env->rep_handle; |
667 |
locked = FALSE; |
|
668 |
ret = 0; |
|
669 |
||
670 |
ENV_NOT_CONFIGURED( |
|
671 |
env, db_rep->region, "DB_ENV->repmgr_add_remote_site", DB_INIT_REP); |
|
672 |
||
673 |
if (APP_IS_BASEAPI(env)) { |
|
674 |
__db_errx(env, "%s %s", "DB_ENV->repmgr_add_remote_site:", |
|
675 |
"cannot call from base replication application"); |
|
676 |
return (EINVAL); |
|
677 |
}
|
|
39
by Greg Burd
improvements and bug fixes |
678 |
|
679 |
if ((ret = __db_fchk(env, |
|
31
by Greg Burd
improvements and bug fixes |
680 |
"DB_ENV->repmgr_add_remote_site", flags, DB_REPMGR_PEER)) != 0) |
681 |
return (ret); |
|
682 |
||
683 |
if (host == NULL) { |
|
39
by Greg Burd
improvements and bug fixes |
684 |
__db_errx(env, |
31
by Greg Burd
improvements and bug fixes |
685 |
"repmgr_add_remote_site: host name is required"); |
686 |
return (EINVAL); |
|
687 |
}
|
|
688 |
||
44
by Greg Burd
improvements and bug fixes |
689 |
if (REP_ON(env)) { |
31
by Greg Burd
improvements and bug fixes |
690 |
LOCK_MUTEX(db_rep->mutex); |
691 |
locked = TRUE; |
|
44
by Greg Burd
improvements and bug fixes |
692 |
|
693 |
ret = __repmgr_add_site(env, host, port, &site, flags); |
|
694 |
if (ret == EEXIST) { |
|
695 |
/*
|
|
696 |
* With NEWSITE messages arriving at any time, it would
|
|
697 |
* be impractical for applications to avoid this. Also
|
|
698 |
* this provides a way they can still set peer.
|
|
699 |
*/
|
|
700 |
ret = 0; |
|
701 |
}
|
|
702 |
if (ret != 0) |
|
703 |
goto out; |
|
704 |
eid = EID_FROM_SITE(site); |
|
705 |
if (eidp != NULL) |
|
706 |
*eidp = eid; |
|
707 |
} else { |
|
708 |
if ((site = __repmgr_find_site(env, host, port)) == NULL && |
|
709 |
(ret = __repmgr_new_site(env, |
|
710 |
&site, host, port, SITE_IDLE)) != 0) |
|
711 |
goto out; |
|
712 |
eid = EID_FROM_SITE(site); |
|
713 |
||
714 |
/*
|
|
715 |
* Set provisional EID of peer; may be adjusted at env open/join
|
|
716 |
* time.
|
|
717 |
*/
|
|
718 |
if (LF_ISSET(DB_REPMGR_PEER)) |
|
719 |
db_rep->peer = eid; |
|
39
by Greg Burd
improvements and bug fixes |
720 |
}
|
44
by Greg Burd
improvements and bug fixes |
721 |
|
722 |
out: |
|
723 |
if (locked) |
|
31
by Greg Burd
improvements and bug fixes |
724 |
UNLOCK_MUTEX(db_rep->mutex); |
44
by Greg Burd
improvements and bug fixes |
725 |
/*
|
726 |
* Adding a remote site makes this a replication manager application.
|
|
727 |
*/
|
|
728 |
if (ret == 0) |
|
729 |
APP_SET_REPMGR(env); |
|
31
by Greg Burd
improvements and bug fixes |
730 |
return (ret); |
731 |
}
|