1/*-
2 * See the file LICENSE for redistribution information.
3 *
4 * Copyright (c) 2001,2008 Oracle.  All rights reserved.
5 *
6 * $Id: rep_stat.c,v 12.36 2008/03/26 21:44:29 ubell Exp $
7 */
8
9#include "db_config.h"
10
11#include "db_int.h"
12#include "dbinc/db_page.h"
13#include "dbinc/db_am.h"
14#include "dbinc/log.h"
15
16#ifdef HAVE_STATISTICS
17static int __rep_print_all __P((ENV *, u_int32_t));
18static int __rep_print_stats __P((ENV *, u_int32_t));
19static int __rep_stat __P((ENV *, DB_REP_STAT **, u_int32_t));
20
21/*
22 * __rep_stat_pp --
23 *	ENV->rep_stat pre/post processing.
24 *
25 * PUBLIC: int __rep_stat_pp __P((DB_ENV *, DB_REP_STAT **, u_int32_t));
26 */
27int
28__rep_stat_pp(dbenv, statp, flags)
29	DB_ENV *dbenv;
30	DB_REP_STAT **statp;
31	u_int32_t flags;
32{
33	DB_THREAD_INFO *ip;
34	ENV *env;
35	int ret;
36
37	env = dbenv->env;
38
39	ENV_REQUIRES_CONFIG_XX(
40	    env, rep_handle, "DB_ENV->rep_stat", DB_INIT_REP);
41
42	if ((ret = __db_fchk(env,
43	    "DB_ENV->rep_stat", flags, DB_STAT_CLEAR)) != 0)
44		return (ret);
45
46	ENV_ENTER(env, ip);
47	ret = __rep_stat(env, statp, flags);
48	ENV_LEAVE(env, ip);
49
50	return (ret);
51}
52
53/*
54 * __rep_stat --
55 *	ENV->rep_stat.
56 */
57static int
58__rep_stat(env, statp, flags)
59	ENV *env;
60	DB_REP_STAT **statp;
61	u_int32_t flags;
62{
63	DB_LOG *dblp;
64	DB_REP *db_rep;
65	DB_REP_STAT *stats;
66	LOG *lp;
67	REP *rep;
68	u_int32_t queued, startupdone;
69	int dolock, ret;
70
71	db_rep = env->rep_handle;
72	rep = db_rep->region;
73	dblp = env->lg_handle;
74	lp = dblp->reginfo.primary;
75
76	*statp = NULL;
77
78	/* Allocate a stat struct to return to the user. */
79	if ((ret = __os_umalloc(env, sizeof(DB_REP_STAT), &stats)) != 0)
80		return (ret);
81
82	/*
83	 * Read without holding the lock.  If we are in client recovery, we
84	 * copy just the stats struct so we won't block.  We only copy out
85	 * those stats that don't require acquiring any mutex.
86	 */
87	dolock = FLD_ISSET(rep->flags, REP_F_RECOVER_MASK) ? 0 : 1;
88	memcpy(stats, &rep->stat, sizeof(*stats));
89
90	/* Copy out election stats. */
91	if (F_ISSET(rep, REP_F_EPHASE1))
92		stats->st_election_status = 1;
93	else if (F_ISSET(rep, REP_F_EPHASE2))
94		stats->st_election_status = 2;
95
96	stats->st_election_nsites = rep->sites;
97	stats->st_election_cur_winner = rep->winner;
98	stats->st_election_priority = rep->w_priority;
99	stats->st_election_gen = rep->w_gen;
100	stats->st_election_lsn = rep->w_lsn;
101	stats->st_election_votes = rep->votes;
102	stats->st_election_nvotes = rep->nvotes;
103	stats->st_election_tiebreaker = rep->w_tiebreaker;
104
105	/* Copy out other info that's protected by the rep mutex. */
106	stats->st_env_id = rep->eid;
107	stats->st_env_priority = rep->priority;
108	stats->st_nsites = rep->nsites;
109	stats->st_master = rep->master_id;
110	stats->st_gen = rep->gen;
111	stats->st_egen = rep->egen;
112
113	if (F_ISSET(rep, REP_F_MASTER))
114		stats->st_status = DB_REP_MASTER;
115	else if (F_ISSET(rep, REP_F_CLIENT))
116		stats->st_status = DB_REP_CLIENT;
117	else
118		stats->st_status = 0;
119
120	if (LF_ISSET(DB_STAT_CLEAR)) {
121		queued = rep->stat.st_log_queued;
122		startupdone = rep->stat.st_startup_complete;
123		memset(&rep->stat, 0, sizeof(rep->stat));
124		rep->stat.st_log_queued = rep->stat.st_log_queued_total =
125		    rep->stat.st_log_queued_max = queued;
126		rep->stat.st_startup_complete = startupdone;
127	}
128
129	/*
130	 * Log-related replication info is stored in the log system and
131	 * protected by the log region lock.
132	 */
133	if (dolock)
134		MUTEX_LOCK(env, rep->mtx_clientdb);
135	if (F_ISSET(rep, REP_F_CLIENT)) {
136		stats->st_next_lsn = lp->ready_lsn;
137		stats->st_waiting_lsn = lp->waiting_lsn;
138		stats->st_next_pg = rep->ready_pg;
139		stats->st_waiting_pg = rep->waiting_pg;
140		stats->st_max_lease_sec = (u_int32_t)lp->max_lease_ts.tv_sec;
141		stats->st_max_lease_usec = (u_int32_t)
142		    (lp->max_lease_ts.tv_nsec / NS_PER_US);
143	} else {
144		if (F_ISSET(rep, REP_F_MASTER)) {
145			LOG_SYSTEM_LOCK(env);
146			stats->st_next_lsn = lp->lsn;
147			LOG_SYSTEM_UNLOCK(env);
148		} else
149			ZERO_LSN(stats->st_next_lsn);
150		ZERO_LSN(stats->st_waiting_lsn);
151		stats->st_max_lease_sec = 0;
152		stats->st_max_lease_usec = 0;
153	}
154	stats->st_max_perm_lsn = lp->max_perm_lsn;
155	if (dolock)
156		MUTEX_UNLOCK(env, rep->mtx_clientdb);
157
158	*statp = stats;
159	return (0);
160}
161
162/*
163 * __rep_stat_print_pp --
164 *	ENV->rep_stat_print pre/post processing.
165 *
166 * PUBLIC: int __rep_stat_print_pp __P((DB_ENV *, u_int32_t));
167 */
168int
169__rep_stat_print_pp(dbenv, flags)
170	DB_ENV *dbenv;
171	u_int32_t flags;
172{
173	DB_THREAD_INFO *ip;
174	ENV *env;
175	int ret;
176
177	env = dbenv->env;
178
179	ENV_REQUIRES_CONFIG_XX(
180	    env, rep_handle, "DB_ENV->rep_stat_print", DB_INIT_REP);
181
182	if ((ret = __db_fchk(env, "DB_ENV->rep_stat_print",
183	    flags, DB_STAT_ALL | DB_STAT_CLEAR)) != 0)
184		return (ret);
185
186	ENV_ENTER(env, ip);
187	ret = __rep_stat_print(env, flags);
188	ENV_LEAVE(env, ip);
189
190	return (ret);
191}
192
193/*
194 * __rep_stat_print --
195 *	ENV->rep_stat_print method.
196 *
197 * PUBLIC: int __rep_stat_print __P((ENV *, u_int32_t));
198 */
199int
200__rep_stat_print(env, flags)
201	ENV *env;
202	u_int32_t flags;
203{
204	u_int32_t orig_flags;
205	int ret;
206
207	orig_flags = flags;
208	LF_CLR(DB_STAT_CLEAR | DB_STAT_SUBSYSTEM);
209	if (flags == 0 || LF_ISSET(DB_STAT_ALL)) {
210		ret = __rep_print_stats(env, orig_flags);
211		if (flags == 0 || ret != 0)
212			return (ret);
213	}
214
215	if (LF_ISSET(DB_STAT_ALL) &&
216	    (ret = __rep_print_all(env, orig_flags)) != 0)
217		return (ret);
218
219	return (0);
220}
221
222/*
223 * __rep_print_stats --
224 *	Print out default statistics.
225 */
226static int
227__rep_print_stats(env, flags)
228	ENV *env;
229	u_int32_t flags;
230{
231	DB_REP_STAT *sp;
232	int is_client, ret;
233	char *p;
234
235	if ((ret = __rep_stat(env, &sp, flags)) != 0)
236		return (ret);
237
238	if (LF_ISSET(DB_STAT_ALL))
239		__db_msg(env, "Default replication region information:");
240	is_client = 0;
241	switch (sp->st_status) {
242	case DB_REP_MASTER:
243		__db_msg(env,
244		    "Environment configured as a replication master");
245		break;
246	case DB_REP_CLIENT:
247		__db_msg(env,
248		    "Environment configured as a replication client");
249		is_client = 1;
250		break;
251	default:
252		__db_msg(env,
253		    "Environment not configured for replication");
254		break;
255	}
256
257	__db_msg(env, "%lu/%lu\t%s",
258	    (u_long)sp->st_next_lsn.file, (u_long)sp->st_next_lsn.offset,
259	    is_client ? "Next LSN expected" : "Next LSN to be used");
260	__db_msg(env, "%lu/%lu\t%s",
261	    (u_long)sp->st_waiting_lsn.file, (u_long)sp->st_waiting_lsn.offset,
262	    sp->st_waiting_lsn.file == 0 ?
263	    "Not waiting for any missed log records" :
264	    "LSN of first log record we have after missed log records");
265	__db_msg(env, "%lu/%lu\t%s",
266	    (u_long)sp->st_max_perm_lsn.file,
267	    (u_long)sp->st_max_perm_lsn.offset,
268	    sp->st_max_perm_lsn.file == 0 ?
269	    "No maximum permanent LSN" :
270	    "Maximum permanent LSN");
271
272	__db_dl(env, "Next page number expected", (u_long)sp->st_next_pg);
273	p = sp->st_waiting_pg == PGNO_INVALID ?
274	    "Not waiting for any missed pages" :
275	    "Page number of first page we have after missed pages";
276	__db_msg(env, "%lu\t%s", (u_long)sp->st_waiting_pg, p);
277	__db_dl(env,
278     "Number of duplicate master conditions originally detected at this site",
279	    (u_long)sp->st_dupmasters);
280	if (sp->st_env_id != DB_EID_INVALID)
281		__db_dl(env, "Current environment ID", (u_long)sp->st_env_id);
282	else
283		__db_msg(env, "No current environment ID");
284	__db_dl(env,
285	    "Current environment priority", (u_long)sp->st_env_priority);
286	__db_dl(env, "Current generation number", (u_long)sp->st_gen);
287	__db_dl(env,
288	    "Current election generation number", (u_long)sp->st_egen);
289	__db_dl(env, "Number of duplicate log records received",
290	    (u_long)sp->st_log_duplicated);
291	__db_dl(env, "Number of log records currently queued",
292	    (u_long)sp->st_log_queued);
293	__db_dl(env, "Maximum number of log records ever queued at once",
294	    (u_long)sp->st_log_queued_max);
295	__db_dl(env, "Total number of log records queued",
296	    (u_long)sp->st_log_queued_total);
297	__db_dl(env,
298	    "Number of log records received and appended to the log",
299	    (u_long)sp->st_log_records);
300	__db_dl(env, "Number of log records missed and requested",
301	    (u_long)sp->st_log_requested);
302	if (sp->st_master != DB_EID_INVALID)
303		__db_dl(env, "Current master ID", (u_long)sp->st_master);
304	else
305		__db_msg(env, "No current master ID");
306	__db_dl(env, "Number of times the master has changed",
307	    (u_long)sp->st_master_changes);
308	__db_dl(env,
309	    "Number of messages received with a bad generation number",
310	    (u_long)sp->st_msgs_badgen);
311	__db_dl(env, "Number of messages received and processed",
312	    (u_long)sp->st_msgs_processed);
313	__db_dl(env, "Number of messages ignored due to pending recovery",
314	    (u_long)sp->st_msgs_recover);
315	__db_dl(env, "Number of failed message sends",
316	    (u_long)sp->st_msgs_send_failures);
317	__db_dl(env, "Number of messages sent", (u_long)sp->st_msgs_sent);
318	__db_dl(env,
319	    "Number of new site messages received", (u_long)sp->st_newsites);
320	__db_dl(env,
321	    "Number of environments believed to be in the replication group",
322	    (u_long)sp->st_nsites);
323	__db_dl(env, "Transmission limited", (u_long)sp->st_nthrottles);
324	__db_dl(env, "Number of outdated conditions detected",
325	    (u_long)sp->st_outdated);
326	__db_dl(env, "Number of duplicate page records received",
327	    (u_long)sp->st_pg_duplicated);
328	__db_dl(env, "Number of page records received and added to databases",
329	    (u_long)sp->st_pg_records);
330	__db_dl(env, "Number of page records missed and requested",
331	    (u_long)sp->st_pg_requested);
332	if (sp->st_startup_complete == 0)
333		__db_msg(env, "Startup incomplete");
334	else
335		__db_msg(env, "Startup complete");
336	__db_dl(env,
337	    "Number of transactions applied", (u_long)sp->st_txns_applied);
338
339	__db_dl(env, "Number of startsync messages delayed",
340	    (u_long)sp->st_startsync_delayed);
341
342	__db_dl(env, "Number of elections held", (u_long)sp->st_elections);
343	__db_dl(env,
344	    "Number of elections won", (u_long)sp->st_elections_won);
345
346	if (sp->st_election_status == 0) {
347		__db_msg(env, "No election in progress");
348		if (sp->st_election_sec > 0 || sp->st_election_usec > 0)
349			__db_msg(env,
350			    "%lu.%.6lu\tDuration of last election (seconds)",
351			    (u_long)sp->st_election_sec,
352			    (u_long)sp->st_election_usec);
353	} else {
354		__db_dl(env, "Current election phase",
355		    (u_long)sp->st_election_status);
356		__db_dl(env, "Election winner",
357		    (u_long)sp->st_election_cur_winner);
358		__db_dl(env, "Election generation number",
359		    (u_long)sp->st_election_gen);
360		__db_msg(env, "%lu/%lu\tMaximum LSN of election winner",
361		    (u_long)sp->st_election_lsn.file,
362		    (u_long)sp->st_election_lsn.offset);
363		__db_dl(env,
364		    "Number of sites expected to participate in elections",
365		    (u_long)sp->st_election_nsites);
366		__db_dl(env, "Number of votes needed to win an election",
367		    (u_long)sp->st_election_nvotes);
368		__db_dl(env,
369		    "Election priority", (u_long)sp->st_election_priority);
370		__db_dl(env, "Election tiebreaker value",
371		    (u_long)sp->st_election_tiebreaker);
372		__db_dl(env, "Votes received this election round",
373		    (u_long)sp->st_election_votes);
374	}
375	__db_dl(env, "Number of bulk buffer sends triggered by full buffer",
376	    (u_long)sp->st_bulk_fills);
377	__db_dl(env, "Number of single records exceeding bulk buffer size",
378	    (u_long)sp->st_bulk_overflows);
379	__db_dl(env, "Number of records added to a bulk buffer",
380	    (u_long)sp->st_bulk_records);
381	__db_dl(env, "Number of bulk buffers sent",
382	    (u_long)sp->st_bulk_transfers);
383	__db_dl(env, "Number of re-request messages received",
384	    (u_long)sp->st_client_rerequests);
385	__db_dl(env,
386	    "Number of request messages this client failed to process",
387	    (u_long)sp->st_client_svc_miss);
388	__db_dl(env, "Number of request messages received by this client",
389	    (u_long)sp->st_client_svc_req);
390	if (sp->st_max_lease_sec > 0 || sp->st_max_lease_usec > 0)
391		__db_msg(env,
392		    "%lu.%.6lu\tDuration of maximum lease (seconds)",
393		    (u_long)sp->st_max_lease_sec,
394		    (u_long)sp->st_max_lease_usec);
395
396	__os_ufree(env, sp);
397
398	return (0);
399}
400
401/*
402 * __rep_print_all --
403 *	Display debugging replication region statistics.
404 */
405static int
406__rep_print_all(env, flags)
407	ENV *env;
408	u_int32_t flags;
409{
410	static const FN rep_fn[] = {
411		{ REP_F_CLIENT,		"REP_F_CLIENT" },
412		{ REP_F_EPHASE1,	"REP_F_EPHASE1" },
413		{ REP_F_EPHASE2,	"REP_F_EPHASE2" },
414		{ REP_F_INREPELECT,	"REP_F_INREPELECT" },
415		{ REP_F_MASTER,		"REP_F_MASTER" },
416		{ REP_F_MASTERELECT,	"REP_F_MASTERELECT" },
417		{ REP_F_NOARCHIVE,	"REP_F_NOARCHIVE" },
418		{ REP_F_READY_API,	"REP_F_READY_API" },
419		{ REP_F_READY_MSG,	"REP_F_READY_MSG" },
420		{ REP_F_READY_OP,	"REP_F_READY_OP" },
421		{ REP_F_RECOVER_LOG,	"REP_F_RECOVER_LOG" },
422		{ REP_F_RECOVER_PAGE,	"REP_F_RECOVER_PAGE" },
423		{ REP_F_RECOVER_UPDATE,	"REP_F_RECOVER_UPDATE" },
424		{ REP_F_RECOVER_VERIFY,	"REP_F_RECOVER_VERIFY" },
425		{ REP_F_TALLY,		"REP_F_TALLY" },
426		{ 0,			NULL }
427	};
428	static const FN dbrep_fn[] = {
429		{ DBREP_OPENFILES,	"DBREP_OPENFILES" },
430		{ 0,			NULL }
431	};
432	DB_LOG *dblp;
433	DB_REP *db_rep;
434	DB_THREAD_INFO *ip;
435	LOG *lp;
436	REGENV *renv;
437	REGINFO *infop;
438	REP *rep;
439	char time_buf[CTIME_BUFLEN];
440
441	db_rep = env->rep_handle;
442	rep = db_rep->region;
443	infop = env->reginfo;
444	renv = infop->primary;
445	ENV_ENTER(env, ip);
446
447	__db_msg(env, "%s", DB_GLOBAL(db_line));
448	__db_msg(env, "DB_REP handle information:");
449
450	if (db_rep->rep_db == NULL)
451		STAT_ISSET("Bookkeeping database", db_rep->rep_db);
452	else
453		(void)__db_stat_print(db_rep->rep_db, ip, flags);
454
455	__db_prflags(env, NULL, db_rep->flags, dbrep_fn, NULL, "\tFlags");
456
457	__db_msg(env, "%s", DB_GLOBAL(db_line));
458	__db_msg(env, "REP handle information:");
459	__mutex_print_debug_single(env,
460	    "Replication region mutex", rep->mtx_region, flags);
461	__mutex_print_debug_single(env,
462	    "Bookkeeping database mutex", rep->mtx_clientdb, flags);
463
464	STAT_LONG("Environment ID", rep->eid);
465	STAT_LONG("Master environment ID", rep->master_id);
466	STAT_ULONG("Election generation", rep->egen);
467	STAT_ULONG("Election generation number", rep->gen);
468	STAT_ULONG("Last generation number in log", rep->recover_gen);
469	STAT_LONG("Space allocated for sites", rep->asites);
470	STAT_LONG("Sites in group", rep->nsites);
471	STAT_LONG("Votes needed for election", rep->nvotes);
472	STAT_LONG("Priority in election", rep->priority);
473	__db_dlbytes(env, "Limit on data sent in a single call",
474	    rep->gbytes, (u_long)0, rep->bytes);
475	STAT_LONG("Request gap seconds", rep->request_gap.tv_sec);
476	STAT_LONG("Request gap microseconds",
477	    rep->request_gap.tv_nsec / NS_PER_US);
478	STAT_LONG("Maximum gap seconds", rep->max_gap.tv_sec);
479	STAT_LONG("Maximum gap microseconds",
480	    rep->max_gap.tv_nsec / NS_PER_US);
481
482	STAT_ULONG("Callers in rep_proc_msg", rep->msg_th);
483	STAT_ULONG("Library handle count", rep->handle_cnt);
484	STAT_ULONG("Multi-step operation count", rep->op_cnt);
485	__db_msg(env, "%.24s\tRecovery timestamp",
486	    renv->rep_timestamp == 0 ?
487	    "0" : __os_ctime(&renv->rep_timestamp, time_buf));
488
489	STAT_LONG("Sites heard from", rep->sites);
490	STAT_LONG("Current winner", rep->winner);
491	STAT_LONG("Winner priority", rep->w_priority);
492	STAT_ULONG("Winner generation", rep->w_gen);
493	STAT_LSN("Winner LSN", &rep->w_lsn);
494	STAT_LONG("Winner tiebreaker", rep->w_tiebreaker);
495	STAT_LONG("Votes for this site", rep->votes);
496
497	__db_prflags(env, NULL, rep->flags, rep_fn, NULL, "\tFlags");
498
499	__db_msg(env, "%s", DB_GLOBAL(db_line));
500	__db_msg(env, "LOG replication information:");
501	MUTEX_LOCK(env, rep->mtx_clientdb);
502	dblp = env->lg_handle;
503	lp = (LOG *)dblp->reginfo.primary;
504	STAT_LSN("First log record after a gap", &lp->waiting_lsn);
505	STAT_LSN("Maximum permanent LSN processed", &lp->max_perm_lsn);
506	STAT_LSN("LSN waiting to verify", &lp->verify_lsn);
507	STAT_LSN("Maximum LSN requested", &lp->max_wait_lsn);
508	STAT_LONG("Time to wait before requesting seconds", lp->wait_ts.tv_sec);
509	STAT_LONG("Time to wait before requesting microseconds",
510	    lp->wait_ts.tv_nsec / NS_PER_US);
511	STAT_LSN("Next LSN expected", &lp->ready_lsn);
512	STAT_LONG("Maximum lease timestamp seconds", lp->max_lease_ts.tv_sec);
513	STAT_LONG("Maximum lease timestamp microseconds",
514	    lp->max_lease_ts.tv_nsec / NS_PER_US);
515	MUTEX_UNLOCK(env, rep->mtx_clientdb);
516
517	return (0);
518}
519
520#else /* !HAVE_STATISTICS */
521
522int
523__rep_stat_pp(dbenv, statp, flags)
524	DB_ENV *dbenv;
525	DB_REP_STAT **statp;
526	u_int32_t flags;
527{
528	COMPQUIET(statp, NULL);
529	COMPQUIET(flags, 0);
530
531	return (__db_stat_not_built(dbenv->env));
532}
533
534int
535__rep_stat_print_pp(dbenv, flags)
536	DB_ENV *dbenv;
537	u_int32_t flags;
538{
539	COMPQUIET(flags, 0);
540
541	return (__db_stat_not_built(dbenv->env));
542}
543#endif
544