add packaging
[platform/upstream/db4.git] / txn / txn_stat.c
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/db_am.h"
14 #include "dbinc/log.h"
15 #include "dbinc/txn.h"
16
17 #ifdef HAVE_STATISTICS
18 static int  __txn_compare __P((const void *, const void *));
19 static int  __txn_print_all __P((ENV *, u_int32_t));
20 static int  __txn_print_stats __P((ENV *, u_int32_t));
21 static int  __txn_stat __P((ENV *, DB_TXN_STAT **, u_int32_t));
22 static char *__txn_status __P((DB_TXN_ACTIVE *));
23 static void __txn_gid __P((ENV *, DB_MSGBUF *, DB_TXN_ACTIVE *));
24
25 /*
26  * __txn_stat_pp --
27  *      DB_ENV->txn_stat pre/post processing.
28  *
29  * PUBLIC: int __txn_stat_pp __P((DB_ENV *, DB_TXN_STAT **, u_int32_t));
30  */
31 int
32 __txn_stat_pp(dbenv, statp, flags)
33         DB_ENV *dbenv;
34         DB_TXN_STAT **statp;
35         u_int32_t flags;
36 {
37         DB_THREAD_INFO *ip;
38         ENV *env;
39         int ret;
40
41         env = dbenv->env;
42
43         ENV_REQUIRES_CONFIG(env,
44             env->tx_handle, "DB_ENV->txn_stat", DB_INIT_TXN);
45
46         if ((ret = __db_fchk(env,
47             "DB_ENV->txn_stat", flags, DB_STAT_CLEAR)) != 0)
48                 return (ret);
49
50         ENV_ENTER(env, ip);
51         REPLICATION_WRAP(env, (__txn_stat(env, statp, flags)), 0, ret);
52         ENV_LEAVE(env, ip);
53         return (ret);
54 }
55
56 /*
57  * __txn_stat --
58  *      ENV->txn_stat.
59  */
60 static int
61 __txn_stat(env, statp, flags)
62         ENV *env;
63         DB_TXN_STAT **statp;
64         u_int32_t flags;
65 {
66         DB_TXNMGR *mgr;
67         DB_TXNREGION *region;
68         DB_TXN_STAT *stats;
69         TXN_DETAIL *td;
70         size_t nbytes;
71         u_int32_t maxtxn, ndx;
72         int ret;
73
74         *statp = NULL;
75         mgr = env->tx_handle;
76         region = mgr->reginfo.primary;
77
78         /*
79          * Allocate for the maximum active transactions -- the DB_TXN_ACTIVE
80          * struct is small and the maximum number of active transactions is
81          * not going to be that large.  Don't have to lock anything to look
82          * at the region's maximum active transactions value, it's read-only
83          * and never changes after the region is created.
84          *
85          * The maximum active transactions isn't a hard limit, so allocate
86          * some extra room, and don't walk off the end.
87          */
88         maxtxn = region->maxtxns + (region->maxtxns / 10) + 10;
89         nbytes = sizeof(DB_TXN_STAT) + sizeof(DB_TXN_ACTIVE) * maxtxn;
90         if ((ret = __os_umalloc(env, nbytes, &stats)) != 0)
91                 return (ret);
92
93         TXN_SYSTEM_LOCK(env);
94         memcpy(stats, &region->stat, sizeof(*stats));
95         stats->st_last_txnid = region->last_txnid;
96         stats->st_last_ckp = region->last_ckp;
97         stats->st_time_ckp = region->time_ckp;
98         stats->st_txnarray = (DB_TXN_ACTIVE *)&stats[1];
99
100         for (ndx = 0,
101             td = SH_TAILQ_FIRST(&region->active_txn, __txn_detail);
102             td != NULL && ndx < maxtxn;
103             td = SH_TAILQ_NEXT(td, links, __txn_detail), ++ndx) {
104                 stats->st_txnarray[ndx].txnid = td->txnid;
105                 if (td->parent == INVALID_ROFF)
106                         stats->st_txnarray[ndx].parentid = TXN_INVALID;
107                 else
108                         stats->st_txnarray[ndx].parentid =
109                             ((TXN_DETAIL *)R_ADDR(&mgr->reginfo,
110                             td->parent))->txnid;
111                 stats->st_txnarray[ndx].pid = td->pid;
112                 stats->st_txnarray[ndx].tid = td->tid;
113                 stats->st_txnarray[ndx].lsn = td->begin_lsn;
114                 stats->st_txnarray[ndx].read_lsn = td->read_lsn;
115                 stats->st_txnarray[ndx].mvcc_ref = td->mvcc_ref;
116                 stats->st_txnarray[ndx].status = td->status;
117                 if (td->status == TXN_PREPARED)
118                         memcpy(stats->st_txnarray[ndx].gid,
119                             td->gid, sizeof(td->gid));
120                 if (td->name != INVALID_ROFF) {
121                         (void)strncpy(stats->st_txnarray[ndx].name,
122                             R_ADDR(&mgr->reginfo, td->name),
123                             sizeof(stats->st_txnarray[ndx].name) - 1);
124                         stats->st_txnarray[ndx].name[
125                             sizeof(stats->st_txnarray[ndx].name) - 1] = '\0';
126                 } else
127                         stats->st_txnarray[ndx].name[0] = '\0';
128         }
129
130         __mutex_set_wait_info(env, region->mtx_region,
131             &stats->st_region_wait, &stats->st_region_nowait);
132         stats->st_regsize = mgr->reginfo.rp->size;
133         if (LF_ISSET(DB_STAT_CLEAR)) {
134                 if (!LF_ISSET(DB_STAT_SUBSYSTEM))
135                         __mutex_clear(env, region->mtx_region);
136                 memset(&region->stat, 0, sizeof(region->stat));
137                 region->stat.st_maxtxns = region->maxtxns;
138                 region->stat.st_maxnactive =
139                     region->stat.st_nactive = stats->st_nactive;
140                 region->stat.st_maxnsnapshot =
141                     region->stat.st_nsnapshot = stats->st_nsnapshot;
142         }
143
144         TXN_SYSTEM_UNLOCK(env);
145
146         *statp = stats;
147         return (0);
148 }
149
150 /*
151  * __txn_stat_print_pp --
152  *      DB_ENV->txn_stat_print pre/post processing.
153  *
154  * PUBLIC: int __txn_stat_print_pp __P((DB_ENV *, u_int32_t));
155  */
156 int
157 __txn_stat_print_pp(dbenv, flags)
158         DB_ENV *dbenv;
159         u_int32_t flags;
160 {
161         DB_THREAD_INFO *ip;
162         ENV *env;
163         int ret;
164
165         env = dbenv->env;
166
167         ENV_REQUIRES_CONFIG(env,
168             env->tx_handle, "DB_ENV->txn_stat_print", DB_INIT_TXN);
169
170         if ((ret = __db_fchk(env, "DB_ENV->txn_stat_print",
171             flags, DB_STAT_ALL | DB_STAT_CLEAR)) != 0)
172                 return (ret);
173
174         ENV_ENTER(env, ip);
175         REPLICATION_WRAP(env, (__txn_stat_print(env, flags)), 0, ret);
176         ENV_LEAVE(env, ip);
177         return (ret);
178 }
179
180 /*
181  * __txn_stat_print
182  *      ENV->txn_stat_print method.
183  *
184  * PUBLIC: int  __txn_stat_print __P((ENV *, u_int32_t));
185  */
186 int
187 __txn_stat_print(env, flags)
188         ENV *env;
189         u_int32_t flags;
190 {
191         u_int32_t orig_flags;
192         int ret;
193
194         orig_flags = flags;
195         LF_CLR(DB_STAT_CLEAR | DB_STAT_SUBSYSTEM);
196         if (flags == 0 || LF_ISSET(DB_STAT_ALL)) {
197                 ret = __txn_print_stats(env, orig_flags);
198                 if (flags == 0 || ret != 0)
199                         return (ret);
200         }
201
202         if (LF_ISSET(DB_STAT_ALL) &&
203             (ret = __txn_print_all(env, orig_flags)) != 0)
204                 return (ret);
205
206         return (0);
207 }
208
209 /*
210  * __txn_print_stats --
211  *      Display default transaction region statistics.
212  */
213 static int
214 __txn_print_stats(env, flags)
215         ENV *env;
216         u_int32_t flags;
217 {
218         DB_ENV *dbenv;
219         DB_MSGBUF mb;
220         DB_TXN_ACTIVE *txn;
221         DB_TXN_STAT *sp;
222         u_int32_t i;
223         int ret;
224         char buf[DB_THREADID_STRLEN], time_buf[CTIME_BUFLEN];
225
226         dbenv = env->dbenv;
227
228         if ((ret = __txn_stat(env, &sp, flags)) != 0)
229                 return (ret);
230
231         if (LF_ISSET(DB_STAT_ALL))
232                 __db_msg(env, "Default transaction region information:");
233         __db_msg(env, "%lu/%lu\t%s",
234             (u_long)sp->st_last_ckp.file, (u_long)sp->st_last_ckp.offset,
235             sp->st_last_ckp.file == 0 ?
236             "No checkpoint LSN" : "File/offset for last checkpoint LSN");
237         if (sp->st_time_ckp == 0)
238                 __db_msg(env, "0\tNo checkpoint timestamp");
239         else
240                 __db_msg(env, "%.24s\tCheckpoint timestamp",
241                     __os_ctime(&sp->st_time_ckp, time_buf));
242         __db_msg(env, "%#lx\tLast transaction ID allocated",
243             (u_long)sp->st_last_txnid);
244         __db_dl(env, "Maximum number of active transactions configured",
245             (u_long)sp->st_maxtxns);
246         __db_dl(env, "Active transactions", (u_long)sp->st_nactive);
247         __db_dl(env,
248             "Maximum active transactions", (u_long)sp->st_maxnactive);
249         __db_dl(env,
250             "Number of transactions begun", (u_long)sp->st_nbegins);
251         __db_dl(env,
252             "Number of transactions aborted", (u_long)sp->st_naborts);
253         __db_dl(env,
254             "Number of transactions committed", (u_long)sp->st_ncommits);
255         __db_dl(env, "Snapshot transactions", (u_long)sp->st_nsnapshot);
256         __db_dl(env, "Maximum snapshot transactions",
257             (u_long)sp->st_maxnsnapshot);
258         __db_dl(env,
259             "Number of transactions restored", (u_long)sp->st_nrestores);
260
261         __db_dlbytes(env, "Transaction region size",
262             (u_long)0, (u_long)0, (u_long)sp->st_regsize);
263         __db_dl_pct(env,
264             "The number of region locks that required waiting",
265             (u_long)sp->st_region_wait, DB_PCT(sp->st_region_wait,
266             sp->st_region_wait + sp->st_region_nowait), NULL);
267
268         qsort(sp->st_txnarray,
269             sp->st_nactive, sizeof(sp->st_txnarray[0]), __txn_compare);
270         __db_msg(env, "Active transactions:");
271         DB_MSGBUF_INIT(&mb);
272         for (i = 0; i < sp->st_nactive; ++i) {
273                 txn = &sp->st_txnarray[i];
274                 __db_msgadd(env, &mb,
275             "\t%lx: %s; pid/thread %s; begin LSN: file/offset %lu/%lu",
276                     (u_long)txn->txnid, __txn_status(txn),
277                     dbenv->thread_id_string(dbenv, txn->pid, txn->tid, buf),
278                     (u_long)txn->lsn.file, (u_long)txn->lsn.offset);
279                 if (txn->parentid != 0)
280                         __db_msgadd(env, &mb,
281                             "; parent: %lx", (u_long)txn->parentid);
282                 if (!IS_MAX_LSN(txn->read_lsn))
283                         __db_msgadd(env, &mb, "; read LSN: %lu/%lu",
284                             (u_long)txn->read_lsn.file,
285                             (u_long)txn->read_lsn.offset);
286                 if (txn->mvcc_ref != 0)
287                         __db_msgadd(env, &mb,
288                             "; mvcc refcount: %lu", (u_long)txn->mvcc_ref);
289                 if (txn->name[0] != '\0')
290                         __db_msgadd(env, &mb, "; \"%s\"", txn->name);
291                 if (txn->status == TXN_PREPARE)
292                         __txn_gid(env, &mb, txn);
293                 DB_MSGBUF_FLUSH(env, &mb);
294         }
295
296         __os_ufree(env, sp);
297
298         return (0);
299 }
300
301 /*
302  * __txn_print_all --
303  *      Display debugging transaction region statistics.
304  */
305 static int
306 __txn_print_all(env, flags)
307         ENV *env;
308         u_int32_t flags;
309 {
310         static const FN fn[] = {
311                 { TXN_IN_RECOVERY,      "TXN_IN_RECOVERY" },
312                 { 0,                    NULL }
313         };
314         DB_TXNMGR *mgr;
315         DB_TXNREGION *region;
316         char time_buf[CTIME_BUFLEN];
317
318         mgr = env->tx_handle;
319         region = mgr->reginfo.primary;
320
321         TXN_SYSTEM_LOCK(env);
322
323         __db_print_reginfo(env, &mgr->reginfo, "Transaction", flags);
324
325         __db_msg(env, "%s", DB_GLOBAL(db_line));
326         __db_msg(env, "DB_TXNMGR handle information:");
327         __mutex_print_debug_single(env, "DB_TXNMGR mutex", mgr->mutex, flags);
328         __db_dl(env,
329             "Number of transactions discarded", (u_long)mgr->n_discards);
330
331         __db_msg(env, "%s", DB_GLOBAL(db_line));
332         __db_msg(env, "DB_TXNREGION handle information:");
333         __mutex_print_debug_single(
334             env, "DB_TXNREGION region mutex", region->mtx_region, flags);
335         STAT_ULONG("Maximum number of active txns", region->maxtxns);
336         STAT_HEX("Last transaction ID allocated", region->last_txnid);
337         STAT_HEX("Current maximum unused ID", region->cur_maxid);
338
339         __mutex_print_debug_single(
340             env, "checkpoint mutex", region->mtx_ckp, flags);
341         STAT_LSN("Last checkpoint LSN", &region->last_ckp);
342         __db_msg(env,
343             "%.24s\tLast checkpoint timestamp",
344             region->time_ckp == 0 ? "0" :
345             __os_ctime(&region->time_ckp, time_buf));
346
347         __db_prflags(env, NULL, region->flags, fn, NULL, "\tFlags");
348
349         __db_msg(env, "%s", DB_GLOBAL(db_line));
350         TXN_SYSTEM_UNLOCK(env);
351
352         return (0);
353 }
354
355 static char *
356 __txn_status(txn)
357         DB_TXN_ACTIVE *txn;
358 {
359         switch (txn->status) {
360         case TXN_ABORTED:
361                 return ("aborted");
362         case TXN_COMMITTED:
363                 return ("committed");
364         case TXN_PREPARED:
365                 return ("prepared");
366         case TXN_RUNNING:
367                 return ("running");
368         default:
369                 break;
370         }
371         return ("unknown state");
372 }
373
374 static void
375 __txn_gid(env, mbp, txn)
376         ENV *env;
377         DB_MSGBUF *mbp;
378         DB_TXN_ACTIVE *txn;
379 {
380         u_int32_t v, *xp;
381         u_int i;
382         int cnt;
383
384         __db_msgadd(env, mbp, "\n\tGID:");
385         for (cnt = 0, xp = (u_int32_t *)txn->gid, i = 0;;) {
386                 memcpy(&v, xp++, sizeof(u_int32_t));
387                 __db_msgadd(env, mbp, "%#lx ", (u_long)v);
388                 if ((i += sizeof(u_int32_t)) >= DB_GID_SIZE)
389                         break;
390                 if (++cnt == 4) {
391                         DB_MSGBUF_FLUSH(env, mbp);
392                         __db_msgadd(env, mbp, "\t\t");
393                         cnt = 0;
394                 }
395         }
396 }
397
398 static int
399 __txn_compare(a1, b1)
400         const void *a1, *b1;
401 {
402         const DB_TXN_ACTIVE *a, *b;
403
404         a = a1;
405         b = b1;
406
407         if (a->txnid > b->txnid)
408                 return (1);
409         if (a->txnid < b->txnid)
410                 return (-1);
411         return (0);
412 }
413
414 #else /* !HAVE_STATISTICS */
415
416 int
417 __txn_stat_pp(dbenv, statp, flags)
418         DB_ENV *dbenv;
419         DB_TXN_STAT **statp;
420         u_int32_t flags;
421 {
422         COMPQUIET(statp, NULL);
423         COMPQUIET(flags, 0);
424
425         return (__db_stat_not_built(dbenv->env));
426 }
427
428 int
429 __txn_stat_print_pp(dbenv, flags)
430         DB_ENV *dbenv;
431         u_int32_t flags;
432 {
433         COMPQUIET(flags, 0);
434
435         return (__db_stat_not_built(dbenv->env));
436 }
437 #endif