1/*-
2 * See the file LICENSE for redistribution information.
3 *
4 * Copyright (c) 1996-2009 Oracle.  All rights reserved.
5 *
6 * $Id$
7 */
8
9#include "db_config.h"
10
11#include "db_int.h"
12#include "dbinc/db_page.h"
13#include "dbinc/btree.h"
14#include "dbinc/hash.h"
15#include "dbinc/qam.h"
16#include "dbinc/lock.h"
17#include "dbinc/log.h"
18#include "dbinc/mp.h"
19#include "dbinc/partition.h"
20
21#ifdef HAVE_STATISTICS
22static int __db_print_all __P((DB *, u_int32_t));
23static int __db_print_citem __P((DBC *));
24static int __db_print_cursor __P((DB *));
25static int __db_print_stats __P((DB *, DB_THREAD_INFO *, u_int32_t));
26static int __db_stat __P((DB *, DB_THREAD_INFO *, DB_TXN *, void *, u_int32_t));
27static int __db_stat_arg __P((DB *, u_int32_t));
28
29/*
30 * __db_stat_pp --
31 *	DB->stat pre/post processing.
32 *
33 * PUBLIC: int __db_stat_pp __P((DB *, DB_TXN *, void *, u_int32_t));
34 */
35int
36__db_stat_pp(dbp, txn, spp, flags)
37	DB *dbp;
38	DB_TXN *txn;
39	void *spp;
40	u_int32_t flags;
41{
42	DB_THREAD_INFO *ip;
43	ENV *env;
44	int handle_check, ret, t_ret;
45
46	env = dbp->env;
47
48	DB_ILLEGAL_BEFORE_OPEN(dbp, "DB->stat");
49
50	if ((ret = __db_stat_arg(dbp, flags)) != 0)
51		return (ret);
52
53	ENV_ENTER(env, ip);
54
55	/* Check for replication block. */
56	handle_check = IS_ENV_REPLICATED(env);
57	if (handle_check && (ret = __db_rep_enter(dbp, 1, 0,
58	    txn != NULL)) != 0) {
59		handle_check = 0;
60		goto err;
61	}
62
63	ret = __db_stat(dbp, ip, txn, spp, flags);
64
65	/* Release replication block. */
66	if (handle_check && (t_ret = __env_db_rep_exit(env)) != 0 && ret == 0)
67		ret = t_ret;
68
69err:	ENV_LEAVE(env, ip);
70	return (ret);
71}
72
73/*
74 * __db_stat --
75 *	DB->stat.
76 *
77 */
78static int
79__db_stat(dbp, ip, txn, spp, flags)
80	DB *dbp;
81	DB_THREAD_INFO *ip;
82	DB_TXN *txn;
83	void *spp;
84	u_int32_t flags;
85{
86	DBC *dbc;
87	ENV *env;
88	int ret, t_ret;
89
90	env = dbp->env;
91
92	/* Acquire a cursor. */
93	if ((ret = __db_cursor(dbp, ip, txn,
94	     &dbc, LF_ISSET(DB_READ_COMMITTED | DB_READ_UNCOMMITTED))) != 0)
95		return (ret);
96
97	DEBUG_LWRITE(dbc, NULL, "DB->stat", NULL, NULL, flags);
98	LF_CLR(DB_READ_COMMITTED | DB_READ_UNCOMMITTED);
99#ifdef HAVE_PARTITION
100	if (DB_IS_PARTITIONED(dbp))
101		ret = __partition_stat(dbc, spp, flags);
102	else
103#endif
104	switch (dbp->type) {
105	case DB_BTREE:
106	case DB_RECNO:
107		ret = __bam_stat(dbc, spp, flags);
108		break;
109	case DB_HASH:
110		ret = __ham_stat(dbc, spp, flags);
111		break;
112	case DB_QUEUE:
113		ret = __qam_stat(dbc, spp, flags);
114		break;
115	case DB_UNKNOWN:
116	default:
117		ret = (__db_unknown_type(env, "DB->stat", dbp->type));
118		break;
119	}
120
121	if ((t_ret = __dbc_close(dbc)) != 0 && ret == 0)
122		ret = t_ret;
123
124	return (ret);
125}
126
127/*
128 * __db_stat_arg --
129 *	Check DB->stat arguments.
130 */
131static int
132__db_stat_arg(dbp, flags)
133	DB *dbp;
134	u_int32_t flags;
135{
136	ENV *env;
137
138	env = dbp->env;
139
140	/* Check for invalid function flags. */
141	LF_CLR(DB_READ_COMMITTED | DB_READ_UNCOMMITTED);
142	switch (flags) {
143	case 0:
144	case DB_FAST_STAT:
145		break;
146	default:
147		return (__db_ferr(env, "DB->stat", 0));
148	}
149
150	return (0);
151}
152
153/*
154 * __db_stat_print_pp --
155 *	DB->stat_print pre/post processing.
156 *
157 * PUBLIC: int __db_stat_print_pp __P((DB *, u_int32_t));
158 */
159int
160__db_stat_print_pp(dbp, flags)
161	DB *dbp;
162	u_int32_t flags;
163{
164	DB_THREAD_INFO *ip;
165	ENV *env;
166	int handle_check, ret, t_ret;
167
168	env = dbp->env;
169
170	DB_ILLEGAL_BEFORE_OPEN(dbp, "DB->stat_print");
171
172	/*
173	 * !!!
174	 * The actual argument checking is simple, do it inline.
175	 */
176	if ((ret = __db_fchk(env,
177	    "DB->stat_print", flags, DB_FAST_STAT | DB_STAT_ALL)) != 0)
178		return (ret);
179
180	ENV_ENTER(env, ip);
181
182	/* Check for replication block. */
183	handle_check = IS_ENV_REPLICATED(env);
184	if (handle_check && (ret = __db_rep_enter(dbp, 1, 0, 0)) != 0) {
185		handle_check = 0;
186		goto err;
187	}
188
189	ret = __db_stat_print(dbp, ip, flags);
190
191	/* Release replication block. */
192	if (handle_check && (t_ret = __env_db_rep_exit(env)) != 0 && ret == 0)
193		ret = t_ret;
194
195err:	ENV_LEAVE(env, ip);
196	return (ret);
197}
198
199/*
200 * __db_stat_print --
201 *	DB->stat_print.
202 *
203 * PUBLIC: int __db_stat_print __P((DB *, DB_THREAD_INFO *, u_int32_t));
204 */
205int
206__db_stat_print(dbp, ip, flags)
207	DB *dbp;
208	DB_THREAD_INFO *ip;
209	u_int32_t flags;
210{
211	time_t now;
212	int ret;
213	char time_buf[CTIME_BUFLEN];
214
215	(void)time(&now);
216	__db_msg(dbp->env, "%.24s\tLocal time", __os_ctime(&now, time_buf));
217
218	if (LF_ISSET(DB_STAT_ALL) && (ret = __db_print_all(dbp, flags)) != 0)
219		return (ret);
220
221	if ((ret = __db_print_stats(dbp, ip, flags)) != 0)
222		return (ret);
223
224	return (0);
225}
226
227/*
228 * __db_print_stats --
229 *	Display default DB handle statistics.
230 */
231static int
232__db_print_stats(dbp, ip, flags)
233	DB *dbp;
234	DB_THREAD_INFO *ip;
235	u_int32_t flags;
236{
237	DBC *dbc;
238	ENV *env;
239	int ret, t_ret;
240
241	env = dbp->env;
242
243	/* Acquire a cursor. */
244	if ((ret = __db_cursor(dbp, ip, NULL, &dbc, 0)) != 0)
245		return (ret);
246
247	DEBUG_LWRITE(dbc, NULL, "DB->stat_print", NULL, NULL, 0);
248
249	switch (dbp->type) {
250	case DB_BTREE:
251	case DB_RECNO:
252		ret = __bam_stat_print(dbc, flags);
253		break;
254	case DB_HASH:
255		ret = __ham_stat_print(dbc, flags);
256		break;
257	case DB_QUEUE:
258		ret = __qam_stat_print(dbc, flags);
259		break;
260	case DB_UNKNOWN:
261	default:
262		ret = (__db_unknown_type(env, "DB->stat_print", dbp->type));
263		break;
264	}
265
266	if ((t_ret = __dbc_close(dbc)) != 0 && ret == 0)
267		ret = t_ret;
268
269	return (ret);
270}
271
272/*
273 * __db_print_all --
274 *	Display debugging DB handle statistics.
275 */
276static int
277__db_print_all(dbp, flags)
278	DB *dbp;
279	u_int32_t flags;
280{
281	static const FN fn[] = {
282		{ DB_AM_CHKSUM,			"DB_AM_CHKSUM" },
283		{ DB_AM_COMPENSATE,		"DB_AM_COMPENSATE" },
284		{ DB_AM_CREATED,		"DB_AM_CREATED" },
285		{ DB_AM_CREATED_MSTR,		"DB_AM_CREATED_MSTR" },
286		{ DB_AM_DBM_ERROR,		"DB_AM_DBM_ERROR" },
287		{ DB_AM_DELIMITER,		"DB_AM_DELIMITER" },
288		{ DB_AM_DISCARD,		"DB_AM_DISCARD" },
289		{ DB_AM_DUP,			"DB_AM_DUP" },
290		{ DB_AM_DUPSORT,		"DB_AM_DUPSORT" },
291		{ DB_AM_ENCRYPT,		"DB_AM_ENCRYPT" },
292		{ DB_AM_FIXEDLEN,		"DB_AM_FIXEDLEN" },
293		{ DB_AM_INMEM,			"DB_AM_INMEM" },
294		{ DB_AM_IN_RENAME,		"DB_AM_IN_RENAME" },
295		{ DB_AM_NOT_DURABLE,		"DB_AM_NOT_DURABLE" },
296		{ DB_AM_OPEN_CALLED,		"DB_AM_OPEN_CALLED" },
297		{ DB_AM_PAD,			"DB_AM_PAD" },
298		{ DB_AM_PGDEF,			"DB_AM_PGDEF" },
299		{ DB_AM_RDONLY,			"DB_AM_RDONLY" },
300		{ DB_AM_READ_UNCOMMITTED,	"DB_AM_READ_UNCOMMITTED" },
301		{ DB_AM_RECNUM,			"DB_AM_RECNUM" },
302		{ DB_AM_RECOVER,		"DB_AM_RECOVER" },
303		{ DB_AM_RENUMBER,		"DB_AM_RENUMBER" },
304		{ DB_AM_REVSPLITOFF,		"DB_AM_REVSPLITOFF" },
305		{ DB_AM_SECONDARY,		"DB_AM_SECONDARY" },
306		{ DB_AM_SNAPSHOT,		"DB_AM_SNAPSHOT" },
307		{ DB_AM_SUBDB,			"DB_AM_SUBDB" },
308		{ DB_AM_SWAP,			"DB_AM_SWAP" },
309		{ DB_AM_TXN,			"DB_AM_TXN" },
310		{ DB_AM_VERIFYING,		"DB_AM_VERIFYING" },
311		{ 0,				NULL }
312	};
313	ENV *env;
314	char time_buf[CTIME_BUFLEN];
315
316	env = dbp->env;
317
318	__db_msg(env, "%s", DB_GLOBAL(db_line));
319	__db_msg(env, "DB handle information:");
320	STAT_ULONG("Page size", dbp->pgsize);
321	STAT_ISSET("Append recno", dbp->db_append_recno);
322	STAT_ISSET("Feedback", dbp->db_feedback);
323	STAT_ISSET("Dup compare", dbp->dup_compare);
324	STAT_ISSET("App private", dbp->app_private);
325	STAT_ISSET("DbEnv", dbp->env);
326	STAT_STRING("Type", __db_dbtype_to_string(dbp->type));
327
328	__mutex_print_debug_single(env, "Thread mutex", dbp->mutex, flags);
329
330	STAT_STRING("File", dbp->fname);
331	STAT_STRING("Database", dbp->dname);
332	STAT_HEX("Open flags", dbp->open_flags);
333
334	__db_print_fileid(env, dbp->fileid, "\tFile ID");
335
336	STAT_ULONG("Cursor adjust ID", dbp->adj_fileid);
337	STAT_ULONG("Meta pgno", dbp->meta_pgno);
338	if (dbp->locker != NULL)
339		STAT_ULONG("Locker ID", dbp->locker->id);
340	if (dbp->cur_locker != NULL)
341		STAT_ULONG("Handle lock", dbp->cur_locker->id);
342	if (dbp->associate_locker != NULL)
343		STAT_ULONG("Associate lock", dbp->associate_locker->id);
344	STAT_ULONG("RPC remote ID", dbp->cl_id);
345
346	__db_msg(env,
347	    "%.24s\tReplication handle timestamp",
348	    dbp->timestamp == 0 ? "0" : __os_ctime(&dbp->timestamp, time_buf));
349
350	STAT_ISSET("Secondary callback", dbp->s_callback);
351	STAT_ISSET("Primary handle", dbp->s_primary);
352
353	STAT_ISSET("api internal", dbp->api_internal);
354	STAT_ISSET("Btree/Recno internal", dbp->bt_internal);
355	STAT_ISSET("Hash internal", dbp->h_internal);
356	STAT_ISSET("Queue internal", dbp->q_internal);
357
358	__db_prflags(env, NULL, dbp->flags, fn, NULL, "\tFlags");
359
360	if (dbp->log_filename == NULL)
361		STAT_ISSET("File naming information", dbp->log_filename);
362	else
363		__dbreg_print_fname(env, dbp->log_filename);
364
365	(void)__db_print_cursor(dbp);
366
367	return (0);
368}
369
370/*
371 * __db_print_cursor --
372 *	Display the cursor active and free queues.
373 */
374static int
375__db_print_cursor(dbp)
376	DB *dbp;
377{
378	DBC *dbc;
379	ENV *env;
380	int ret, t_ret;
381
382	env = dbp->env;
383
384	__db_msg(env, "%s", DB_GLOBAL(db_line));
385	__db_msg(env, "DB handle cursors:");
386
387	ret = 0;
388	MUTEX_LOCK(dbp->env, dbp->mutex);
389	__db_msg(env, "Active queue:");
390	TAILQ_FOREACH(dbc, &dbp->active_queue, links)
391		if ((t_ret = __db_print_citem(dbc)) != 0 && ret == 0)
392			ret = t_ret;
393	__db_msg(env, "Join queue:");
394	TAILQ_FOREACH(dbc, &dbp->join_queue, links)
395		if ((t_ret = __db_print_citem(dbc)) != 0 && ret == 0)
396			ret = t_ret;
397	__db_msg(env, "Free queue:");
398	TAILQ_FOREACH(dbc, &dbp->free_queue, links)
399		if ((t_ret = __db_print_citem(dbc)) != 0 && ret == 0)
400			ret = t_ret;
401	MUTEX_UNLOCK(dbp->env, dbp->mutex);
402
403	return (ret);
404}
405
406static int
407__db_print_citem(dbc)
408	DBC *dbc;
409{
410	static const FN fn[] = {
411		{ DBC_ACTIVE,		"DBC_ACTIVE" },
412		{ DBC_DONTLOCK,		"DBC_DONTLOCK" },
413		{ DBC_MULTIPLE,		"DBC_MULTIPLE" },
414		{ DBC_MULTIPLE_KEY,	"DBC_MULTIPLE_KEY" },
415		{ DBC_OPD,		"DBC_OPD" },
416		{ DBC_OWN_LID,		"DBC_OWN_LID" },
417		{ DBC_READ_COMMITTED,	"DBC_READ_COMMITTED" },
418		{ DBC_READ_UNCOMMITTED,	"DBC_READ_UNCOMMITTED" },
419		{ DBC_RECOVER,		"DBC_RECOVER" },
420		{ DBC_RMW,		"DBC_RMW" },
421		{ DBC_TRANSIENT,	"DBC_TRANSIENT" },
422		{ DBC_WAS_READ_COMMITTED,"DBC_WAS_READ_COMMITTED" },
423		{ DBC_WRITECURSOR,	"DBC_WRITECURSOR" },
424		{ DBC_WRITER,		"DBC_WRITER" },
425		{ 0,			NULL }
426	};
427	DB *dbp;
428	DBC_INTERNAL *cp;
429	ENV *env;
430
431	dbp = dbc->dbp;
432	env = dbp->env;
433	cp = dbc->internal;
434
435	STAT_POINTER("DBC", dbc);
436	STAT_POINTER("Associated dbp", dbc->dbp);
437	STAT_POINTER("Associated txn", dbc->txn);
438	STAT_POINTER("Internal", cp);
439	STAT_HEX("Default locker ID", dbc->lref == NULL ? 0 : dbc->lref->id);
440	STAT_HEX("Locker", P_TO_ULONG(dbc->locker));
441	STAT_STRING("Type", __db_dbtype_to_string(dbc->dbtype));
442
443	STAT_POINTER("Off-page duplicate cursor", cp->opd);
444	STAT_POINTER("Referenced page", cp->page);
445	STAT_ULONG("Root", cp->root);
446	STAT_ULONG("Page number", cp->pgno);
447	STAT_ULONG("Page index", cp->indx);
448	STAT_STRING("Lock mode", __db_lockmode_to_string(cp->lock_mode));
449	__db_prflags(env, NULL, dbc->flags, fn, NULL, "\tFlags");
450
451	switch (dbc->dbtype) {
452	case DB_BTREE:
453	case DB_RECNO:
454		__bam_print_cursor(dbc);
455		break;
456	case DB_HASH:
457		__ham_print_cursor(dbc);
458		break;
459	case DB_UNKNOWN:
460		DB_ASSERT(env, dbp->type != DB_UNKNOWN);
461		/* FALLTHROUGH */
462	case DB_QUEUE:
463	default:
464		break;
465	}
466	return (0);
467}
468
469#else /* !HAVE_STATISTICS */
470
471int
472__db_stat_pp(dbp, txn, spp, flags)
473	DB *dbp;
474	DB_TXN *txn;
475	void *spp;
476	u_int32_t flags;
477{
478	COMPQUIET(spp, NULL);
479	COMPQUIET(txn, NULL);
480	COMPQUIET(flags, 0);
481
482	return (__db_stat_not_built(dbp->env));
483}
484
485int
486__db_stat_print_pp(dbp, flags)
487	DB *dbp;
488	u_int32_t flags;
489{
490	COMPQUIET(flags, 0);
491
492	return (__db_stat_not_built(dbp->env));
493}
494#endif
495