1 /*-
2 * Copyright (c) 1996, 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 #include "dbinc/db_page.h"
13 #include "dbinc/db_am.h"
14
15 #ifdef HAVE_STATISTICS
16 static int __mutex_print_all __P((ENV *, u_int32_t));
17 static const char *__mutex_print_id __P((int));
18 static int __mutex_print_stats __P((ENV *, u_int32_t));
19 static void __mutex_print_summary __P((ENV *));
20 static int __mutex_stat __P((ENV *, DB_MUTEX_STAT **, u_int32_t));
21
22 static const FN MutexFlagNames[] = {
23 { DB_MUTEX_ALLOCATED, "alloc" },
24 { DB_MUTEX_LOCKED, "locked" },
25 { DB_MUTEX_LOGICAL_LOCK, "logical" },
26 { DB_MUTEX_OWNER_DEAD, "ower-dead" },
27 { DB_MUTEX_PROCESS_ONLY, "process-private" },
28 { DB_MUTEX_SELF_BLOCK, "self-block" },
29 { DB_MUTEX_SHARED, "shared" },
30 { 0, NULL }
31 };
32
33 /*
34 * __mutex_stat_pp --
35 * ENV->mutex_stat pre/post processing.
36 *
37 * PUBLIC: int __mutex_stat_pp __P((DB_ENV *, DB_MUTEX_STAT **, u_int32_t));
38 */
39 int
__mutex_stat_pp(dbenv,statp,flags)40 __mutex_stat_pp(dbenv, statp, flags)
41 DB_ENV *dbenv;
42 DB_MUTEX_STAT **statp;
43 u_int32_t flags;
44 {
45 DB_THREAD_INFO *ip;
46 ENV *env;
47 int ret;
48
49 env = dbenv->env;
50
51 ENV_REQUIRES_CONFIG(env,
52 env->mutex_handle, "DB_ENV->mutex_stat", DB_INIT_MUTEX);
53
54 if ((ret = __db_fchk(env,
55 "DB_ENV->mutex_stat", flags, DB_STAT_CLEAR)) != 0)
56 return (ret);
57
58 ENV_ENTER(env, ip);
59 REPLICATION_WRAP(env, (__mutex_stat(env, statp, flags)), 0, ret);
60 ENV_LEAVE(env, ip);
61 return (ret);
62 }
63
64 /*
65 * __mutex_stat --
66 * ENV->mutex_stat.
67 */
68 static int
__mutex_stat(env,statp,flags)69 __mutex_stat(env, statp, flags)
70 ENV *env;
71 DB_MUTEX_STAT **statp;
72 u_int32_t flags;
73 {
74 DB_MUTEXMGR *mtxmgr;
75 DB_MUTEXREGION *mtxregion;
76 DB_MUTEX_STAT *stats;
77 int ret;
78
79 *statp = NULL;
80 mtxmgr = env->mutex_handle;
81 mtxregion = mtxmgr->reginfo.primary;
82
83 if ((ret = __os_umalloc(env, sizeof(DB_MUTEX_STAT), &stats)) != 0)
84 return (ret);
85
86 MUTEX_SYSTEM_LOCK(env);
87
88 /*
89 * Most fields are maintained in the underlying region structure.
90 * Region size and region mutex are not.
91 */
92 *stats = mtxregion->stat;
93 stats->st_regsize = mtxmgr->reginfo.rp->size;
94 stats->st_regmax = mtxmgr->reginfo.rp->max;
95 __mutex_set_wait_info(env, mtxregion->mtx_region,
96 &stats->st_region_wait, &stats->st_region_nowait);
97 if (LF_ISSET(DB_STAT_CLEAR))
98 __mutex_clear(env, mtxregion->mtx_region);
99
100 MUTEX_SYSTEM_UNLOCK(env);
101
102 *statp = stats;
103 return (0);
104 }
105
106 /*
107 * __mutex_stat_print_pp --
108 * ENV->mutex_stat_print pre/post processing.
109 *
110 * PUBLIC: int __mutex_stat_print_pp __P((DB_ENV *, u_int32_t));
111 */
112 int
__mutex_stat_print_pp(dbenv,flags)113 __mutex_stat_print_pp(dbenv, flags)
114 DB_ENV *dbenv;
115 u_int32_t flags;
116 {
117 DB_THREAD_INFO *ip;
118 ENV *env;
119 int ret;
120
121 env = dbenv->env;
122
123 ENV_REQUIRES_CONFIG(env,
124 env->mutex_handle, "DB_ENV->mutex_stat_print", DB_INIT_MUTEX);
125
126 if ((ret = __db_fchk(env, "DB_ENV->mutex_stat_print",
127 flags, DB_STAT_ALL | DB_STAT_ALLOC | DB_STAT_CLEAR)) != 0)
128 return (ret);
129
130 ENV_ENTER(env, ip);
131 REPLICATION_WRAP(env, (__mutex_stat_print(env, flags)), 0, ret);
132 ENV_LEAVE(env, ip);
133 return (ret);
134 }
135
136 /*
137 * __mutex_stat_print
138 * ENV->mutex_stat_print method.
139 *
140 * PUBLIC: int __mutex_stat_print __P((ENV *, u_int32_t));
141 */
142 int
__mutex_stat_print(env,flags)143 __mutex_stat_print(env, flags)
144 ENV *env;
145 u_int32_t flags;
146 {
147 u_int32_t orig_flags;
148 int ret;
149
150 orig_flags = flags;
151 LF_CLR(DB_STAT_CLEAR | DB_STAT_SUBSYSTEM);
152 if (flags == 0 || LF_ISSET(DB_STAT_ALL)) {
153 ret = __mutex_print_stats(env, orig_flags);
154 __mutex_print_summary(env);
155 if (flags == 0 || ret != 0)
156 return (ret);
157 }
158
159 if (LF_ISSET(DB_STAT_ALL))
160 ret = __mutex_print_all(env, orig_flags);
161
162 return (0);
163 }
164
165 static void
__mutex_print_summary(env)166 __mutex_print_summary(env)
167 ENV *env;
168 {
169 DB_MUTEX *mutexp;
170 DB_MUTEXMGR *mtxmgr;
171 DB_MUTEXREGION *mtxregion;
172 void *chunk;
173 db_mutex_t i;
174 u_int32_t counts[MTX_MAX_ENTRY + 2];
175 uintmax_t size;
176 int alloc_id;
177
178 mtxmgr = env->mutex_handle;
179 mtxregion = mtxmgr->reginfo.primary;
180 memset(counts, 0, sizeof(counts));
181 size = 0;
182
183 if (F_ISSET(env, ENV_PRIVATE)) {
184 mutexp = (DB_MUTEX *)((uintptr_t)mtxmgr->mutex_array +
185 mtxregion->mutex_size);
186 chunk = NULL;
187 size = __env_elem_size(env,
188 ROFF_TO_P(mtxregion->mutex_off_alloc));
189 size -= mtxregion->mutex_size;
190 } else
191 mutexp = MUTEXP_SET(env, 1);
192 for (i = 1; i <= mtxregion->stat.st_mutex_cnt; ++i) {
193 if (!F_ISSET(mutexp, DB_MUTEX_ALLOCATED))
194 counts[0]++;
195 else if (mutexp->alloc_id > MTX_MAX_ENTRY)
196 counts[MTX_MAX_ENTRY + 1]++;
197 else
198 counts[mutexp->alloc_id]++;
199
200 mutexp = (DB_MUTEX *)((uintptr_t)mutexp +
201 mtxregion->mutex_size);
202 if (F_ISSET(env, ENV_PRIVATE) &&
203 (size -= sizeof(*mutexp)) < sizeof(*mutexp)) {
204 mutexp =
205 __env_get_chunk(&mtxmgr->reginfo, &chunk, &size);
206 mutexp = ALIGNP_INC(mutexp,
207 mtxregion->stat.st_mutex_align);
208 }
209 }
210 __db_msg(env, "Mutex counts");
211 __db_msg(env, "%d\tUnallocated", counts[0]);
212 for (alloc_id = 1; alloc_id <= MTX_TXN_REGION + 1; alloc_id++)
213 if (counts[alloc_id] != 0)
214 __db_msg(env, "%lu\t%s",
215 (u_long)counts[alloc_id],
216 __mutex_print_id(alloc_id));
217
218 }
219
220 /*
221 * __mutex_print_stats --
222 * Display default mutex region statistics.
223 */
224 static int
__mutex_print_stats(env,flags)225 __mutex_print_stats(env, flags)
226 ENV *env;
227 u_int32_t flags;
228 {
229 DB_MUTEX_STAT *sp;
230 int ret;
231
232 if ((ret = __mutex_stat(env, &sp, LF_ISSET(DB_STAT_CLEAR))) != 0)
233 return (ret);
234
235 if (LF_ISSET(DB_STAT_ALL))
236 __db_msg(env, "Default mutex region information:");
237
238 __db_dlbytes(env, "Mutex region size",
239 (u_long)0, (u_long)0, (u_long)sp->st_regsize);
240 __db_dlbytes(env, "Mutex region max size",
241 (u_long)0, (u_long)0, (u_long)sp->st_regmax);
242 __db_dl_pct(env,
243 "The number of region locks that required waiting",
244 (u_long)sp->st_region_wait, DB_PCT(sp->st_region_wait,
245 sp->st_region_wait + sp->st_region_nowait), NULL);
246 STAT_ULONG("Mutex alignment", sp->st_mutex_align);
247 STAT_ULONG("Mutex test-and-set spins", sp->st_mutex_tas_spins);
248 STAT_ULONG("Mutex initial count", sp->st_mutex_init);
249 STAT_ULONG("Mutex total count", sp->st_mutex_cnt);
250 STAT_ULONG("Mutex max count", sp->st_mutex_max);
251 STAT_ULONG("Mutex free count", sp->st_mutex_free);
252 STAT_ULONG("Mutex in-use count", sp->st_mutex_inuse);
253 STAT_ULONG("Mutex maximum in-use count", sp->st_mutex_inuse_max);
254
255 __os_ufree(env, sp);
256
257 return (0);
258 }
259
260 /*
261 * __mutex_print_all --
262 * Display debugging mutex region statistics.
263 */
264 static int
__mutex_print_all(env,flags)265 __mutex_print_all(env, flags)
266 ENV *env;
267 u_int32_t flags;
268 {
269 DB_MSGBUF mb, *mbp;
270 DB_MUTEX *mutexp;
271 DB_MUTEXMGR *mtxmgr;
272 DB_MUTEXREGION *mtxregion;
273 db_mutex_t i;
274 uintmax_t size;
275 void *chunk;
276
277 DB_MSGBUF_INIT(&mb);
278 mbp = &mb;
279
280 mtxmgr = env->mutex_handle;
281 mtxregion = mtxmgr->reginfo.primary;
282
283 __db_print_reginfo(env, &mtxmgr->reginfo, "Mutex", flags);
284 __db_msg(env, "%s", DB_GLOBAL(db_line));
285
286 __db_msg(env, "DB_MUTEXREGION structure:");
287 __mutex_print_debug_single(env,
288 "DB_MUTEXREGION region mutex", mtxregion->mtx_region, flags);
289 STAT_ULONG("Size of the aligned mutex", mtxregion->mutex_size);
290 STAT_ULONG("Next free mutex", mtxregion->mutex_next);
291
292 /*
293 * The OOB mutex (MUTEX_INVALID) is 0, skip it.
294 *
295 * We're not holding the mutex region lock, so we're racing threads of
296 * control allocating mutexes. That's OK, it just means we display or
297 * clear statistics while mutexes are moving.
298 */
299 __db_msg(env, "%s", DB_GLOBAL(db_line));
300 __db_msg(env, "mutex\twait/nowait, pct wait, holder, flags");
301 size = 0;
302 if (F_ISSET(env, ENV_PRIVATE)) {
303 mutexp = (DB_MUTEX *)((uintptr_t)mtxmgr->mutex_array +
304 mtxregion->mutex_size);
305 chunk = NULL;
306 size = __env_elem_size(env,
307 ROFF_TO_P(mtxregion->mutex_off_alloc));
308 size -= mtxregion->mutex_size;
309 } else
310 mutexp = MUTEXP_SET(env, 1);
311 for (i = 1; i <= mtxregion->stat.st_mutex_cnt; ++i) {
312 if (F_ISSET(mutexp, DB_MUTEX_ALLOCATED)) {
313 __db_msgadd(env, mbp, "%5lu\t", (u_long)i);
314 __mutex_print_debug_stats(env, mbp,
315 F_ISSET(env, ENV_PRIVATE) ?
316 (db_mutex_t)mutexp : i, flags);
317 DB_MSGBUF_FLUSH(env, mbp);
318 }
319
320 mutexp = (DB_MUTEX *)((uintptr_t)mutexp +
321 mtxregion->mutex_size);
322 if (F_ISSET(env, ENV_PRIVATE) &&
323 (size -= mtxregion->mutex_size) < mtxregion->mutex_size) {
324 mutexp =
325 __env_get_chunk(&mtxmgr->reginfo, &chunk, &size);
326 mutexp = ALIGNP_INC(mutexp,
327 mtxregion->stat.st_mutex_align);
328 }
329 }
330
331 return (0);
332 }
333
334 /*
335 * __mutex_print_debug_single --
336 * Print mutex internal debugging statistics for a single mutex.
337 *
338 * PUBLIC: void __mutex_print_debug_single
339 * PUBLIC: __P((ENV *, const char *, db_mutex_t, u_int32_t));
340 */
341 void
__mutex_print_debug_single(env,tag,mutex,flags)342 __mutex_print_debug_single(env, tag, mutex, flags)
343 ENV *env;
344 const char *tag;
345 db_mutex_t mutex;
346 u_int32_t flags;
347 {
348 DB_MSGBUF mb, *mbp;
349
350 DB_MSGBUF_INIT(&mb);
351 mbp = &mb;
352
353 if (LF_ISSET(DB_STAT_SUBSYSTEM))
354 LF_CLR(DB_STAT_CLEAR);
355 __db_msgadd(env, mbp, "%lu\t%s ", (u_long)mutex, tag);
356 __mutex_print_debug_stats(env, mbp, mutex, flags);
357 DB_MSGBUF_FLUSH(env, mbp);
358 }
359
360 /*
361 * __mutex_print_debug_stats --
362 * Print the mutex internal debugging statistics in square bracket,s on a
363 * followed by the allocation id and flags, on single line. When MUTEX_DIAG
364 * is on and the mutex is held, append the owner's stack trace.
365 *
366 * PUBLIC: void __mutex_print_debug_stats
367 * PUBLIC: __P((ENV *, DB_MSGBUF *, db_mutex_t, u_int32_t));
368 */
369 void
__mutex_print_debug_stats(env,mbp,mutex,flags)370 __mutex_print_debug_stats(env, mbp, mutex, flags)
371 ENV *env;
372 DB_MSGBUF *mbp;
373 db_mutex_t mutex;
374 u_int32_t flags;
375 {
376 DB_ENV *dbenv;
377 DB_MUTEX *mutexp;
378 u_long value;
379 char buf[DB_THREADID_STRLEN];
380 #if defined(HAVE_SHARED_LATCHES) && (defined(HAVE_MUTEX_HYBRID) || \
381 !defined(HAVE_MUTEX_PTHREADS))
382 int sharecount;
383 #endif
384 #ifdef MUTEX_DIAG
385 char timestr[CTIME_BUFLEN];
386 #endif
387
388 if (mutex == MUTEX_INVALID) {
389 __db_msgadd(env, mbp, "[!Set]");
390 return;
391 }
392
393 dbenv = env->dbenv;
394 mutexp = MUTEXP_SET(env, mutex);
395
396 __db_msgadd(env, mbp, "[");
397 if ((value = mutexp->mutex_set_wait) < 10000000)
398 __db_msgadd(env, mbp, "%lu", value);
399 else
400 __db_msgadd(env, mbp, "%luM", value / 1000000);
401 if ((value = mutexp->mutex_set_nowait) < 10000000)
402 __db_msgadd(env, mbp, "/%lu", value);
403 else
404 __db_msgadd(env, mbp, "/%luM", value / 1000000);
405
406 __db_msgadd(env, mbp, " %d%% ",
407 DB_PCT(mutexp->mutex_set_wait,
408 mutexp->mutex_set_wait + mutexp->mutex_set_nowait));
409
410 #if defined(HAVE_SHARED_LATCHES)
411 if (F_ISSET(mutexp, DB_MUTEX_SHARED)) {
412 __db_msgadd(env, mbp, " rd ");
413 if ((value = mutexp->mutex_set_rd_wait) < 10000000)
414 __db_msgadd(env, mbp, "%lu", value);
415 else
416 __db_msgadd(env, mbp, "%luM", value / 1000000);
417 if ((value = mutexp->mutex_set_rd_nowait) < 10000000)
418 __db_msgadd(env, mbp, "/%lu", value);
419 else
420 __db_msgadd(env, mbp, "/%luM", value / 1000000);
421 __db_msgadd(env, mbp, " %d%% ",
422 DB_PCT(mutexp->mutex_set_rd_wait,
423 mutexp->mutex_set_rd_wait + mutexp->mutex_set_rd_nowait));
424 }
425 #endif
426
427 if (F_ISSET(mutexp, DB_MUTEX_LOCKED))
428 __db_msgadd(env, mbp, "%s]",
429 dbenv->thread_id_string(dbenv,
430 mutexp->pid, mutexp->tid, buf));
431 /* Pthreads-based shared latches do not expose the share count. */
432 #if defined(HAVE_SHARED_LATCHES) && (defined(HAVE_MUTEX_HYBRID) || \
433 !defined(HAVE_MUTEX_PTHREADS))
434 else if (F_ISSET(mutexp, DB_MUTEX_SHARED) &&
435 (sharecount = atomic_read(&mutexp->sharecount)) != 0) {
436 if (sharecount == 1)
437 __db_msgadd(env, mbp, "1 reader");
438 else
439 __db_msgadd(env, mbp, "%d readers", sharecount);
440 /* Show the thread which last acquired the latch. */
441 __db_msgadd(env, mbp, " %s]",
442 dbenv->thread_id_string(dbenv,
443 mutexp->pid, mutexp->tid, buf));
444 }
445 #endif
446 else
447 __db_msgadd(env, mbp, "!Own]");
448
449 #ifdef HAVE_MUTEX_HYBRID
450 if (mutexp->hybrid_wait != 0 || mutexp->hybrid_wakeup != 0)
451 __db_msgadd(env, mbp, " <wakeups %d/%d>",
452 mutexp->hybrid_wait, mutexp->hybrid_wakeup);
453 #endif
454
455 if (mutexp->alloc_id != 0)
456 __db_msgadd(env,
457 mbp, ", %s", __mutex_print_id(mutexp->alloc_id));
458
459 __db_prflags(env, mbp, mutexp->flags, MutexFlagNames, " (", ")");
460 #ifdef MUTEX_DIAG
461 if (mutexp->alloc_id != MTX_LOGICAL_LOCK &&
462 timespecisset(&mutexp->mutex_history.when)) {
463 __db_ctimespec(&mutexp->mutex_history.when, timestr);
464 __db_msgadd(env, mbp, "\nLocked %s", timestr);
465 if (mutexp->mutex_history.stacktext[0] != '\0')
466 __db_msgadd(env, mbp, "\n%.*s",
467 (int)sizeof(mutexp->mutex_history.stacktext) - 1,
468 mutexp->mutex_history.stacktext);
469 }
470 #endif
471 if (LF_ISSET(DB_STAT_CLEAR))
472 __mutex_clear(env, mutex);
473 }
474
475 static const char *
__mutex_print_id(alloc_id)476 __mutex_print_id(alloc_id)
477 int alloc_id;
478 {
479 switch (alloc_id) {
480 case MTX_APPLICATION: return ("application allocated");
481 case MTX_ATOMIC_EMULATION: return ("atomic emulation");
482 case MTX_DB_HANDLE: return ("db handle");
483 case MTX_ENV_DBLIST: return ("env dblist");
484 case MTX_ENV_EXCLDBLIST: return ("env exclusive dblist");
485 case MTX_ENV_HANDLE: return ("env handle");
486 case MTX_ENV_REGION: return ("env region");
487 case MTX_LOCK_REGION: return ("lock region");
488 case MTX_LOGICAL_LOCK: return ("logical lock");
489 case MTX_LOG_FILENAME: return ("log filename");
490 case MTX_LOG_FLUSH: return ("log flush");
491 case MTX_LOG_HANDLE: return ("log handle");
492 case MTX_LOG_REGION: return ("log region");
493 case MTX_LSN_HISTORY: return ("lsn history");
494 case MTX_MPOOLFILE_HANDLE: return ("mpoolfile handle");
495 case MTX_MPOOL_BH: return ("mpool buffer");
496 case MTX_MPOOL_FH: return ("mpool filehandle");
497 case MTX_MPOOL_FILE_BUCKET: return ("mpool file bucket");
498 case MTX_MPOOL_HANDLE: return ("mpool handle");
499 case MTX_MPOOL_HASH_BUCKET: return ("mpool hash bucket");
500 case MTX_MPOOL_REGION: return ("mpool region");
501 case MTX_MUTEX_REGION: return ("mutex region");
502 case MTX_MUTEX_TEST: return ("mutex test");
503 case MTX_REPMGR: return ("replication manager");
504 case MTX_REP_CHKPT: return ("replication checkpoint");
505 case MTX_REP_DATABASE: return ("replication database");
506 case MTX_REP_DIAG: return ("replication diagnostics");
507 case MTX_REP_EVENT: return ("replication event");
508 case MTX_REP_REGION: return ("replication region");
509 case MTX_REP_START: return ("replication role config");
510 case MTX_REP_WAITER: return ("replication txn apply");
511 case MTX_SEQUENCE: return ("sequence");
512 case MTX_TWISTER: return ("twister");
513 case MTX_TCL_EVENTS: return ("Tcl events");
514 case MTX_TXN_ACTIVE: return ("txn active list");
515 case MTX_TXN_CHKPT: return ("transaction checkpoint");
516 case MTX_TXN_COMMIT: return ("txn commit");
517 case MTX_TXN_MVCC: return ("txn mvcc");
518 case MTX_TXN_REGION: return ("txn region");
519 case 0: return ("invalid 0 mutex type");
520 default: return ("unknown non-zero mutex type");
521 /* NOTREACHED */
522 }
523 }
524
525 /*
526 * __mutex_set_wait_info --
527 * Return mutex statistics.
528 *
529 * PUBLIC: void __mutex_set_wait_info
530 * PUBLIC: __P((ENV *, db_mutex_t, uintmax_t *, uintmax_t *));
531 */
532 void
__mutex_set_wait_info(env,mutex,waitp,nowaitp)533 __mutex_set_wait_info(env, mutex, waitp, nowaitp)
534 ENV *env;
535 db_mutex_t mutex;
536 uintmax_t *waitp, *nowaitp;
537 {
538 DB_MUTEX *mutexp;
539
540 if (mutex == MUTEX_INVALID) {
541 *waitp = 0;
542 *nowaitp = 0;
543 return;
544 }
545 mutexp = MUTEXP_SET(env, mutex);
546
547 *waitp = mutexp->mutex_set_wait;
548 *nowaitp = mutexp->mutex_set_nowait;
549 }
550
551 /*
552 * __mutex_clear --
553 * Clear mutex statistics.
554 *
555 * PUBLIC: void __mutex_clear __P((ENV *, db_mutex_t));
556 */
557 void
__mutex_clear(env,mutex)558 __mutex_clear(env, mutex)
559 ENV *env;
560 db_mutex_t mutex;
561 {
562 DB_MUTEX *mutexp;
563
564 if (!MUTEX_ON(env))
565 return;
566
567 mutexp = MUTEXP_SET(env, mutex);
568
569 mutexp->mutex_set_wait = mutexp->mutex_set_nowait = 0;
570 #ifdef HAVE_SHARED_LATCHES
571 mutexp->mutex_set_rd_wait = mutexp->mutex_set_rd_nowait = 0;
572 #endif
573 #ifdef HAVE_MUTEX_HYBRID
574 mutexp->hybrid_wait = mutexp->hybrid_wakeup = 0;
575 #endif
576 }
577
578 #else /* !HAVE_STATISTICS */
579
580 int
__mutex_stat_pp(dbenv,statp,flags)581 __mutex_stat_pp(dbenv, statp, flags)
582 DB_ENV *dbenv;
583 DB_MUTEX_STAT **statp;
584 u_int32_t flags;
585 {
586 COMPQUIET(statp, NULL);
587 COMPQUIET(flags, 0);
588
589 return (__db_stat_not_built(dbenv->env));
590 }
591
592 int
__mutex_stat_print_pp(dbenv,flags)593 __mutex_stat_print_pp(dbenv, flags)
594 DB_ENV *dbenv;
595 u_int32_t flags;
596 {
597 COMPQUIET(flags, 0);
598
599 return (__db_stat_not_built(dbenv->env));
600 }
601 #endif
602
603 /*
604 * __mutex_describe
605 * Fill in a buffer with the mutex #, alloc_id, and any other
606 * characteristics which are likely to be useful for diagnostics. The
607 * destination buffer must hold at least DB_MUTEX_DESCRIBE_STRLEN bytes.
608 *
609 * PUBLIC: char *__mutex_describe __P((ENV *, db_mutex_t, char *));
610 */
611 char *
__mutex_describe(env,mutex,dest)612 __mutex_describe(env, mutex, dest)
613 ENV *env;
614 db_mutex_t mutex;
615 char *dest;
616 {
617 DB_MUTEX *mutexp;
618 DB_MSGBUF mb, *mbp;
619 const char *type;
620
621 DB_MSGBUF_INIT(&mb);
622 mbp = &mb;
623 mutexp = MUTEXP_SET(env, mutex);
624 type = F_ISSET(mutexp, DB_MUTEX_SHARED) ? "latch" : "mutex";
625 #ifdef HAVE_STATISTICS
626 __db_msgadd(env, mbp, "%s %s id %ld ",
627 __mutex_print_id(mutexp->alloc_id), type, (long)mutex);
628 __db_prflags(env, mbp, mutexp->flags, MutexFlagNames, " (", ")");
629 #else
630 __db_msgadd(env, mbp, "%s flags %x id %ld ",
631 type, mutexp->flags, (long)mutex);
632 #endif
633 (void)snprintf(dest, DB_MUTEX_DESCRIBE_STRLEN - 1,
634 "%.*s", (int)(mbp->cur - mbp->buf), mbp->buf);
635 dest[DB_MUTEX_DESCRIBE_STRLEN - 1] = '\0';
636 return (dest);
637 }
638