1/*-
2 * See the file LICENSE for redistribution information.
3 *
4 * Copyright (c) 2005,2008 Oracle.  All rights reserved.
5 *
6 * $Id: repmgr_stat.c,v 1.40 2008/01/08 20:58:48 bostic Exp $
7 */
8
9#include "db_config.h"
10
11#define	__INCLUDE_NETWORKING	1
12#include "db_int.h"
13
14#ifdef HAVE_STATISTICS
15static int __repmgr_print_all __P((ENV *, u_int32_t));
16static int __repmgr_print_sites __P((ENV *));
17static int __repmgr_print_stats __P((ENV *, u_int32_t));
18static int __repmgr_stat __P((ENV *, DB_REPMGR_STAT **, u_int32_t));
19static int __repmgr_stat_print __P((ENV *, u_int32_t));
20
21/*
22 * __repmgr_stat_pp --
23 *	DB_ENV->repmgr_stat pre/post processing.
24 *
25 * PUBLIC: int __repmgr_stat_pp __P((DB_ENV *, DB_REPMGR_STAT **, u_int32_t));
26 */
27int
28__repmgr_stat_pp(dbenv, statp, flags)
29	DB_ENV *dbenv;
30	DB_REPMGR_STAT **statp;
31	u_int32_t flags;
32{
33	ENV *env;
34	int ret;
35
36	env = dbenv->env;
37
38	ENV_REQUIRES_CONFIG_XX(
39	    env, rep_handle, "DB_ENV->repmgr_stat", DB_INIT_REP);
40
41	if ((ret = __db_fchk(env,
42	    "DB_ENV->repmgr_stat", flags, DB_STAT_CLEAR)) != 0)
43		return (ret);
44
45	return (__repmgr_stat(env, statp, flags));
46}
47
48/*
49 * __repmgr_stat --
50 *	ENV->repmgr_stat.
51 */
52static int
53__repmgr_stat(env, statp, flags)
54	ENV *env;
55	DB_REPMGR_STAT **statp;
56	u_int32_t flags;
57{
58	DB_REP *db_rep;
59	DB_REPMGR_STAT *stats;
60	int ret;
61
62	db_rep = env->rep_handle;
63
64	*statp = NULL;
65
66	/* Allocate a stat struct to return to the user. */
67	if ((ret = __os_umalloc(env, sizeof(DB_REPMGR_STAT), &stats)) != 0)
68		return (ret);
69
70	memcpy(stats, &db_rep->region->mstat, sizeof(*stats));
71	if (LF_ISSET(DB_STAT_CLEAR))
72		memset(&db_rep->region->mstat, 0, sizeof(DB_REPMGR_STAT));
73
74	*statp = stats;
75	return (0);
76}
77
78/*
79 * __repmgr_stat_print_pp --
80 *	DB_ENV->repmgr_stat_print pre/post processing.
81 *
82 * PUBLIC: int __repmgr_stat_print_pp __P((DB_ENV *, u_int32_t));
83 */
84int
85__repmgr_stat_print_pp(dbenv, flags)
86	DB_ENV *dbenv;
87	u_int32_t flags;
88{
89	ENV *env;
90	int ret;
91
92	env = dbenv->env;
93
94	ENV_REQUIRES_CONFIG_XX(
95	    env, rep_handle, "DB_ENV->repmgr_stat_print", DB_INIT_REP);
96
97	if ((ret = __db_fchk(env, "DB_ENV->repmgr_stat_print",
98	    flags, DB_STAT_ALL | DB_STAT_CLEAR)) != 0)
99		return (ret);
100
101	return (__repmgr_stat_print(env, flags));
102}
103
104static int
105__repmgr_stat_print(env, flags)
106	ENV *env;
107	u_int32_t flags;
108{
109	u_int32_t orig_flags;
110	int ret;
111
112	orig_flags = flags;
113	LF_CLR(DB_STAT_CLEAR | DB_STAT_SUBSYSTEM);
114	if (flags == 0 || LF_ISSET(DB_STAT_ALL)) {
115		if ((ret = __repmgr_print_stats(env, orig_flags)) == 0)
116			ret = __repmgr_print_sites(env);
117		if (flags == 0 || ret != 0)
118			return (ret);
119	}
120
121	if (LF_ISSET(DB_STAT_ALL) &&
122	    (ret = __repmgr_print_all(env, orig_flags)) != 0)
123		return (ret);
124
125	return (0);
126}
127
128static int
129__repmgr_print_stats(env, flags)
130	ENV *env;
131	u_int32_t flags;
132{
133	DB_REPMGR_STAT *sp;
134	int ret;
135
136	if ((ret = __repmgr_stat(env, &sp, flags)) != 0)
137		return (ret);
138
139	__db_dl(env, "Number of PERM messages not acknowledged",
140	    (u_long)sp->st_perm_failed);
141	__db_dl(env, "Number of messages queued due to network delay",
142	    (u_long)sp->st_msgs_queued);
143	__db_dl(env, "Number of messages discarded due to queue length",
144	    (u_long)sp->st_msgs_dropped);
145	__db_dl(env, "Number of existing connections dropped",
146	    (u_long)sp->st_connection_drop);
147	__db_dl(env, "Number of failed new connection attempts",
148	    (u_long)sp->st_connect_fail);
149
150	__os_ufree(env, sp);
151
152	return (0);
153}
154
155static int
156__repmgr_print_sites(env)
157	ENV *env;
158{
159	DB_REPMGR_SITE *list;
160	u_int count, i;
161	int ret;
162
163	if ((ret = __repmgr_site_list(env->dbenv, &count, &list)) != 0)
164		return (ret);
165
166	if (count == 0)
167		return (0);
168
169	__db_msg(env, "%s", DB_GLOBAL(db_line));
170	__db_msg(env, "DB_REPMGR site information:");
171
172	for (i = 0; i < count; ++i) {
173		__db_msg(env, "%s (eid: %d, port: %u, %sconnected)",
174		    list[i].host, list[i].eid, list[i].port,
175		    list[i].status == DB_REPMGR_CONNECTED ? "" : "dis");
176	}
177
178	__os_ufree(env, list);
179
180	return (0);
181}
182
183/*
184 * __repmgr_print_all --
185 *	Display debugging replication manager statistics.
186 */
187static int
188__repmgr_print_all(env, flags)
189	ENV *env;
190	u_int32_t flags;
191{
192	COMPQUIET(env, NULL);
193	COMPQUIET(flags, 0);
194	return (0);
195}
196
197#else /* !HAVE_STATISTICS */
198
199int
200__repmgr_stat_pp(dbenv, statp, flags)
201	DB_ENV *dbenv;
202	DB_REPMGR_STAT **statp;
203	u_int32_t flags;
204{
205	COMPQUIET(statp, NULL);
206	COMPQUIET(flags, 0);
207
208	return (__db_stat_not_built(dbenv->env));
209}
210
211int
212__repmgr_stat_print_pp(dbenv, flags)
213	DB_ENV *dbenv;
214	u_int32_t flags;
215{
216	COMPQUIET(flags, 0);
217
218	return (__db_stat_not_built(dbenv->env));
219}
220#endif
221
222/*
223 * PUBLIC: int __repmgr_site_list __P((DB_ENV *, u_int *, DB_REPMGR_SITE **));
224 */
225int
226__repmgr_site_list(dbenv, countp, listp)
227	DB_ENV *dbenv;
228	u_int *countp;
229	DB_REPMGR_SITE **listp;
230{
231	DB_REP *db_rep;
232	DB_REPMGR_SITE *status;
233	ENV *env;
234	REPMGR_SITE *site;
235	size_t array_size, total_size;
236	u_int count, i;
237	int locked, ret;
238	char *name;
239
240	env = dbenv->env;
241	db_rep = env->rep_handle;
242	if (REPMGR_SYNC_INITED(db_rep)) {
243		LOCK_MUTEX(db_rep->mutex);
244		locked = TRUE;
245	} else
246		locked = FALSE;
247
248	/* Initialize for empty list or error return. */
249	ret = 0;
250	*countp = 0;
251	*listp = NULL;
252
253	/* First, add up how much memory we need for the host names. */
254	if ((count = db_rep->site_cnt) == 0)
255		goto err;
256
257	array_size = sizeof(DB_REPMGR_SITE) * count;
258	total_size = array_size;
259	for (i = 0; i < count; i++) {
260		site = &db_rep->sites[i];
261
262		/* Make room for the NUL terminating byte. */
263		total_size += strlen(site->net_addr.host) + 1;
264	}
265
266	if ((ret = __os_umalloc(env, total_size, &status)) != 0)
267		goto err;
268
269	/*
270	 * Put the storage for the host names after the array of structs.  This
271	 * way, the caller can free the whole thing in one single operation.
272	 */
273	name = (char *)((u_int8_t *)status + array_size);
274	for (i = 0; i < count; i++) {
275		site = &db_rep->sites[i];
276
277		status[i].eid = EID_FROM_SITE(site);
278
279		status[i].host = name;
280		(void)strcpy(name, site->net_addr.host);
281		name += strlen(name) + 1;
282
283		status[i].port = site->net_addr.port;
284		status[i].status = site->state == SITE_CONNECTED ?
285		    DB_REPMGR_CONNECTED : DB_REPMGR_DISCONNECTED;
286	}
287
288	*countp = count;
289	*listp = status;
290
291err:	if (locked)
292		UNLOCK_MUTEX(db_rep->mutex);
293	return (ret);
294}
295