3 * print information about ovdb database
13 #include "inn/innconf.h"
14 #include "inn/messages.h"
20 #include "../storage/ovdb/ovdb.h"
21 #include "../storage/ovdb/ovdb-private.h"
24 #ifndef USE_BERKELEY_DB
26 int main(int argc UNUSED, char **argv UNUSED)
28 die("BerkeleyDB support not compiled");
31 #else /* USE_BERKELEY_DB */
33 static int signalled = 0;
34 static void sigfunc(int signum UNUSED)
43 INT32, /* 'a' points to u_int32_t */
44 HEX32, /* 'a' printed in hex */
45 DIFF32, /* 'a' - 'b' - 'c' */
46 PCT32, /* 100 * 'a' / ('a' + 'b') */
47 FF, /* 'a' = freebytes, 'b' = npages, 'c' = pagesize */
48 BYTES, /* 'a' = bytes, 'b' = mbytes, 'c' = gbytes */
49 MODE, /* 'a' points to int, printed as octal mode */
50 TIME, /* 'a' points to time_t, printed as date/time */
51 LSN, /* 'a' points to DB_LSN */
52 STR, /* 'a' points to char* */
53 SIZE /* 'a' points to size_t */
64 static void display_heading(const char *str)
67 printf("<h2>%s<h2>\n", str);
73 static void getval(int i, void *p, struct datatab *tab, char *val, char *sufx)
76 u_int32_t a = 0, b = 0, c = 0, bytes = 0, mbytes = 0, gbytes = 0;
87 case INT32: /* 'a' points to u_int32_t */
88 memcpy(&a, cp + tab[i].a, sizeof(a));
89 sprintf(val, "%u", a);
91 case HEX32: /* 'a' printed in hex */
92 memcpy(&a, cp + tab[i].a, sizeof(a));
93 sprintf(val, "%x", a);
95 case DIFF32: /* 'a' - 'b' - 'c' */
96 memcpy(&a, cp + tab[i].a, sizeof(a));
97 memcpy(&b, cp + tab[i].b, sizeof(b));
99 memcpy(&c, cp + tab[i].c, sizeof(c));
100 sprintf(val, "%d", a - b - c);
102 sprintf(val, "%d", a - b);
105 case PCT32: /* 100 * 'a' / ('a' + 'b') */
106 memcpy(&a, cp + tab[i].a, sizeof(a));
107 memcpy(&b, cp + tab[i].b, sizeof(b));
108 sprintf(val, "%.0f", (double) a / (a + b) * 100.0);
111 case FF: /* 'a' = freebytes, 'b' = npages, 'c' = pagesize */
112 memcpy(&a, cp + tab[i].a, sizeof(a));
113 memcpy(&b, cp + tab[i].b, sizeof(b));
114 memcpy(&c, cp + tab[i].c, sizeof(c));
116 sprintf(val, "%.0f", 0.0);
118 sprintf(val, "%.0f", (double)((b * c) - a) / (b * c) * 100);
122 case BYTES: /* 'a' = bytes, 'b' = mbytes, 'c' = gbytes */
124 memcpy(&bytes, cp + tab[i].a, sizeof(bytes));
128 memcpy(&mbytes, cp + tab[i].b, sizeof(mbytes));
132 memcpy(&gbytes, cp + tab[i].c, sizeof(gbytes));
135 if(gbytes > 0 || mbytes > 0) {
136 mbytes += gbytes * 1024;
137 if(bytes > (1024*1024))
138 mbytes += bytes / (1024*1024);
139 sprintf(val, "%u", mbytes);
142 sprintf(val, "%u", bytes);
145 case MODE: /* 'a' points to int, printed as octal mode */
146 memcpy(&mode, cp + tab[i].a, sizeof(mode));
147 sprintf(val, "%04o", mode);
149 case TIME: /* 'a' points to time_t, printed as date/time */
150 memcpy(&tm, cp + tab[i].a, sizeof(tm));
154 strftime(val, SMBUF, "%Y-%m-%d %T %Z", localtime(&tm));
157 case LSN: /* 'a' points to DB_LSN */
158 dl = (DB_LSN *)(cp + tab[i].a);
162 sprintf(val, "%u/%u", dl->file, dl->offset);
165 case STR: /* 'a' points to char* */
166 memcpy(&tmp, cp + tab[i].a, sizeof(tmp));
169 case SIZE: /* 'a' points to size_t */
170 memcpy(&sz, cp + tab[i].a, sizeof(sz));
171 sprintf(val, "%lu", (unsigned long) sz);
178 static char *myctime(time_t *tm)
180 static char val[SMBUF];
181 strftime(val, SMBUF, "%Y-%m-%d %T %Z", localtime(tm));
185 static void display_data(void *p, struct datatab *tab)
188 char val[SMBUF], sufx[SMBUF];
190 puts("<table border=0 cellpadding=1>");
191 for(i = 0; tab[i].type != END; i++) {
192 getval(i, p, tab, val, sufx);
194 printf("<tr><td align=right>%s<td>%s<td>%s\n", val, sufx, tab[i].desc);
196 printf("%16s%-2s %s\n", val, sufx, tab[i].desc);
202 static void start_table(const char *label, struct datatab *tab)
206 printf("<h2>%s</h2>\n", label);
207 puts("<table border=0 cellpadding=1>\n<tr bgcolor=#3399aa>");
208 for(i = 0; tab[i].type != END; i++)
209 printf("<th colspan=2>%s\n", tab[i].desc);
213 static void display_row(void *p, struct datatab *tab)
216 char val[SMBUF], sufx[SMBUF];
219 for(i = 0; tab[i].type != END; i++) {
220 getval(i, p, tab, val, sufx);
221 printf("<td align=right>%s<td>%s\n", val, sufx);
224 puts("---------------------------------------------");
225 display_data(p, tab);
229 static void end_table(void)
235 #define OFFSETOF(type, f) ((char *)&(((type *)0)->f) - (char *)0)
237 #define F(f) OFFSETOF(DB_LOCK_STAT, f)
239 static struct datatab LOCK_tab[] = {
240 #if DB_VERSION_MAJOR >= 3
242 #if DB_VERSION_MAJOR > 4 || (DB_VERSION_MAJOR == 4 && DB_VERSION_MINOR >= 1)
247 -1, -1, "Last allocated locker ID" },
249 { INT32, F(st_maxlocks), -1, -1, "Maximum number of locks possible" },
250 #if DB_VERSION_MAJOR >= 4 || (DB_VERSION_MAJOR == 3 && DB_VERSION_MINOR >= 2)
251 { INT32, F(st_maxlockers), -1, -1, "Maximum number of lockers possible" },
252 { INT32, F(st_maxobjects), -1, -1, "Maximum number of objects possible" },
254 { INT32, F(st_nmodes), -1, -1, "Lock modes" },
255 #if DB_VERSION_MAJOR >= 4 || (DB_VERSION_MAJOR == 3 && DB_VERSION_MINOR >= 2)
256 { INT32, F(st_nlocks), -1, -1, "Current locks" },
257 { INT32, F(st_maxnlocks), -1, -1, "Maximum locks" },
259 { INT32, F(st_nlockers), -1, -1, "Current lockers" },
260 #if DB_VERSION_MAJOR >= 3
261 { INT32, F(st_maxnlockers), -1, -1, "Maximum lockers" },
263 { INT32, F(st_numobjs), -1, -1, "Lock objects" },
265 #if DB_VERSION_MAJOR >= 4 || (DB_VERSION_MAJOR == 3 && DB_VERSION_MINOR >= 2)
266 { INT32, F(st_nobjects), -1, -1, "Current objects" },
267 { INT32, F(st_maxnobjects), -1, -1, "Maximum objects" },
269 #if DB_VERSION_MAJOR == 4 && DB_VERSION_MINOR >= 4
270 { INT32, F(st_lock_wait), -1, -1, "Lock conflicts" },
272 { INT32, F(st_nconflicts), -1, -1, "Lock conflicts" },
274 { INT32, F(st_nrequests), -1, -1, "Lock requests" },
275 { INT32, F(st_nreleases), -1, -1, "Lock releases" },
276 { DIFF32, F(st_nrequests), F(st_nreleases), F(st_ndeadlocks), "Outstanding locks" },
277 #if DB_VERSION_MAJOR == 4 && DB_VERSION_MINOR >= 4
278 { INT32, F(st_lock_nowait), -1, -1, "Lock conflicts w/o subsequent wait" },
279 #elif DB_VERSION_MAJOR >= 4 || (DB_VERSION_MAJOR == 3 && DB_VERSION_MINOR > 0)
280 { INT32, F(st_nnowaits), -1, -1, "Lock conflicts w/o subsequent wait" },
282 { INT32, F(st_ndeadlocks), -1, -1, "Deadlocks" },
283 #if DB_VERSION_MAJOR >= 4
284 { INT32, F(st_nlocktimeouts), -1, -1, "Lock timeouts" },
285 { INT32, F(st_ntxntimeouts), -1, -1, "Transaction timeouts" },
287 { INT32, F(st_region_nowait), -1, -1, "Region locks granted without waiting" },
288 { INT32, F(st_region_wait), -1, -1, "Region locks granted after waiting" },
289 { BYTES, F(st_regsize), -1, -1, "Lock region size" },
290 { END, -1, -1, -1, NULL }
293 static int display_lock(void)
297 #if DB_VERSION_MAJOR == 2
298 if(lock_stat(OVDBenv->lk_info, &sp, NULL) != 0)
299 #elif DB_VERSION_MAJOR == 3 && DB_VERSION_MINOR <= 2
300 if(lock_stat(OVDBenv, &sp, NULL) != 0)
301 #elif DB_VERSION_MAJOR == 3
302 if(lock_stat(OVDBenv, &sp) != 0)
304 if(OVDBenv->lock_stat(OVDBenv, &sp, 0) != 0)
308 display_heading("Lock Region Statistics");
309 display_data(sp, LOCK_tab);
317 #define F(f) OFFSETOF(DB_LOG_STAT, f)
319 static struct datatab LOG_tab[] = {
320 { HEX32, F(st_magic), -1, -1, "Log magic number" },
321 { INT32, F(st_version), -1, -1, "Log version number" },
322 { MODE, F(st_mode), -1, -1, "Log file mode" },
323 #if DB_VERSION_MAJOR >= 3
324 { BYTES, F(st_lg_bsize), -1, -1, "Log record cache size" },
326 #if DB_VERSION_MAJOR > 4 || (DB_VERSION_MAJOR == 4 && DB_VERSION_MINOR >= 1)
327 { BYTES, F(st_lg_size), -1, -1, "The current log file size" },
329 { BYTES, F(st_lg_max), -1, -1, "Max log file size" },
331 { BYTES, F(st_w_bytes), F(st_w_mbytes), -1, "Log bytes written" },
332 { BYTES, F(st_wc_bytes), F(st_wc_mbytes), -1, "Log bytes written since last checkpoint" },
333 { INT32, F(st_wcount), -1, -1, "Total log writes" },
334 #if DB_VERSION_MAJOR >= 3
335 { INT32, F(st_wcount_fill), -1, -1, "Total log writes due to overflow" },
337 { INT32, F(st_scount), -1, -1, "Total log flushes" },
338 { INT32, F(st_region_nowait), -1, -1, "Region locks granted without waiting" },
339 { INT32, F(st_region_wait), -1, -1, "Region locks granted after waiting" },
340 { INT32, F(st_cur_file), -1, -1, "Current log file number" },
341 { INT32, F(st_cur_offset), -1, -1, "Current log file offset" },
342 #if DB_VERSION_MAJOR >= 4 || (DB_VERSION_MAJOR == 3 && DB_VERSION_MINOR >= 3)
343 { INT32, F(st_disk_file), -1, -1, "Known on disk log file number" },
344 { INT32, F(st_disk_offset), -1, -1, "Known on disk log file offset" },
346 { BYTES, F(st_regsize), -1, -1, "Log region size" },
347 #if DB_VERSION_MAJOR >= 4
348 #if DB_VERSION_MINOR < 1
349 { INT32, F(st_flushcommit), -1, -1, "Flushes containing a commit"},
351 { INT32, F(st_maxcommitperflush), -1, -1, "Max number of commits in a flush"},
352 { INT32, F(st_mincommitperflush), -1, -1, "Min number of commits in a flush"},
354 { END, -1, -1, -1, NULL }
357 static int display_log(void)
361 #if DB_VERSION_MAJOR == 2
362 if(log_stat(OVDBenv->lg_info, &sp, NULL) != 0)
363 #elif DB_VERSION_MAJOR == 3 && DB_VERSION_MINOR <= 2
364 if(log_stat(OVDBenv, &sp, NULL) != 0)
365 #elif DB_VERSION_MAJOR == 3
366 if(log_stat(OVDBenv, &sp) != 0)
368 if(OVDBenv->log_stat(OVDBenv, &sp, 0) != 0)
372 display_heading("Log Region Statistics");
373 display_data(sp, LOG_tab);
381 #define F(f) OFFSETOF(DB_MPOOL_STAT, f)
383 static struct datatab MEM_tab[] = {
384 { INT32, F(st_cache_hit), -1, -1, "Cache hits"},
385 { INT32, F(st_cache_miss), -1, -1, "Cache misses"},
386 { PCT32, F(st_cache_hit), F(st_cache_miss), -1, "Cache hit percentage"},
387 #if DB_VERSION_MAJOR == 2
388 { INT32, F(st_cachesize), -1, -1, "Total cache size"},
389 { INT32, F(st_regsize), -1, -1, "Pool region size"},
391 { BYTES, F(st_bytes), -1, F(st_gbytes), "Total cache size"},
392 #if DB_VERSION_MAJOR == 3 && DB_VERSION_MINOR == 0
393 { INT32, F(st_regsize), -1, -1, "Pool region size"},
395 { INT32, F(st_ncache), -1, -1, "Number of caches"},
396 { INT32, F(st_regsize), -1, -1, "Pool individual cache size"},
399 { INT32, F(st_map), -1, -1, "Memory mapped pages"},
400 { INT32, F(st_page_create), -1, -1, "Pages created in the cache"},
401 { INT32, F(st_page_in), -1, -1, "Pages read into the cache"},
402 { INT32, F(st_page_out), -1, -1, "Pages written from the cache to the backing file"},
403 { INT32, F(st_ro_evict), -1, -1, "Clean pages forced from the cache"},
404 { INT32, F(st_rw_evict), -1, -1, "Dirty pages forced from the cache"},
405 { INT32, F(st_hash_buckets), -1, -1, "Hash buckets used for page location"},
406 { INT32, F(st_hash_searches), -1, -1, "Total hash chain searches"},
407 { INT32, F(st_hash_longest), -1, -1, "Longest hash chain searched"},
408 { INT32, F(st_hash_examined), -1, -1, "Total hash entries searched"},
409 { INT32, F(st_page_trickle), -1, -1, "Dirty buffers written by trickle-sync thread"},
410 { INT32, F(st_page_clean), -1, -1, "Current clean buffer count"},
411 { INT32, F(st_page_dirty), -1, -1, "Current dirty buffer count"},
412 { INT32, F(st_region_nowait), -1, -1, "Region locks granted without waiting"},
413 { INT32, F(st_region_wait), -1, -1, "Region locks granted after waiting"},
414 { END, -1, -1, -1, NULL }
418 #define F(f) OFFSETOF(DB_MPOOL_FSTAT, f)
420 static struct datatab MEMF_tab[] = {
421 { STR, F(file_name), -1, -1, "Database"},
422 { SIZE, F(st_pagesize), -1, -1, "Page size"},
423 { INT32, F(st_cache_hit), -1, -1, "Cache hits"},
424 { INT32, F(st_cache_miss), -1, -1, "Cache misses"},
425 { PCT32, F(st_cache_hit), F(st_cache_miss), -1, "Cache hit percentage"},
426 { INT32, F(st_map), -1, -1, "Memory mapped pages"},
427 { INT32, F(st_page_create), -1, -1, "Pages created in the cache"},
428 { INT32, F(st_page_in), -1, -1, "Pages read into the cache"},
429 { INT32, F(st_page_out), -1, -1, "Pages written from the cache to the backing file"},
430 { END, -1, -1, -1, NULL }
433 static int display_mem(int all)
435 DB_MPOOL_FSTAT **fsp;
438 #if DB_VERSION_MAJOR == 2
439 if(memp_stat(OVDBenv->mp_info, &gsp, &fsp, NULL) != 0)
440 #elif DB_VERSION_MAJOR == 3 && DB_VERSION_MINOR <= 2
441 if(memp_stat(OVDBenv, &gsp, &fsp, NULL) != 0)
442 #elif DB_VERSION_MAJOR == 3
443 if(memp_stat(OVDBenv, &gsp, &fsp) != 0)
445 if(OVDBenv->memp_stat(OVDBenv, &gsp, &fsp, 0) != 0)
449 display_heading("Memory Pool Statistics");
450 display_data(gsp, MEM_tab);
453 DB_MPOOL_FSTAT **p = fsp;
455 start_table("Per-database Memory Pool Statistics", MEMF_tab);
456 for(; p != NULL && *p != NULL; ++p) {
457 display_row(*p, MEMF_tab);
467 static int txn_compare(const void *a, const void *b)
469 if (((const DB_TXN_ACTIVE *)a)->txnid > ((const DB_TXN_ACTIVE *)b)->txnid)
471 if (((const DB_TXN_ACTIVE *)a)->txnid < ((const DB_TXN_ACTIVE *)b)->txnid)
477 #define F(f) OFFSETOF(DB_TXN_STAT, f)
479 static struct datatab TXN_tab[] = {
480 { LSN, F(st_last_ckp), -1, -1, "File/offset for last checkpoint LSN" },
481 #if DB_VERSION_MAJOR < 4 || (DB_VERSION_MAJOR == 4 && DB_VERSION_MINOR < 1)
482 { LSN, F(st_pending_ckp), -1, -1, "File/offset for last pending checkpoint LSN" },
484 { TIME, F(st_time_ckp), -1, -1, "Checkpoint timestamp" },
485 { HEX32, F(st_last_txnid), -1, -1, "Last transaction ID allocated" },
486 { INT32, F(st_maxtxns), -1, -1, "Maximum active transactions possible" },
487 { INT32, F(st_nactive), -1, -1, "Active transactions" },
488 #if DB_VERSION_MAJOR >= 4 || (DB_VERSION_MAJOR == 3 && DB_VERSION_MINOR >= 3)
489 { INT32, F(st_nrestores), -1, -1, "Restored transactions after recovery" },
491 #if DB_VERSION_MAJOR >= 3
492 { INT32, F(st_maxnactive), -1, -1, "Maximum active transactions" },
494 { INT32, F(st_nbegins), -1, -1, "Transactions started" },
495 { INT32, F(st_ncommits), -1, -1, "Transactions committed" },
496 { INT32, F(st_naborts), -1, -1, "Transactions aborted" },
497 { INT32, F(st_region_nowait), -1, -1, "Region locks granted without waiting"},
498 { INT32, F(st_region_wait), -1, -1, "Region locks granted after waiting"},
499 { BYTES, F(st_regsize), -1, -1, "Transaction region size" },
500 { END, -1, -1, -1, NULL }
504 #define F(f) OFFSETOF(DB_TXN_ACTIVE, f)
506 static struct datatab TXNA_tab[] = {
507 { INT32, F(txnid), -1, -1, "Transaction ID" },
508 #if DB_VERSION_MAJOR >= 3
509 { INT32, F(parentid), -1, -1, "Parent Transaction ID" },
511 { LSN, F(lsn), -1, -1, "Initial LSN file/offset" },
512 { END, -1, -1, -1, NULL }
515 static int display_txn(void)
520 #if DB_VERSION_MAJOR == 2
521 if(txn_stat(OVDBenv->tx_info, &sp, NULL) != 0)
522 #elif DB_VERSION_MAJOR == 3 && DB_VERSION_MINOR <= 2
523 if(txn_stat(OVDBenv, &sp, NULL) != 0)
524 #elif DB_VERSION_MAJOR == 3
525 if(txn_stat(OVDBenv, &sp) != 0)
527 if(OVDBenv->txn_stat(OVDBenv, &sp, 0) != 0)
531 display_heading("Transaction Region Statistics");
532 display_data(sp, TXN_tab);
535 qsort(sp->st_txnarray, sp->st_nactive, sizeof(sp->st_txnarray[0]), txn_compare);
536 start_table("Active Transactions", TXNA_tab);
537 for (i = 0; i < sp->st_nactive; ++i)
538 display_row(&(sp->st_txnarray[i]), TXNA_tab);
545 static int display_ver(void)
547 if(html) puts("<p>");
548 printf("ovdb data version: %d\n", DATA_VERSION);
549 if(html) puts("<br>");
550 printf("BerkeleyDB version: %s\n", db_version(NULL,NULL,NULL));
551 if(html) puts("<p>");
556 #define F(f) OFFSETOF(DB_BTREE_STAT, f)
558 static struct datatab BTREE_tab[] = {
559 { HEX32, F(bt_magic), -1, -1, "Btree magic number" },
560 { INT32, F(bt_version), -1, -1, "Btree version number" },
561 { INT32, F(bt_minkey), -1, -1, "Minimum keys per page (minkey)" },
562 { INT32, F(bt_pagesize), -1, -1, "Database page size" },
563 { INT32, F(bt_levels), -1, -1, "Levels in the tree" },
564 #if DB_VERSION_MAJOR == 2 || (DB_VERSION_MAJOR == 3 && DB_VERSION_MINOR == 0)
565 { INT32, F(bt_nrecs), -1, -1, "Keys in the tree" },
567 { INT32, F(bt_nkeys), -1, -1, "Unique keys in the tree" },
568 { INT32, F(bt_ndata), -1, -1, "Data items in the tree" },
570 { INT32, F(bt_int_pg), -1, -1, "Tree internal pages" },
571 { BYTES, F(bt_int_pgfree), -1, -1, "Bytes free in internal pages" },
572 { FF, F(bt_int_pgfree), F(bt_int_pg), F(bt_pagesize), "Internal page fill factor" },
574 { INT32, F(bt_leaf_pg), -1, -1, "Tree leaf pages" },
575 { BYTES, F(bt_leaf_pgfree), -1, -1, "Bytes free in leaf pages" },
576 { FF, F(bt_leaf_pgfree), F(bt_leaf_pg), F(bt_pagesize), "Leaf page fill factor" },
578 { INT32, F(bt_dup_pg), -1, -1, "Tree duplicate pages" },
579 { BYTES, F(bt_dup_pgfree), -1, -1, "Bytes free in duplicate pages" },
580 { FF, F(bt_dup_pgfree), F(bt_dup_pg), F(bt_pagesize), "Duplicate page fill factor" },
582 { INT32, F(bt_over_pg), -1, -1, "Tree overflow pages" },
583 { BYTES, F(bt_over_pgfree), -1, -1, "Bytes free overflow pages" },
584 { FF, F(bt_over_pgfree), F(bt_over_pg), F(bt_pagesize), "Overflow page fill factor" },
586 #if DB_VERSION_MAJOR >= 3
587 { INT32, F(bt_free), -1, -1, "Pages on the free list" },
589 { END, -1, -1, -1, NULL }
592 static int display_btree(DB *db)
596 #if DB_VERSION_MAJOR > 4 || (DB_VERSION_MAJOR == 4 && DB_VERSION_MINOR >= 3)
597 if(db->stat(db, NULL, &sp, 0))
599 #if DB_VERSION_MAJOR == 4 || (DB_VERSION_MAJOR == 3 && DB_VERSION_MINOR >= 3)
600 if(db->stat(db, &sp, 0))
602 if(db->stat(db, &sp, NULL, 0))
607 display_heading("Btree Statistics");
608 display_data(sp, BTREE_tab);
615 #if DB_VERSION_MAJOR >= 3
618 #define F(f) OFFSETOF(DB_HASH_STAT, f)
620 static struct datatab HASH_tab[] = {
621 { HEX32, F(hash_magic), -1, -1, "Hash magic number" },
622 { INT32, F(hash_version), -1, -1, "Hash version number" },
623 { INT32, F(hash_pagesize), -1, -1, "Database page size" },
624 #if DB_VERSION_MAJOR == 3 && DB_VERSION_MINOR == 0
625 { INT32, F(hash_nrecs), -1, -1, "Keys in the database" },
627 { INT32, F(hash_nkeys), -1, -1, "Keys in the database" },
628 { INT32, F(hash_ndata), -1, -1, "Data items in the database" },
630 { INT32, F(hash_buckets), -1, -1, "Hash buckets" },
631 { BYTES, F(hash_bfree), -1, -1, "Bytes free on bucket pages" },
632 { FF, F(hash_buckets), F(hash_bfree), F(hash_pagesize), "Bucket page fill factor" },
634 { INT32, F(hash_bigpages), -1, -1, "Overflow pages" },
635 { BYTES, F(hash_big_bfree), -1, -1, "Bytes free on Overflow pages" },
636 { FF, F(hash_bigpages), F(hash_big_bfree), F(hash_pagesize), "Overflow page fill factor" },
638 { INT32, F(hash_overflows), -1, -1, "Bucket overflow pages" },
639 { BYTES, F(hash_ovfl_free), -1, -1, "Bytes free on bucket overflow pages" },
640 { FF, F(hash_overflows), F(hash_ovfl_free), F(hash_pagesize), "Bucket overflow page fill factor" },
642 { INT32, F(hash_dup), -1, -1, "Duplicate pages" },
643 { BYTES, F(hash_dup_free), -1, -1, "Bytes free in duplicate pages" },
644 { FF, F(hash_dup), F(hash_dup_free), F(hash_pagesize), "Duplicate page fill factor" },
646 { INT32, F(hash_free), -1, -1, "Pages on the free list"},
647 { END, -1, -1, -1, NULL }
651 static int display_hash(DB *db UNUSED)
653 #if DB_VERSION_MAJOR == 2
654 printf("Hash statistics not available.\n");
659 #if DB_VERSION_MAJOR > 4 || (DB_VERSION_MAJOR == 4 && DB_VERSION_MINOR >= 3)
660 if(db->stat(db, NULL, &sp, 0))
662 #if DB_VERSION_MAJOR == 3 && DB_VERSION_MINOR <= 2
663 if(db->stat(db, &sp, NULL, 0))
665 if(db->stat(db, &sp, 0))
670 display_heading("Hash Information");
671 display_data(sp, HASH_tab);
677 static int display_db(char *dbfile)
682 #if DB_VERSION_MAJOR == 2
683 if(db_open(dbfile, DB_UNKNOWN, DB_RDONLY, 0, OVDBenv, NULL, &db))
686 if(db_create(&db, OVDBenv, 0))
688 #if DB_VERSION_MAJOR > 4 || (DB_VERSION_MAJOR == 4 && DB_VERSION_MINOR >= 1)
689 if(db->open(db, NULL, dbfile, NULL, DB_UNKNOWN, DB_RDONLY, 0))
691 if(db->open(db, dbfile, NULL, DB_UNKNOWN, DB_RDONLY, 0))
699 ret = display_btree(db);
702 ret = display_hash(db);
712 static int parse_artrange(char *str, ARTNUM *start, ARTNUM *stop)
717 c = strchr(str, '-');
731 if (strlen(str) == (size_t)(c - str + 1)) {
734 return (*start == 0);
738 if(*start == 0 || *stop == 0 || *start > *stop)
744 static void htwrite(char *data, int len)
747 for(i = 0; i < len; i++) {
752 printf("&#%d;", (int)data[i]);
760 int main(int argc, char *argv[])
763 ARTNUM a, start=0, stop=0, low, high;
764 char *data, *disp_db = NULL;
765 int len, c, count, flag, lowi, highi;
766 int getgs=0, getcount=0, getinfo=0, err=0, gotone=0;
767 int disp_lock=0, disp_log=0, disp_mem=0, disp_mem_all=0, disp_txn=0, disp_ver=0;
770 openlog("ovdb_stat", L_OPENLOG_FLAGS | LOG_PID, LOG_INN_PROG);
771 message_program_name = "ovdb_stat";
773 if (!innconf_read(NULL))
776 if(!ovdb_check_user())
777 die("command must be run as user " NEWSUSER);
778 if(!ovdb_getlock(OVDB_LOCK_ADMIN))
779 sysdie("cannot lock database");
780 if(!ovdb_open(OV_READ|OVDB_SERVER))
781 sysdie("cannot open overview; check syslog for OVDB messages");
783 xsignal(SIGINT, sigfunc);
784 xsignal(SIGTERM, sigfunc);
785 xsignal(SIGHUP, sigfunc);
787 while((c = getopt(argc, argv, ":Hgcir:klmMtvd:")) != -1) {
808 if(parse_artrange(optarg, &start, &stop))
843 warn("option -%c requires an argument", optopt);
847 warn("unrecognized option -%c", optopt);
854 } else if(optind == argc && needng) {
855 warn("missing newsgroup argument(s)");
861 ovdb_stat -Hgci [-r artnum] newsgroup [newsgroup ...]\n\
862 -H : output in HTML\n\
863 -g : show groupstats info\n\
864 -c : show groupstats info by counting actual records\n\
865 -i : show additional group info\n\
866 -r artnum-range : retrieve OV records for article number range\n\
868 ovdb_stat -Hklmtv [-d <database>]\n\
869 -H : output in HTML\n\
870 -k : Display lock region statistics\n\
871 -l : Display log region statistics\n\
872 -m : Display global memory cache statistics\n\
873 -M : Display all memory cache statistics\n\
874 -t : Display transaction statistics\n\
875 -v : Display version information\n\
876 -d database : Display statistics of specified database\n");
882 puts("<html><head><title>ovdb_stat</title></head><body><p>");
888 display_mem(disp_mem_all);
896 if(getgs || getcount || getinfo) {
898 puts("<table border=0 cellpadding=1 width=90%>\n<tr bgcolor=#3399aa>");
899 puts("<th rowspan=2>Group");
901 puts("<th colspan=4>Groupstats");
903 puts("<th colspan=3>Counted");
905 puts("<th>Status<th colspan=2>Current<th colspan=2>Pending");
906 puts("<th rowspan=2>Expired<th rowspan=2>Expire PID<tr bgcolor=#3399aa>");
908 puts("<th>Low<th>High<th>Count<th>Flag");
910 puts("<th>Low<th>High<th>Count");
912 puts("<th>Flags<th>GroupID<th>DB<th>GroupID<th>DB");
914 for(o = optind ; o < argc; o++) {
916 printf("<tr><td>%s", argv[o]);
918 if(ovdb_groupstats(argv[o], &lowi, &highi, &count, &flag)) {
920 printf("<td>%d<td>%d<td>%d<td>%c", lowi, highi, count, flag);
922 printf("%s: groupstats: low: %d, high: %d, count: %d, flag: %c\n",
923 argv[o], lowi, highi, count, flag);
927 low = high = count = 0;
928 s = ovdb_opensearch(argv[o], 1, 0xffffffff);
930 while(ovdb_search(s, &a, NULL, NULL, NULL, NULL)) {
931 if(low == 0 || a < low)
943 printf("<td>%ld<td>%ld<td>%d", low, high, count);
945 printf("%s: counted: low: %ld, high: %ld, count: %d\n",
946 argv[o], low, high, count);
953 ret = ovdb_getgroupinfo(argv[o], &gi, false, NULL, 0);
955 warn("%s: ovdb_getgroupinfo error: %s", argv[o],
960 printf("<td>%s%s%s%s",
961 (gi.status & GROUPINFO_DELETED) ? "D ":"",
962 (gi.status & GROUPINFO_EXPIRING) ? "E ":"",
963 (gi.status & GROUPINFO_MOVING) ? "M":"",
964 (gi.status == 0) ? " ":"");
965 printf("<td>%d<td>ov%05d", gi.current_gid, gi.current_db);
966 if(gi.status & GROUPINFO_MOVING)
967 printf("<td>%d<td>ov%05d", gi.new_gid, gi.new_db);
969 printf("<td> <td> ");
971 printf("<td>%s<td>%lu", myctime(&gi.expired),
972 (unsigned long) gi.expiregrouppid);
974 printf("<td> <td> ");
977 printf("%s: flags: %s%s%s%s\n", argv[o],
978 (gi.status & GROUPINFO_DELETED) ? "DELETED ":"",
979 (gi.status & GROUPINFO_EXPIRING) ? "EXPIRING ":"",
980 (gi.status & GROUPINFO_MOVING) ? "MOVING":"",
981 (gi.status == 0) ? "none":"");
983 printf("%s: gid: %d; Stored in: ov%05d\n", argv[o], gi.current_gid, gi.current_db);
984 if(gi.status & GROUPINFO_MOVING)
985 printf("%s: pending gid: %d; pending db: ov%05d\n", argv[o], gi.new_gid, gi.new_db);
987 printf("%s: last expired: %s\n", argv[o], myctime(&gi.expired));
988 printf("%s: by process id: %lu\n", argv[o],
989 (unsigned long) gi.expiregrouppid);
1002 for(o = optind ; o < argc; o++) {
1003 s = ovdb_opensearch(argv[o], start, stop);
1005 while(ovdb_search(s, &a, &data, &len, NULL, NULL)) {
1009 fwrite(data, len, 1, stdout);
1013 ovdb_closesearch(s);
1025 puts("<p></body></html>");
1030 #endif /* USE_BERKELEY_DB */