1*0Sstevel@tonic-gate /*- 2*0Sstevel@tonic-gate * See the file LICENSE for redistribution information. 3*0Sstevel@tonic-gate * 4*0Sstevel@tonic-gate * Copyright (c) 1996, 1997, 1998 5*0Sstevel@tonic-gate * Sleepycat Software. All rights reserved. 6*0Sstevel@tonic-gate */ 7*0Sstevel@tonic-gate 8*0Sstevel@tonic-gate #include "config.h" 9*0Sstevel@tonic-gate 10*0Sstevel@tonic-gate #ifndef lint 11*0Sstevel@tonic-gate static const char sccsid[] = "@(#)bt_stat.c 10.27 (Sleepycat) 11/25/98"; 12*0Sstevel@tonic-gate #endif /* not lint */ 13*0Sstevel@tonic-gate 14*0Sstevel@tonic-gate #ifndef NO_SYSTEM_INCLUDES 15*0Sstevel@tonic-gate #include <sys/types.h> 16*0Sstevel@tonic-gate 17*0Sstevel@tonic-gate #include <errno.h> 18*0Sstevel@tonic-gate #include <string.h> 19*0Sstevel@tonic-gate #endif 20*0Sstevel@tonic-gate 21*0Sstevel@tonic-gate #include "db_int.h" 22*0Sstevel@tonic-gate #include "db_page.h" 23*0Sstevel@tonic-gate #include "btree.h" 24*0Sstevel@tonic-gate 25*0Sstevel@tonic-gate /* 26*0Sstevel@tonic-gate * __bam_stat -- 27*0Sstevel@tonic-gate * Gather/print the btree statistics 28*0Sstevel@tonic-gate * 29*0Sstevel@tonic-gate * PUBLIC: int __bam_stat __P((DB *, void *, void *(*)(size_t), u_int32_t)); 30*0Sstevel@tonic-gate */ 31*0Sstevel@tonic-gate int 32*0Sstevel@tonic-gate __bam_stat(dbp, spp, db_malloc, flags) 33*0Sstevel@tonic-gate DB *dbp; 34*0Sstevel@tonic-gate void *spp; 35*0Sstevel@tonic-gate void *(*db_malloc) __P((size_t)); 36*0Sstevel@tonic-gate u_int32_t flags; 37*0Sstevel@tonic-gate { 38*0Sstevel@tonic-gate BTMETA *meta; 39*0Sstevel@tonic-gate BTREE *t; 40*0Sstevel@tonic-gate DBC *dbc; 41*0Sstevel@tonic-gate DB_BTREE_STAT *sp; 42*0Sstevel@tonic-gate DB_LOCK lock; 43*0Sstevel@tonic-gate PAGE *h; 44*0Sstevel@tonic-gate db_pgno_t lastpgno, pgno; 45*0Sstevel@tonic-gate int ret, t_ret; 46*0Sstevel@tonic-gate 47*0Sstevel@tonic-gate DB_PANIC_CHECK(dbp); 48*0Sstevel@tonic-gate 49*0Sstevel@tonic-gate /* Check for invalid flags. */ 50*0Sstevel@tonic-gate if ((ret = __db_statchk(dbp, flags)) != 0) 51*0Sstevel@tonic-gate return (ret); 52*0Sstevel@tonic-gate 53*0Sstevel@tonic-gate if ((ret = dbp->cursor(dbp, NULL, &dbc, 0)) != 0) 54*0Sstevel@tonic-gate return (ret); 55*0Sstevel@tonic-gate 56*0Sstevel@tonic-gate DEBUG_LWRITE(dbc, NULL, "bam_stat", NULL, NULL, flags); 57*0Sstevel@tonic-gate 58*0Sstevel@tonic-gate t = dbp->internal; 59*0Sstevel@tonic-gate 60*0Sstevel@tonic-gate if (spp == NULL) 61*0Sstevel@tonic-gate return (0); 62*0Sstevel@tonic-gate 63*0Sstevel@tonic-gate /* Allocate and clear the structure. */ 64*0Sstevel@tonic-gate if ((ret = __os_malloc(sizeof(*sp), db_malloc, &sp)) != 0) 65*0Sstevel@tonic-gate goto err; 66*0Sstevel@tonic-gate memset(sp, 0, sizeof(*sp)); 67*0Sstevel@tonic-gate 68*0Sstevel@tonic-gate /* If the app just wants the record count, make it fast. */ 69*0Sstevel@tonic-gate if (flags == DB_RECORDCOUNT) { 70*0Sstevel@tonic-gate pgno = PGNO_ROOT; 71*0Sstevel@tonic-gate if ((ret = __bam_lget(dbc, 0, pgno, DB_LOCK_READ, &lock)) != 0) 72*0Sstevel@tonic-gate goto err; 73*0Sstevel@tonic-gate if ((ret = memp_fget(dbp->mpf, &pgno, 0, (PAGE **)&h)) != 0) 74*0Sstevel@tonic-gate goto err; 75*0Sstevel@tonic-gate 76*0Sstevel@tonic-gate sp->bt_nrecs = RE_NREC(h); 77*0Sstevel@tonic-gate 78*0Sstevel@tonic-gate (void)memp_fput(dbp->mpf, h, 0); 79*0Sstevel@tonic-gate (void)__BT_LPUT(dbc, lock); 80*0Sstevel@tonic-gate goto done; 81*0Sstevel@tonic-gate } 82*0Sstevel@tonic-gate 83*0Sstevel@tonic-gate /* Get the meta-data page. */ 84*0Sstevel@tonic-gate pgno = PGNO_METADATA; 85*0Sstevel@tonic-gate if ((ret = __bam_lget(dbc, 0, pgno, DB_LOCK_READ, &lock)) != 0) 86*0Sstevel@tonic-gate goto err; 87*0Sstevel@tonic-gate if ((ret = memp_fget(dbp->mpf, &pgno, 0, (PAGE **)&meta)) != 0) 88*0Sstevel@tonic-gate goto err; 89*0Sstevel@tonic-gate 90*0Sstevel@tonic-gate /* Translate the metadata flags. */ 91*0Sstevel@tonic-gate if (F_ISSET(meta, BTM_DUP)) 92*0Sstevel@tonic-gate sp->bt_flags |= DB_DUP; 93*0Sstevel@tonic-gate if (F_ISSET(meta, BTM_FIXEDLEN)) 94*0Sstevel@tonic-gate sp->bt_flags |= DB_FIXEDLEN; 95*0Sstevel@tonic-gate if (F_ISSET(meta, BTM_RECNUM)) 96*0Sstevel@tonic-gate sp->bt_flags |= DB_RECNUM; 97*0Sstevel@tonic-gate if (F_ISSET(meta, BTM_RENUMBER)) 98*0Sstevel@tonic-gate sp->bt_flags |= DB_RENUMBER; 99*0Sstevel@tonic-gate 100*0Sstevel@tonic-gate /* Get the remaining metadata fields. */ 101*0Sstevel@tonic-gate sp->bt_minkey = meta->minkey; 102*0Sstevel@tonic-gate sp->bt_maxkey = meta->maxkey; 103*0Sstevel@tonic-gate sp->bt_re_len = meta->re_len; 104*0Sstevel@tonic-gate sp->bt_re_pad = meta->re_pad; 105*0Sstevel@tonic-gate sp->bt_magic = meta->magic; 106*0Sstevel@tonic-gate sp->bt_version = meta->version; 107*0Sstevel@tonic-gate 108*0Sstevel@tonic-gate /* Get the page size from the DB. */ 109*0Sstevel@tonic-gate sp->bt_pagesize = dbp->pgsize; 110*0Sstevel@tonic-gate 111*0Sstevel@tonic-gate /* Walk the free list, counting pages. */ 112*0Sstevel@tonic-gate for (sp->bt_free = 0, pgno = meta->free; pgno != PGNO_INVALID;) { 113*0Sstevel@tonic-gate ++sp->bt_free; 114*0Sstevel@tonic-gate 115*0Sstevel@tonic-gate if ((ret = memp_fget(dbp->mpf, &pgno, 0, &h)) != 0) { 116*0Sstevel@tonic-gate (void)memp_fput(dbp->mpf, meta, 0); 117*0Sstevel@tonic-gate (void)__BT_TLPUT(dbc, lock); 118*0Sstevel@tonic-gate goto err; 119*0Sstevel@tonic-gate } 120*0Sstevel@tonic-gate pgno = h->next_pgno; 121*0Sstevel@tonic-gate (void)memp_fput(dbp->mpf, h, 0); 122*0Sstevel@tonic-gate } 123*0Sstevel@tonic-gate 124*0Sstevel@tonic-gate /* Discard the meta-data page. */ 125*0Sstevel@tonic-gate (void)memp_fput(dbp->mpf, meta, 0); 126*0Sstevel@tonic-gate (void)__BT_TLPUT(dbc, lock); 127*0Sstevel@tonic-gate 128*0Sstevel@tonic-gate /* Determine the last page of the database. */ 129*0Sstevel@tonic-gate if ((ret = memp_fget(dbp->mpf, &lastpgno, DB_MPOOL_LAST, &h)) != 0) 130*0Sstevel@tonic-gate goto err; 131*0Sstevel@tonic-gate (void)memp_fput(dbp->mpf, h, 0); 132*0Sstevel@tonic-gate 133*0Sstevel@tonic-gate /* Get the root page. */ 134*0Sstevel@tonic-gate pgno = PGNO_ROOT; 135*0Sstevel@tonic-gate if ((ret = __bam_lget(dbc, 0, PGNO_ROOT, DB_LOCK_READ, &lock)) != 0) 136*0Sstevel@tonic-gate goto err; 137*0Sstevel@tonic-gate if ((ret = memp_fget(dbp->mpf, &pgno, 0, &h)) != 0) { 138*0Sstevel@tonic-gate (void)__BT_LPUT(dbc, lock); 139*0Sstevel@tonic-gate goto err; 140*0Sstevel@tonic-gate } 141*0Sstevel@tonic-gate 142*0Sstevel@tonic-gate /* Get the levels from the root page. */ 143*0Sstevel@tonic-gate sp->bt_levels = h->level; 144*0Sstevel@tonic-gate 145*0Sstevel@tonic-gate /* Walk the page list, counting things. */ 146*0Sstevel@tonic-gate for (;;) { 147*0Sstevel@tonic-gate switch (TYPE(h)) { 148*0Sstevel@tonic-gate case P_INVALID: 149*0Sstevel@tonic-gate break; 150*0Sstevel@tonic-gate case P_IBTREE: 151*0Sstevel@tonic-gate case P_IRECNO: 152*0Sstevel@tonic-gate ++sp->bt_int_pg; 153*0Sstevel@tonic-gate sp->bt_int_pgfree += HOFFSET(h) - LOFFSET(h); 154*0Sstevel@tonic-gate break; 155*0Sstevel@tonic-gate case P_LBTREE: 156*0Sstevel@tonic-gate ++sp->bt_leaf_pg; 157*0Sstevel@tonic-gate sp->bt_leaf_pgfree += HOFFSET(h) - LOFFSET(h); 158*0Sstevel@tonic-gate sp->bt_nrecs += NUM_ENT(h) / P_INDX; 159*0Sstevel@tonic-gate break; 160*0Sstevel@tonic-gate case P_LRECNO: 161*0Sstevel@tonic-gate ++sp->bt_leaf_pg; 162*0Sstevel@tonic-gate sp->bt_leaf_pgfree += HOFFSET(h) - LOFFSET(h); 163*0Sstevel@tonic-gate sp->bt_nrecs += NUM_ENT(h); 164*0Sstevel@tonic-gate break; 165*0Sstevel@tonic-gate case P_DUPLICATE: 166*0Sstevel@tonic-gate ++sp->bt_dup_pg; 167*0Sstevel@tonic-gate /* XXX MARGO: sp->bt_dup_pgfree; */ 168*0Sstevel@tonic-gate break; 169*0Sstevel@tonic-gate case P_OVERFLOW: 170*0Sstevel@tonic-gate ++sp->bt_over_pg; 171*0Sstevel@tonic-gate /* XXX MARGO: sp->bt_over_pgfree; */ 172*0Sstevel@tonic-gate break; 173*0Sstevel@tonic-gate default: 174*0Sstevel@tonic-gate (void)memp_fput(dbp->mpf, h, 0); 175*0Sstevel@tonic-gate (void)__BT_LPUT(dbc, lock); 176*0Sstevel@tonic-gate return (__db_pgfmt(dbp, pgno)); 177*0Sstevel@tonic-gate } 178*0Sstevel@tonic-gate 179*0Sstevel@tonic-gate (void)memp_fput(dbp->mpf, h, 0); 180*0Sstevel@tonic-gate (void)__BT_LPUT(dbc, lock); 181*0Sstevel@tonic-gate 182*0Sstevel@tonic-gate if (++pgno > lastpgno) 183*0Sstevel@tonic-gate break; 184*0Sstevel@tonic-gate if (__bam_lget(dbc, 0, pgno, DB_LOCK_READ, &lock)) 185*0Sstevel@tonic-gate break; 186*0Sstevel@tonic-gate if (memp_fget(dbp->mpf, &pgno, 0, &h) != 0) { 187*0Sstevel@tonic-gate (void)__BT_LPUT(dbc, lock); 188*0Sstevel@tonic-gate break; 189*0Sstevel@tonic-gate } 190*0Sstevel@tonic-gate } 191*0Sstevel@tonic-gate 192*0Sstevel@tonic-gate done: *(DB_BTREE_STAT **)spp = sp; 193*0Sstevel@tonic-gate ret = 0; 194*0Sstevel@tonic-gate 195*0Sstevel@tonic-gate err: if ((t_ret = dbc->c_close(dbc)) != 0 && ret == 0) 196*0Sstevel@tonic-gate ret = t_ret; 197*0Sstevel@tonic-gate return (ret); 198*0Sstevel@tonic-gate } 199