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