1/*-
2 * See the file LICENSE for redistribution information.
3 *
4 * Copyright (c) 1996,2008 Oracle.  All rights reserved.
5 *
6 * $Id: env_stat.c,v 12.64 2008/03/12 20:52:53 mbrey 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/lock.h"
15#include "dbinc/log.h"
16#include "dbinc/mp.h"
17#include "dbinc/txn.h"
18
19#ifdef HAVE_STATISTICS
20static int   __env_print_all __P((ENV *, u_int32_t));
21static int   __env_print_dbenv_all __P((ENV *, u_int32_t));
22static int   __env_print_env_all __P((ENV *, u_int32_t));
23static int   __env_print_fh __P((ENV *));
24static int   __env_print_stats __P((ENV *, u_int32_t));
25static int   __env_print_thread __P((ENV *));
26static int   __env_stat_print __P((ENV *, u_int32_t));
27static char *__env_thread_state_print __P((DB_THREAD_STATE));
28static const char *
29	     __reg_type __P((reg_type_t));
30
31/*
32 * __env_stat_print_pp --
33 *	ENV->stat_print pre/post processor.
34 *
35 * PUBLIC: int __env_stat_print_pp __P((DB_ENV *, u_int32_t));
36 */
37int
38__env_stat_print_pp(dbenv, flags)
39	DB_ENV *dbenv;
40	u_int32_t flags;
41{
42	DB_THREAD_INFO *ip;
43	ENV *env;
44	int ret;
45
46	env = dbenv->env;
47
48	ENV_ILLEGAL_BEFORE_OPEN(env, "DB_ENV->stat_print");
49
50	if ((ret = __db_fchk(env, "DB_ENV->stat_print",
51	    flags, DB_STAT_ALL | DB_STAT_CLEAR | DB_STAT_SUBSYSTEM)) != 0)
52		return (ret);
53
54	ENV_ENTER(env, ip);
55	REPLICATION_WRAP(env, (__env_stat_print(env, flags)), 0, ret);
56	ENV_LEAVE(env, ip);
57	return (ret);
58}
59
60/*
61 * __env_stat_print --
62 *	ENV->stat_print method.
63 */
64static int
65__env_stat_print(env, flags)
66	ENV *env;
67	u_int32_t flags;
68{
69	time_t now;
70	int ret;
71	char time_buf[CTIME_BUFLEN];
72
73	(void)time(&now);
74	__db_msg(env, "%.24s\tLocal time", __os_ctime(&now, time_buf));
75
76	if ((ret = __env_print_stats(env, flags)) != 0)
77		return (ret);
78
79	if (LF_ISSET(DB_STAT_ALL) &&
80	    (ret = __env_print_all(env, flags)) != 0)
81		return (ret);
82
83	if ((ret = __env_print_thread(env)) != 0)
84		return (ret);
85
86	if ((ret = __env_print_fh(env)) != 0)
87		return (ret);
88
89	if (!LF_ISSET(DB_STAT_SUBSYSTEM))
90		return (0);
91
92	if (LOGGING_ON(env)) {
93		__db_msg(env, "%s", DB_GLOBAL(db_line));
94		if ((ret = __log_stat_print(env, flags)) != 0)
95			return (ret);
96
97		__db_msg(env, "%s", DB_GLOBAL(db_line));
98		if ((ret = __dbreg_stat_print(env, flags)) != 0)
99			return (ret);
100	}
101
102	if (LOCKING_ON(env)) {
103		__db_msg(env, "%s", DB_GLOBAL(db_line));
104		if ((ret = __lock_stat_print(env, flags)) != 0)
105			return (ret);
106	}
107
108	if (MPOOL_ON(env)) {
109		__db_msg(env, "%s", DB_GLOBAL(db_line));
110		if ((ret = __memp_stat_print(env, flags)) != 0)
111			return (ret);
112	}
113
114	if (REP_ON(env)) {
115		__db_msg(env, "%s", DB_GLOBAL(db_line));
116		if ((ret = __rep_stat_print(env, flags)) != 0)
117			return (ret);
118	}
119
120	if (TXN_ON(env)) {
121		__db_msg(env, "%s", DB_GLOBAL(db_line));
122		if ((ret = __txn_stat_print(env, flags)) != 0)
123			return (ret);
124	}
125
126#ifdef HAVE_MUTEX_SUPPORT
127	/*
128	 * Dump the mutexes last.  If DB_STAT_CLEAR is set this will
129	 * clear out the mutex counters and we want to see them in
130	 * the context of the other subsystems first.
131	 */
132	if (MUTEX_ON(env)) {
133		__db_msg(env, "%s", DB_GLOBAL(db_line));
134		if ((ret = __mutex_stat_print(env, flags)) != 0)
135			return (ret);
136	}
137#endif
138
139	return (0);
140}
141
142/*
143 * __env_print_stats --
144 *	Display the default environment statistics.
145 *
146 */
147static int
148__env_print_stats(env, flags)
149	ENV *env;
150	u_int32_t flags;
151{
152	REGENV *renv;
153	REGINFO *infop;
154	char time_buf[CTIME_BUFLEN];
155
156	infop = env->reginfo;
157	renv = infop->primary;
158
159	if (LF_ISSET(DB_STAT_ALL)) {
160		__db_msg(env, "%s", DB_GLOBAL(db_line));
161		__db_msg(env, "Default database environment information:");
162	}
163	STAT_HEX("Magic number", renv->magic);
164	STAT_LONG("Panic value", renv->panic);
165	__db_msg(env, "%d.%d.%d\tEnvironment version",
166	    renv->majver, renv->minver, renv->patchver);
167	STAT_LONG("Btree version", DB_BTREEVERSION);
168	STAT_LONG("Hash version", DB_HASHVERSION);
169	STAT_LONG("Lock version", DB_LOCKVERSION);
170	STAT_LONG("Log version", DB_LOGVERSION);
171	STAT_LONG("Queue version", DB_QAMVERSION);
172	STAT_LONG("Sequence version", DB_SEQUENCE_VERSION);
173	STAT_LONG("Txn version", DB_TXNVERSION);
174	__db_msg(env,
175	    "%.24s\tCreation time", __os_ctime(&renv->timestamp, time_buf));
176	STAT_HEX("Environment ID", renv->envid);
177	__mutex_print_debug_single(env,
178	    "Primary region allocation and reference count mutex",
179	    renv->mtx_regenv, flags);
180	STAT_LONG("References", renv->refcnt);
181
182	return (0);
183}
184
185/*
186 * __env_print_all --
187 *	Display the debugging environment statistics.
188 */
189static int
190__env_print_all(env, flags)
191	ENV *env;
192	u_int32_t flags;
193{
194	int ret, t_ret;
195
196	/*
197	 * There are two structures -- DB_ENV and ENV.
198	 */
199	ret = __env_print_dbenv_all(env, flags);
200	if ((t_ret = __env_print_env_all(env, flags)) != 0 && ret == 0)
201		ret = t_ret;
202
203	return (ret);
204}
205
206/*
207 * __env_print_dbenv_all --
208 *	Display the debugging environment statistics.
209 */
210static int
211__env_print_dbenv_all(env, flags)
212	ENV *env;
213	u_int32_t flags;
214{
215	static const FN db_env_fn[] = {
216		{ DB_ENV_AUTO_COMMIT,		"DB_ENV_AUTO_COMMIT" },
217		{ DB_ENV_CDB_ALLDB,		"DB_ENV_CDB_ALLDB" },
218		{ DB_ENV_DIRECT_DB,		"DB_ENV_DIRECT_DB" },
219		{ DB_ENV_DSYNC_DB,		"DB_ENV_DSYNC_DB" },
220		{ DB_ENV_MULTIVERSION,		"DB_ENV_MULTIVERSION" },
221		{ DB_ENV_NOLOCKING,		"DB_ENV_NOLOCKING" },
222		{ DB_ENV_NOMMAP,		"DB_ENV_NOMMAP" },
223		{ DB_ENV_NOPANIC,		"DB_ENV_NOPANIC" },
224		{ DB_ENV_OVERWRITE,		"DB_ENV_OVERWRITE" },
225		{ DB_ENV_REGION_INIT,		"DB_ENV_REGION_INIT" },
226		{ DB_ENV_RPCCLIENT,		"DB_ENV_RPCCLIENT" },
227		{ DB_ENV_RPCCLIENT_GIVEN,	"DB_ENV_RPCCLIENT_GIVEN" },
228		{ DB_ENV_TIME_NOTGRANTED,	"DB_ENV_TIME_NOTGRANTED" },
229		{ DB_ENV_TXN_NOSYNC,		"DB_ENV_TXN_NOSYNC" },
230		{ DB_ENV_TXN_NOWAIT,		"DB_ENV_TXN_NOWAIT" },
231		{ DB_ENV_TXN_SNAPSHOT,		"DB_ENV_TXN_SNAPSHOT" },
232		{ DB_ENV_TXN_WRITE_NOSYNC,	"DB_ENV_TXN_WRITE_NOSYNC" },
233		{ DB_ENV_YIELDCPU,		"DB_ENV_YIELDCPU" },
234		{ 0,				NULL }
235	};
236	static const FN vfn[] = {
237		{ DB_VERB_DEADLOCK,		"DB_VERB_DEADLOCK" },
238		{ DB_VERB_FILEOPS,		"DB_VERB_FILEOPS" },
239		{ DB_VERB_FILEOPS_ALL,		"DB_VERB_FILEOPS_ALL" },
240		{ DB_VERB_RECOVERY,		"DB_VERB_RECOVERY" },
241		{ DB_VERB_REGISTER,		"DB_VERB_REGISTER" },
242		{ DB_VERB_REPLICATION,		"DB_VERB_REPLICATION" },
243		{ DB_VERB_REP_ELECT,		"DB_VERB_REP_ELECT" },
244		{ DB_VERB_REP_LEASE,		"DB_VERB_REP_LEASE" },
245		{ DB_VERB_REP_MISC,		"DB_VERB_REP_MISC" },
246		{ DB_VERB_REP_MSGS,		"DB_VERB_REP_MSGS" },
247		{ DB_VERB_REP_SYNC,		"DB_VERB_REP_SYNC" },
248		{ DB_VERB_REPMGR_CONNFAIL,	"DB_VERB_REPMGR_CONNFAIL" },
249		{ DB_VERB_REPMGR_MISC,		"DB_VERB_REPMGR_MISC" },
250		{ DB_VERB_WAITSFOR,		"DB_VERB_WAITSFOR" },
251		{ 0,				NULL }
252	};
253	DB_ENV *dbenv;
254	DB_MSGBUF mb;
255	char **p;
256
257	dbenv = env->dbenv;
258	DB_MSGBUF_INIT(&mb);
259
260	__db_msg(env, "%s", DB_GLOBAL(db_line));
261	STAT_POINTER("ENV", dbenv->env);
262	__mutex_print_debug_single(
263	    env, "DB_ENV handle mutex", dbenv->mtx_db_env, flags);
264	STAT_ISSET("Errcall", dbenv->db_errcall);
265	STAT_ISSET("Errfile", dbenv->db_errfile);
266	STAT_STRING("Errpfx", dbenv->db_errpfx);
267	STAT_ISSET("Msgfile", dbenv->db_msgfile);
268	STAT_ISSET("Msgcall", dbenv->db_msgcall);
269
270	STAT_ISSET("AppDispatch", dbenv->app_dispatch);
271	STAT_ISSET("Event", dbenv->db_event_func);
272	STAT_ISSET("Feedback", dbenv->db_feedback);
273	STAT_ISSET("Free", dbenv->db_free);
274	STAT_ISSET("Panic", dbenv->db_paniccall);
275	STAT_ISSET("Malloc", dbenv->db_malloc);
276	STAT_ISSET("Realloc", dbenv->db_realloc);
277	STAT_ISSET("IsAlive", dbenv->is_alive);
278	STAT_ISSET("ThreadId", dbenv->thread_id);
279	STAT_ISSET("ThreadIdString", dbenv->thread_id_string);
280
281	STAT_STRING("Log dir", dbenv->db_log_dir);
282	STAT_STRING("Tmp dir", dbenv->db_tmp_dir);
283	if (dbenv->db_data_dir == NULL)
284		STAT_ISSET("Data dir", dbenv->db_data_dir);
285	else {
286		for (p = dbenv->db_data_dir; *p != NULL; ++p)
287			__db_msgadd(env, &mb, "%s\tData dir", *p);
288		DB_MSGBUF_FLUSH(env, &mb);
289	}
290
291	STAT_STRING(
292	    "Intermediate directory mode", dbenv->intermediate_dir_mode);
293
294	STAT_LONG("Shared memory key", dbenv->shm_key);
295
296	STAT_ISSET("Password", dbenv->passwd);
297
298	STAT_ISSET("RPC client", dbenv->cl_handle);
299	STAT_ULONG("RPC client ID", dbenv->cl_id);
300
301	STAT_ISSET("App private", dbenv->app_private);
302	STAT_ISSET("Api1 internal", dbenv->api1_internal);
303	STAT_ISSET("Api2 internal", dbenv->api2_internal);
304
305	__db_prflags(env, NULL, dbenv->verbose, vfn, NULL, "\tVerbose flags");
306
307	STAT_ULONG("Mutex align", dbenv->mutex_align);
308	STAT_ULONG("Mutex cnt", dbenv->mutex_cnt);
309	STAT_ULONG("Mutex inc", dbenv->mutex_inc);
310	STAT_ULONG("Mutex tas spins", dbenv->mutex_tas_spins);
311
312	STAT_ISSET("Lock conflicts", dbenv->lk_conflicts);
313	STAT_LONG("Lock modes", dbenv->lk_modes);
314	STAT_ULONG("Lock detect", dbenv->lk_detect);
315	STAT_ULONG("Lock max", dbenv->lk_max);
316	STAT_ULONG("Lock max lockers", dbenv->lk_max_lockers);
317	STAT_ULONG("Lock max objects", dbenv->lk_max_objects);
318	STAT_ULONG("Lock partitions", dbenv->lk_partitions);
319	STAT_ULONG("Lock timeout", dbenv->lk_timeout);
320
321	STAT_ULONG("Log bsize", dbenv->lg_bsize);
322	STAT_FMT("Log file mode", "%#o", int, dbenv->lg_filemode);
323	STAT_ULONG("Log region max", dbenv->lg_regionmax);
324	STAT_ULONG("Log size", dbenv->lg_size);
325
326	STAT_ULONG("Cache GB", dbenv->mp_gbytes);
327	STAT_ULONG("Cache B", dbenv->mp_bytes);
328	STAT_ULONG("Cache max GB", dbenv->mp_max_gbytes);
329	STAT_ULONG("Cache max B", dbenv->mp_max_bytes);
330	STAT_ULONG("Cache mmap size", dbenv->mp_mmapsize);
331	STAT_ULONG("Cache max open fd", dbenv->mp_maxopenfd);
332	STAT_ULONG("Cache max write", dbenv->mp_maxwrite);
333	STAT_ULONG("Cache number", dbenv->mp_ncache);
334	STAT_ULONG("Cache max write sleep", dbenv->mp_maxwrite_sleep);
335
336	STAT_ULONG("Txn max", dbenv->tx_max);
337	STAT_ULONG("Txn timestamp", dbenv->tx_timestamp);
338	STAT_ULONG("Txn timeout", dbenv->tx_timeout);
339
340	STAT_ULONG("Thread count", dbenv->thr_max);
341
342	STAT_ISSET("Registry", dbenv->registry);
343	STAT_ULONG("Registry offset", dbenv->registry_off);
344
345	__db_prflags(env,
346	    NULL, dbenv->flags, db_env_fn, NULL, "\tPublic environment flags");
347
348	return (0);
349}
350
351/*
352 * __env_print_env_all --
353 *	Display the debugging environment statistics.
354 */
355static int
356__env_print_env_all(env, flags)
357	ENV *env;
358	u_int32_t flags;
359{
360	static const FN env_fn[] = {
361		{ ENV_CDB,			"ENV_CDB" },
362		{ ENV_DBLOCAL,			"ENV_DBLOCAL" },
363		{ ENV_LOCKDOWN,			"ENV_LOCKDOWN" },
364		{ ENV_NO_OUTPUT_SET,		"ENV_NO_OUTPUT_SET" },
365		{ ENV_OPEN_CALLED,		"ENV_OPEN_CALLED" },
366		{ ENV_PRIVATE,			"ENV_PRIVATE" },
367		{ ENV_RECOVER_FATAL,		"ENV_RECOVER_FATAL" },
368		{ ENV_REF_COUNTED,		"ENV_REF_COUNTED" },
369		{ ENV_SYSTEM_MEM,		"ENV_SYSTEM_MEM" },
370		{ ENV_THREAD,			"ENV_THREAD" },
371		{ 0,				NULL }
372	};
373	static const FN ofn[] = {
374		{ DB_CREATE,			"DB_CREATE" },
375		{ DB_FORCE,			"DB_FORCE" },
376		{ DB_INIT_CDB,			"DB_INIT_CDB" },
377		{ DB_INIT_LOCK,			"DB_INIT_LOCK" },
378		{ DB_INIT_LOG,			"DB_INIT_LOG" },
379		{ DB_INIT_MPOOL,		"DB_INIT_MPOOL" },
380		{ DB_INIT_REP,			"DB_INIT_REP" },
381		{ DB_INIT_TXN,			"DB_INIT_TXN" },
382		{ DB_LOCKDOWN,			"DB_LOCKDOWN" },
383		{ DB_NOMMAP,			"DB_NOMMAP" },
384		{ DB_PRIVATE,			"DB_PRIVATE" },
385		{ DB_RDONLY,			"DB_RDONLY" },
386		{ DB_RECOVER,			"DB_RECOVER" },
387		{ DB_RECOVER_FATAL,		"DB_RECOVER_FATAL" },
388		{ DB_SYSTEM_MEM,		"DB_SYSTEM_MEM" },
389		{ DB_THREAD,			"DB_THREAD" },
390		{ DB_TRUNCATE,			"DB_TRUNCATE" },
391		{ DB_TXN_NOSYNC,		"DB_TXN_NOSYNC" },
392		{ DB_USE_ENVIRON,		"DB_USE_ENVIRON" },
393		{ DB_USE_ENVIRON_ROOT,		"DB_USE_ENVIRON_ROOT" },
394		{ 0,				NULL }
395	};
396	static const FN regenvfn[] = {
397		{ DB_REGENV_REPLOCKED,		"DB_REGENV_REPLOCKED" },
398		{ 0,				NULL }
399	};
400	REGENV *renv;
401	REGINFO *infop;
402	REGION *rp;
403	u_int32_t i;
404	char time_buf[CTIME_BUFLEN];
405
406	infop = env->reginfo;
407	renv = infop->primary;
408
409	__db_msg(env, "%s", DB_GLOBAL(db_line));
410	STAT_POINTER("DB_ENV", env->dbenv);
411	__mutex_print_debug_single(
412	    env, "ENV handle mutex", env->mtx_env, flags);
413
414	STAT_STRING("Home", env->db_home);
415	__db_prflags(env, NULL, env->open_flags, ofn, NULL, "\tOpen flags");
416	STAT_FMT("Mode", "%#o", int, env->db_mode);
417
418	STAT_ULONG("Pid cache", env->pid_cache);
419
420	STAT_ISSET("Lockfhp", env->lockfhp);
421
422	STAT_ISSET("Locker", env->env_lref);
423
424	STAT_ISSET("Internal recovery table", env->recover_dtab.int_dispatch);
425	STAT_ULONG("Number of recovery table slots",
426	    env->recover_dtab.int_size);
427	STAT_ISSET("External recovery table", env->recover_dtab.ext_dispatch);
428	STAT_ULONG("Number of recovery table slots",
429	    env->recover_dtab.ext_size);
430
431	STAT_ULONG("Thread hash buckets", env->thr_nbucket);
432	STAT_ISSET("Thread hash table", env->thr_hashtab);
433
434	STAT_ULONG("Mutex initial count", env->mutex_iq_next);
435	STAT_ULONG("Mutex initial max", env->mutex_iq_max);
436
437	__mutex_print_debug_single(
438	    env, "ENV list of DB handles mutex", env->mtx_dblist, flags);
439	STAT_LONG("DB reference count", env->db_ref);
440
441	STAT_ULONG("XA RM ID", env->xa_rmid);
442
443	__mutex_print_debug_single(env, "MT mutex", env->mtx_mt, flags);
444
445	STAT_ISSET("Crypto handle", env->crypto_handle);
446	STAT_ISSET("Lock handle", env->lk_handle);
447	STAT_ISSET("Log handle", env->lg_handle);
448	STAT_ISSET("Cache handle", env->mp_handle);
449	STAT_ISSET("Mutex handle", env->mutex_handle);
450	STAT_ISSET("Replication handle", env->rep_handle);
451	STAT_ISSET("Txn handle", env->tx_handle);
452
453	STAT_ISSET("User copy", env->dbt_usercopy);
454
455	STAT_LONG("Test abort", env->test_abort);
456	STAT_LONG("Test check", env->test_check);
457	STAT_LONG("Test copy", env->test_copy);
458
459	__db_prflags(env,
460	    NULL, env->flags, env_fn, NULL, "\tPrivate environment flags");
461
462	__db_print_reginfo(env, infop, "Primary", flags);
463	__db_msg(env, "%s", DB_GLOBAL(db_line));
464	__db_msg(env, "Per region database environment information:");
465	for (rp = R_ADDR(infop, renv->region_off),
466	    i = 0; i < renv->region_cnt; ++i, ++rp) {
467		if (rp->id == INVALID_REGION_ID)
468			continue;
469		__db_msg(env, "%s Region:", __reg_type(rp->type));
470		STAT_LONG("Region ID", rp->id);
471		STAT_LONG("Segment ID", rp->segid);
472		__db_dlbytes(env,
473		    "Size", (u_long)0, (u_long)0, (u_long)rp->size);
474	}
475	__db_prflags(env,
476	    NULL, renv->init_flags, ofn, NULL, "\tInitialization flags");
477	STAT_ULONG("Region slots", renv->region_cnt);
478	__db_prflags(env,
479	    NULL, renv->flags, regenvfn, NULL, "\tReplication flags");
480	__db_msg(env, "%.24s\tOperation timestamp",
481	    renv->op_timestamp == 0 ?
482	    "!Set" : __os_ctime(&renv->op_timestamp, time_buf));
483	__db_msg(env, "%.24s\tReplication timestamp",
484	    renv->rep_timestamp == 0 ?
485	    "!Set" : __os_ctime(&renv->rep_timestamp, time_buf));
486
487	return (0);
488}
489
490static char *
491__env_thread_state_print(state)
492	DB_THREAD_STATE state;
493{
494	switch (state) {
495	case THREAD_ACTIVE:
496		return ("active");
497	case THREAD_BLOCKED:
498		return ("blocked");
499	case THREAD_BLOCKED_DEAD:
500		return ("blocked and dead");
501	case THREAD_OUT:
502		return ("out");
503	default:
504		return ("unknown");
505	}
506	/* NOTREACHED */
507}
508
509/*
510 * __env_print_thread --
511 *	Display the thread block state.
512 */
513static int
514__env_print_thread(env)
515	ENV *env;
516{
517	BH *bhp;
518	DB_ENV *dbenv;
519	DB_HASHTAB *htab;
520	DB_MPOOL *dbmp;
521	DB_THREAD_INFO *ip;
522	PIN_LIST *list, *lp;
523	REGENV *renv;
524	REGINFO *infop;
525	THREAD_INFO *thread;
526	u_int32_t i;
527	char buf[DB_THREADID_STRLEN];
528
529	dbenv = env->dbenv;
530
531	/* The thread table may not be configured. */
532	if ((htab = env->thr_hashtab) == NULL)
533		return (0);
534
535	dbmp = env->mp_handle;
536	__db_msg(env, "%s", DB_GLOBAL(db_line));
537	__db_msg(env, "Thread tracking information");
538
539	/* Dump out the info we have on thread tracking. */
540	infop = env->reginfo;
541	renv = infop->primary;
542	thread = R_ADDR(infop, renv->thread_off);
543	STAT_ULONG("Thread blocks allocated", thread->thr_count);
544	STAT_ULONG("Thread allocation threshold", thread->thr_max);
545	STAT_ULONG("Thread hash buckets", thread->thr_nbucket);
546
547	/* Dump out the info we have on active threads. */
548	__db_msg(env, "Thread status blocks:");
549	for (i = 0; i < env->thr_nbucket; i++)
550		SH_TAILQ_FOREACH(ip, &htab[i], dbth_links, __db_thread_info) {
551			if (ip->dbth_state == THREAD_SLOT_NOT_IN_USE)
552				continue;
553			__db_msg(env, "\tprocess/thread %s: %s",
554			    dbenv->thread_id_string(
555			    dbenv, ip->dbth_pid, ip->dbth_tid, buf),
556			    __env_thread_state_print(ip->dbth_state));
557			list = R_ADDR(env->reginfo, ip->dbth_pinlist);
558			for (lp = list; lp < &list[ip->dbth_pinmax]; lp++) {
559				if (lp->b_ref == INVALID_ROFF)
560					continue;
561				bhp = R_ADDR(
562				    &dbmp->reginfo[lp->region], lp->b_ref);
563				__db_msg(env,
564				     "\t\tpins: %lu", (u_long)bhp->pgno);
565			}
566		}
567	return (0);
568}
569
570/*
571 * __env_print_fh --
572 *	Display statistics for all handles open in this environment.
573 */
574static int
575__env_print_fh(env)
576	ENV *env;
577{
578	DB_FH *fhp;
579
580	if (TAILQ_FIRST(&env->fdlist) == NULL)
581		return (0);
582
583	__db_msg(env, "%s", DB_GLOBAL(db_line));
584	__db_msg(env, "Environment file handle information");
585
586	MUTEX_LOCK(env, env->mtx_env);
587
588	TAILQ_FOREACH(fhp, &env->fdlist, q)
589		__db_print_fh(env, NULL, fhp, 0);
590
591	MUTEX_UNLOCK(env, env->mtx_env);
592
593	return (0);
594}
595
596/*
597 * __db_print_fh --
598 *	Print out a file handle.
599 *
600 * PUBLIC: void __db_print_fh __P((ENV *, const char *, DB_FH *, u_int32_t));
601 */
602void
603__db_print_fh(env, tag, fh, flags)
604	ENV *env;
605	const char *tag;
606	DB_FH *fh;
607	u_int32_t flags;
608{
609	static const FN fn[] = {
610		{ DB_FH_NOSYNC,	"DB_FH_NOSYNC" },
611		{ DB_FH_OPENED,	"DB_FH_OPENED" },
612		{ DB_FH_UNLINK,	"DB_FH_UNLINK" },
613		{ 0,		NULL }
614	};
615
616	if (fh == NULL) {
617		STAT_ISSET(tag, fh);
618		return;
619	}
620
621	STAT_STRING("file-handle.file name", fh->name);
622
623	__mutex_print_debug_single(
624	    env, "file-handle.mutex", fh->mtx_fh, flags);
625
626	STAT_LONG("file-handle.reference count", fh->ref);
627	STAT_LONG("file-handle.file descriptor", fh->fd);
628
629	STAT_ULONG("file-handle.page number", fh->pgno);
630	STAT_ULONG("file-handle.page size", fh->pgsize);
631	STAT_ULONG("file-handle.page offset", fh->offset);
632
633	STAT_ULONG("file-handle.seek count", fh->seek_count);
634	STAT_ULONG("file-handle.read count", fh->read_count);
635	STAT_ULONG("file-handle.write count", fh->write_count);
636
637	__db_prflags(env, NULL, fh->flags, fn, NULL, "\tfile-handle.flags");
638}
639
640/*
641 * __db_print_fileid --
642 *	Print out a file ID.
643 *
644 * PUBLIC: void __db_print_fileid __P((ENV *, u_int8_t *, const char *));
645 */
646void
647__db_print_fileid(env, id, suffix)
648	ENV *env;
649	u_int8_t *id;
650	const char *suffix;
651{
652	DB_MSGBUF mb;
653	int i;
654
655	if (id == NULL) {
656		STAT_ISSET("ID", id);
657		return;
658	}
659
660	DB_MSGBUF_INIT(&mb);
661	for (i = 0; i < DB_FILE_ID_LEN; ++i, ++id) {
662		__db_msgadd(env, &mb, "%x", (u_int)*id);
663		if (i < DB_FILE_ID_LEN - 1)
664			__db_msgadd(env, &mb, " ");
665	}
666	if (suffix != NULL)
667		__db_msgadd(env, &mb, "%s", suffix);
668	DB_MSGBUF_FLUSH(env, &mb);
669}
670
671/*
672 * __db_dl --
673 *	Display a big value.
674 *
675 * PUBLIC: void __db_dl __P((ENV *, const char *, u_long));
676 */
677void
678__db_dl(env, msg, value)
679	ENV *env;
680	const char *msg;
681	u_long value;
682{
683	/*
684	 * Two formats: if less than 10 million, display as the number, if
685	 * greater than 10 million display as ###M.
686	 */
687	if (value < 10000000)
688		__db_msg(env, "%lu\t%s", value, msg);
689	else
690		__db_msg(env, "%luM\t%s (%lu)", value / 1000000, msg, value);
691}
692
693/*
694 * __db_dl_pct --
695 *	Display a big value, and related percentage.
696 *
697 * PUBLIC: void __db_dl_pct
698 * PUBLIC:          __P((ENV *, const char *, u_long, int, const char *));
699 */
700void
701__db_dl_pct(env, msg, value, pct, tag)
702	ENV *env;
703	const char *msg, *tag;
704	u_long value;
705	int pct;
706{
707	DB_MSGBUF mb;
708
709	DB_MSGBUF_INIT(&mb);
710
711	/*
712	 * Two formats: if less than 10 million, display as the number, if
713	 * greater than 10 million, round it off and display as ###M.
714	 */
715	if (value < 10000000)
716		__db_msgadd(env, &mb, "%lu\t%s", value, msg);
717	else
718		__db_msgadd(env,
719		    &mb, "%luM\t%s", (value + 500000) / 1000000, msg);
720	if (tag == NULL)
721		__db_msgadd(env, &mb, " (%d%%)", pct);
722	else
723		__db_msgadd(env, &mb, " (%d%% %s)", pct, tag);
724
725	DB_MSGBUF_FLUSH(env, &mb);
726}
727
728/*
729 * __db_dlbytes --
730 *	Display a big number of bytes.
731 *
732 * PUBLIC: void __db_dlbytes
733 * PUBLIC:     __P((ENV *, const char *, u_long, u_long, u_long));
734 */
735void
736__db_dlbytes(env, msg, gbytes, mbytes, bytes)
737	ENV *env;
738	const char *msg;
739	u_long gbytes, mbytes, bytes;
740{
741	DB_MSGBUF mb;
742	const char *sep;
743
744	DB_MSGBUF_INIT(&mb);
745
746	/* Normalize the values. */
747	while (bytes >= MEGABYTE) {
748		++mbytes;
749		bytes -= MEGABYTE;
750	}
751	while (mbytes >= GIGABYTE / MEGABYTE) {
752		++gbytes;
753		mbytes -= GIGABYTE / MEGABYTE;
754	}
755
756	if (gbytes == 0 && mbytes == 0 && bytes == 0)
757		__db_msgadd(env, &mb, "0");
758	else {
759		sep = "";
760		if (gbytes > 0) {
761			__db_msgadd(env, &mb, "%luGB", gbytes);
762			sep = " ";
763		}
764		if (mbytes > 0) {
765			__db_msgadd(env, &mb, "%s%luMB", sep, mbytes);
766			sep = " ";
767		}
768		if (bytes >= 1024) {
769			__db_msgadd(env, &mb, "%s%luKB", sep, bytes / 1024);
770			bytes %= 1024;
771			sep = " ";
772		}
773		if (bytes > 0)
774			__db_msgadd(env, &mb, "%s%luB", sep, bytes);
775	}
776
777	__db_msgadd(env, &mb, "\t%s", msg);
778
779	DB_MSGBUF_FLUSH(env, &mb);
780}
781
782/*
783 * __db_print_reginfo --
784 *	Print out underlying shared region information.
785 *
786 * PUBLIC: void __db_print_reginfo
787 * PUBLIC:     __P((ENV *, REGINFO *, const char *, u_int32_t));
788 */
789void
790__db_print_reginfo(env, infop, s, flags)
791	ENV *env;
792	REGINFO *infop;
793	const char *s;
794	u_int32_t flags;
795{
796	static const FN fn[] = {
797		{ REGION_CREATE,	"REGION_CREATE" },
798		{ REGION_CREATE_OK,	"REGION_CREATE_OK" },
799		{ REGION_JOIN_OK,	"REGION_JOIN_OK" },
800		{ 0,			NULL }
801	};
802
803	__db_msg(env, "%s", DB_GLOBAL(db_line));
804	__db_msg(env, "%s REGINFO information:",  s);
805	STAT_STRING("Region type", __reg_type(infop->type));
806	STAT_ULONG("Region ID", infop->id);
807	STAT_STRING("Region name", infop->name);
808	STAT_POINTER("Original region address", infop->addr_orig);
809	STAT_POINTER("Region address", infop->addr);
810	STAT_POINTER("Region primary address", infop->primary);
811	STAT_ULONG("Region maximum allocation", infop->max_alloc);
812	STAT_ULONG("Region allocated", infop->allocated);
813	__env_alloc_print(infop, flags);
814
815	__db_prflags(env, NULL, infop->flags, fn, NULL, "\tRegion flags");
816}
817
818/*
819 * __reg_type --
820 *	Return the region type string.
821 */
822static const char *
823__reg_type(t)
824	reg_type_t t;
825{
826	switch (t) {
827	case REGION_TYPE_ENV:
828		return ("Environment");
829	case REGION_TYPE_LOCK:
830		return ("Lock");
831	case REGION_TYPE_LOG:
832		return ("Log");
833	case REGION_TYPE_MPOOL:
834		return ("Mpool");
835	case REGION_TYPE_MUTEX:
836		return ("Mutex");
837	case REGION_TYPE_TXN:
838		return ("Transaction");
839	case INVALID_REGION_TYPE:
840		return ("Invalid");
841	}
842	return ("Unknown");
843}
844
845#else /* !HAVE_STATISTICS */
846
847/*
848 * __db_stat_not_built --
849 *	Common error routine when library not built with statistics.
850 *
851 * PUBLIC: int __db_stat_not_built __P((ENV *));
852 */
853int
854__db_stat_not_built(env)
855	ENV *env;
856{
857	__db_errx(env, "Library build did not include statistics support");
858	return (DB_OPNOTSUP);
859}
860
861int
862__env_stat_print_pp(dbenv, flags)
863	DB_ENV *dbenv;
864	u_int32_t flags;
865{
866	COMPQUIET(flags, 0);
867
868	return (__db_stat_not_built(dbenv->env));
869}
870#endif
871