1 /*-
2 * Copyright (c) 2005, 2020 Oracle and/or its affiliates. All rights reserved.
3 *
4 * See the file LICENSE for license information.
5 *
6 * $Id$
7 */
8
9 #include "db_config.h"
10
11 #include "db_int.h"
12
13 #ifdef HAVE_STATISTICS
14 static int __repmgr_print_all __P((ENV *, u_int32_t));
15 static int __repmgr_print_sites __P((ENV *));
16 static int __repmgr_print_stats __P((ENV *, u_int32_t));
17 static int __repmgr_stat __P((ENV *, DB_REPMGR_STAT **, u_int32_t));
18
19 /*
20 * __repmgr_stat_pp --
21 * DB_ENV->repmgr_stat pre/post processing.
22 *
23 * PUBLIC: int __repmgr_stat_pp __P((DB_ENV *, DB_REPMGR_STAT **, u_int32_t));
24 */
25 int
__repmgr_stat_pp(dbenv,statp,flags)26 __repmgr_stat_pp(dbenv, statp, flags)
27 DB_ENV *dbenv;
28 DB_REPMGR_STAT **statp;
29 u_int32_t flags;
30 {
31 ENV *env;
32 int ret;
33
34 env = dbenv->env;
35
36 ENV_REQUIRES_CONFIG_XX(
37 env, rep_handle, "DB_ENV->repmgr_stat", DB_INIT_REP);
38
39 if ((ret = __db_fchk(env,
40 "DB_ENV->repmgr_stat", flags, DB_STAT_CLEAR)) != 0)
41 return (ret);
42
43 return (__repmgr_stat(env, statp, flags));
44 }
45
46 /*
47 * __repmgr_stat --
48 * ENV->repmgr_stat.
49 */
50 static int
__repmgr_stat(env,statp,flags)51 __repmgr_stat(env, statp, flags)
52 ENV *env;
53 DB_REPMGR_STAT **statp;
54 u_int32_t flags;
55 {
56 DB_REP *db_rep;
57 DB_REPMGR_STAT *copy, *stats;
58 REPMGR_SITE *site;
59 u_int32_t tmp;
60 u_int i;
61 int ret;
62
63 db_rep = env->rep_handle;
64 stats = &db_rep->region->mstat;
65
66 *statp = NULL;
67
68 /* Allocate a stat struct to return to the user. */
69 if ((ret = __os_umalloc(env, sizeof(DB_REPMGR_STAT), ©)) != 0)
70 return (ret);
71
72 memcpy(copy, stats, sizeof(*stats));
73 if (LF_ISSET(DB_STAT_CLEAR)) {
74 tmp = stats->st_max_elect_threads;
75 memset(stats, 0, sizeof(DB_REPMGR_STAT));
76 stats->st_max_elect_threads = tmp;
77 }
78 stats->st_incoming_queue_gbytes = db_rep->input_queue.gbytes;
79 stats->st_incoming_queue_bytes = db_rep->input_queue.bytes;
80 LOCK_MUTEX(db_rep->mutex);
81 for (i = 0; i < db_rep->site_cnt; i++) {
82 site = SITE_FROM_EID(i);
83 if (site->membership != 0) {
84 copy->st_site_total++;
85 if (FLD_ISSET(site->gmdb_flags, SITE_VIEW))
86 copy->st_site_views++;
87 else
88 copy->st_site_participants++;
89 }
90 }
91 UNLOCK_MUTEX(db_rep->mutex);
92
93 *statp = copy;
94 return (0);
95 }
96
97 /*
98 * __repmgr_stat_print_pp --
99 * DB_ENV->repmgr_stat_print pre/post processing.
100 *
101 * PUBLIC: int __repmgr_stat_print_pp __P((DB_ENV *, u_int32_t));
102 */
103 int
__repmgr_stat_print_pp(dbenv,flags)104 __repmgr_stat_print_pp(dbenv, flags)
105 DB_ENV *dbenv;
106 u_int32_t flags;
107 {
108 ENV *env;
109 int ret;
110
111 env = dbenv->env;
112
113 ENV_REQUIRES_CONFIG_XX(
114 env, rep_handle, "DB_ENV->repmgr_stat_print", DB_INIT_REP);
115
116 if ((ret = __db_fchk(env, "DB_ENV->repmgr_stat_print",
117 flags, DB_STAT_ALL | DB_STAT_CLEAR)) != 0)
118 return (ret);
119
120 return (__repmgr_stat_print(env, flags));
121 }
122
123 /*
124 * PUBLIC: int __repmgr_stat_print __P((ENV *, u_int32_t));
125 */
126 int
__repmgr_stat_print(env,flags)127 __repmgr_stat_print(env, flags)
128 ENV *env;
129 u_int32_t flags;
130 {
131 u_int32_t orig_flags;
132 int ret;
133
134 orig_flags = flags;
135 LF_CLR(DB_STAT_CLEAR | DB_STAT_SUBSYSTEM);
136 if (flags == 0 || LF_ISSET(DB_STAT_ALL)) {
137 if ((ret = __repmgr_print_stats(env, orig_flags)) == 0)
138 ret = __repmgr_print_sites(env);
139 if (flags == 0 || ret != 0)
140 return (ret);
141 }
142
143 if (LF_ISSET(DB_STAT_ALL) &&
144 (ret = __repmgr_print_all(env, orig_flags)) != 0)
145 return (ret);
146
147 return (0);
148 }
149
150 static int
__repmgr_print_stats(env,flags)151 __repmgr_print_stats(env, flags)
152 ENV *env;
153 u_int32_t flags;
154 {
155 DB_REPMGR_STAT *sp;
156 int ret;
157 char* poll_method;
158
159 if ((ret = __repmgr_stat(env, &sp, flags)) != 0)
160 return (ret);
161
162 __db_dl(env, "Number of PERM messages not acknowledged",
163 (u_long)sp->st_perm_failed);
164 __db_dl(env, "Number of messages queued due to network delay",
165 (u_long)sp->st_msgs_queued);
166 __db_dl(env, "Number of messages discarded due to queue length",
167 (u_long)sp->st_msgs_dropped);
168 __db_dlbytes(env, "Incoming message size in queue",
169 (u_long)sp->st_incoming_queue_gbytes, (u_long)0,
170 (u_long)sp->st_incoming_queue_bytes);
171 __db_dl(env, "Number of messages discarded due to incoming queue full",
172 (u_long)sp->st_incoming_msgs_dropped);
173 __db_dl(env, "Number of existing connections dropped",
174 (u_long)sp->st_connection_drop);
175 __db_dl(env, "Number of failed new connection attempts",
176 (u_long)sp->st_connect_fail);
177 __db_dl(env, "Number of currently active election threads",
178 (u_long)sp->st_elect_threads);
179 __db_dl(env, "Earliest log file still needed by replication group",
180 (u_long)sp->st_group_stable_log_file);
181 __db_dl(env, "Election threads for which space is reserved",
182 (u_long)sp->st_max_elect_threads);
183 __db_dl(env, "Number of participant sites in replication group",
184 (u_long)sp->st_site_participants);
185 __db_dl(env, "Total number of sites in replication group",
186 (u_long)sp->st_site_total);
187 __db_dl(env, "Number of view sites in replication group",
188 (u_long)sp->st_site_views);
189 __db_dl(env, "Number of automatic replication process takeovers",
190 (u_long)sp->st_takeovers);
191 __db_dl(env, "Number of write operations forwarded by this client",
192 (u_long)sp->st_write_ops_forwarded);
193 __db_dl(env, "Number of write operations received by this master",
194 (u_long)sp->st_write_ops_received);
195
196 switch (sp->st_polling_method) {
197 case SELECT:
198 poll_method = "SELECT";
199 break;
200 case POLL:
201 poll_method = "POLL";
202 break;
203 case EPOLL:
204 poll_method = "EPOLL";
205 break;
206 default:
207 poll_method = "Not yet specified";
208 break;
209 }
210 __db_msg(env, "%lu(%s) \tReplication Manager Polling method",
211 (u_long)sp->st_polling_method, poll_method);
212
213 __os_ufree(env, sp);
214
215 return (0);
216 }
217
218 static int
__repmgr_print_sites(env)219 __repmgr_print_sites(env)
220 ENV *env;
221 {
222 DB_REPMGR_SITE *list;
223 DB_MSGBUF mb;
224 u_int count, i;
225 int ret;
226
227 if ((ret = __repmgr_site_list_int(env, &count, &list)) != 0)
228 return (ret);
229
230 if (count == 0)
231 return (0);
232
233 __db_msg(env, "%s", DB_GLOBAL(db_line));
234 __db_msg(env, "DB_REPMGR site information:");
235
236 DB_MSGBUF_INIT(&mb);
237 for (i = 0; i < count; ++i) {
238 __db_msgadd(env, &mb, "%s (eid: %d, port: %u",
239 list[i].host, list[i].eid, list[i].port);
240 if (list[i].status != 0)
241 __db_msgadd(env, &mb, ", %sconnected",
242 list[i].status == DB_REPMGR_CONNECTED ? "" : "dis");
243 if (IS_REP_MASTER(env))
244 __db_msgadd(env, &mb, ", max_ack_lsn: %lu/%lu",
245 (u_long)list[i].max_ack_lsn.file,
246 (u_long)list[i].max_ack_lsn.offset);
247 __db_msgadd(env, &mb, ", %selectable",
248 F_ISSET(&list[i], DB_REPMGR_ISELECTABLE) ? "" : "non-");
249 __db_msgadd(env, &mb, ", %speer",
250 F_ISSET(&list[i], DB_REPMGR_ISPEER) ? "" : "non-");
251 __db_msgadd(env, &mb, ", %s",
252 F_ISSET(&list[i], DB_REPMGR_ISVIEW) ?
253 "view" : "participant");
254 __db_msgadd(env, &mb, ")");
255 DB_MSGBUF_FLUSH(env, &mb);
256 }
257
258 __os_ufree(env, list);
259
260 return (0);
261 }
262
263 /*
264 * __repmgr_print_all --
265 * Display debugging replication manager statistics.
266 */
267 static int
__repmgr_print_all(env,flags)268 __repmgr_print_all(env, flags)
269 ENV *env;
270 u_int32_t flags;
271 {
272 COMPQUIET(env, NULL);
273 COMPQUIET(flags, 0);
274 return (0);
275 }
276
277 #else /* !HAVE_STATISTICS */
278
279 int
__repmgr_stat_pp(dbenv,statp,flags)280 __repmgr_stat_pp(dbenv, statp, flags)
281 DB_ENV *dbenv;
282 DB_REPMGR_STAT **statp;
283 u_int32_t flags;
284 {
285 COMPQUIET(statp, NULL);
286 COMPQUIET(flags, 0);
287
288 return (__db_stat_not_built(dbenv->env));
289 }
290
291 int
__repmgr_stat_print_pp(dbenv,flags)292 __repmgr_stat_print_pp(dbenv, flags)
293 DB_ENV *dbenv;
294 u_int32_t flags;
295 {
296 COMPQUIET(flags, 0);
297
298 return (__db_stat_not_built(dbenv->env));
299 }
300 #endif
301
302 /*
303 * PUBLIC: int __repmgr_site_list_pp
304 * PUBLIC: __P((DB_ENV *, u_int *, DB_REPMGR_SITE **));
305 */
306 int
__repmgr_site_list_pp(dbenv,countp,listp)307 __repmgr_site_list_pp(dbenv, countp, listp)
308 DB_ENV *dbenv;
309 u_int *countp;
310 DB_REPMGR_SITE **listp;
311 {
312 ENV *env;
313 DB_THREAD_INFO *ip;
314 int ret;
315
316 env = dbenv->env;
317
318 ENV_ENTER(env, ip);
319 ret = __repmgr_site_list_int(env, countp, listp);
320 ENV_LEAVE(env, ip);
321
322 return (ret);
323 }
324
325 /*
326 * PUBLIC: int __repmgr_site_list_int __P((ENV *, u_int *, DB_REPMGR_SITE **));
327 */
328 int
__repmgr_site_list_int(env,countp,listp)329 __repmgr_site_list_int(env, countp, listp)
330 ENV *env;
331 u_int *countp;
332 DB_REPMGR_SITE **listp;
333 {
334 DB_REP *db_rep;
335 DB_REPMGR_SITE *status;
336 REP *rep;
337 REPMGR_SITE *site;
338 size_t array_size, total_size;
339 int eid, locked, ret;
340 u_int count, i;
341 char *name;
342
343 db_rep = env->rep_handle;
344 ret = 0;
345
346 ENV_NOT_CONFIGURED(
347 env, db_rep->region, "DB_ENV->repmgr_site_list", DB_INIT_REP);
348
349 if (REP_ON(env)) {
350 rep = db_rep->region;
351 LOCK_MUTEX(db_rep->mutex);
352 locked = TRUE;
353
354 if (rep->siteinfo_seq > db_rep->siteinfo_seq)
355 ret = __repmgr_sync_siteaddr(env);
356 if (ret != 0)
357 goto err;
358 } else {
359 rep = NULL;
360 locked = FALSE;
361 }
362
363 /* Initialize for empty list or error return. */
364 *countp = 0;
365 *listp = NULL;
366
367 /*
368 * First, add up how much memory we need for the host names, excluding
369 * the local site.
370 */
371 for (i = 0, count = 0, total_size = 0; i < db_rep->site_cnt; i++) {
372 site = &db_rep->sites[i];
373
374 if ((int)i == db_rep->self_eid || site->membership == 0)
375 continue;
376
377 /* Make room for the NUL terminating byte. */
378 total_size += strlen(site->net_addr.host) + 1;
379 count++;
380 }
381 if (count == 0)
382 goto err;
383 array_size = sizeof(DB_REPMGR_SITE) * count;
384 total_size += array_size;
385
386 if ((ret = __os_umalloc(env, total_size, &status)) != 0)
387 goto err;
388
389 /*
390 * Put the storage for the host names after the array of structs. This
391 * way, the caller can free the whole thing in one single operation.
392 */
393 name = (char *)((u_int8_t *)status + array_size);
394 for (eid = 0, i = 0; eid < (int)db_rep->site_cnt; eid++) {
395 site = &db_rep->sites[eid];
396 if (eid == db_rep->self_eid || site->membership == 0)
397 continue;
398
399 /* If we don't have rep, we can't really know EID yet. */
400 status[i].eid = rep ? eid : DB_EID_INVALID;
401
402 status[i].host = name;
403 (void)strcpy(name, site->net_addr.host);
404 name += strlen(name) + 1;
405
406 status[i].port = site->net_addr.port;
407
408 status[i].flags = 0;
409
410 if (FLD_ISSET(site->config, DB_REPMGR_PEER))
411 F_SET(&status[i], DB_REPMGR_ISPEER);
412 if (FLD_ISSET(site->gmdb_flags, SITE_VIEW))
413 F_SET(&status[i], DB_REPMGR_ISVIEW);
414 else if (F_ISSET(site, SITE_ELECTABLE))
415 F_SET(&status[i], DB_REPMGR_ISELECTABLE);
416
417 /*
418 * If we haven't started a communications thread, connection
419 * status is kind of meaningless. This distinction is useful
420 * for calls from the db_stat utility: it could be useful for
421 * db_stat to display known sites with EID; but would be
422 * confusing for it to display "disconnected" if another process
423 * does indeed have a connection established (db_stat can't know
424 * that).
425 */
426 if (db_rep->selector == NULL)
427 status[i].status = 0;
428 else if (site->state != SITE_CONNECTED)
429 status[i].status = DB_REPMGR_DISCONNECTED;
430 else if ((site->ref.conn.in != NULL &&
431 IS_READY_STATE(site->ref.conn.in->state)) ||
432 (site->ref.conn.out != NULL &&
433 IS_READY_STATE(site->ref.conn.out->state)))
434 status[i].status = DB_REPMGR_CONNECTED;
435 else
436 status[i].status = DB_REPMGR_DISCONNECTED;
437 memcpy(&status[i].max_ack_lsn, &site->max_ack, sizeof(DB_LSN));
438
439 i++;
440 }
441
442 *countp = count;
443 *listp = status;
444
445 err: if (locked)
446 UNLOCK_MUTEX(db_rep->mutex);
447 return (ret);
448 }
449