00001
00002
00003
00004
00005
00006
00007
00008
00009
00010 #include "db_config.h"
00011
00012 #ifndef NO_SYSTEM_INCLUDES
00013 #include <sys/types.h>
00014
00015 #include <ctype.h>
00016 #include <string.h>
00017 #endif
00018
00019 #include "db_int.h"
00020 #include "dbinc/db_page.h"
00021 #include "dbinc/db_shash.h"
00022 #include "dbinc/btree.h"
00023 #include "dbinc/lock.h"
00024 #include "dbinc/mp.h"
00025
00026 #ifdef HAVE_STATISTICS
00027
00028
00029
00030
00031
00032
00033 int
00034 __bam_stat(dbc, spp, flags)
00035 DBC *dbc;
00036 void *spp;
00037 u_int32_t flags;
00038 {
00039 BTMETA *meta;
00040 BTREE *t;
00041 BTREE_CURSOR *cp;
00042 DB *dbp;
00043 DB_BTREE_STAT *sp;
00044 DB_ENV *dbenv;
00045 DB_LOCK lock, metalock;
00046 DB_MPOOLFILE *mpf;
00047 PAGE *h;
00048 db_pgno_t pgno;
00049 int ret, t_ret, write_meta;
00050
00051 dbp = dbc->dbp;
00052 dbenv = dbp->dbenv;
00053
00054 meta = NULL;
00055 t = dbp->bt_internal;
00056 sp = NULL;
00057 LOCK_INIT(metalock);
00058 LOCK_INIT(lock);
00059 mpf = dbp->mpf;
00060 h = NULL;
00061 ret = write_meta = 0;
00062
00063 cp = (BTREE_CURSOR *)dbc->internal;
00064
00065
00066 if ((ret = __os_umalloc(dbenv, sizeof(*sp), &sp)) != 0)
00067 goto err;
00068 memset(sp, 0, sizeof(*sp));
00069
00070
00071 pgno = PGNO_BASE_MD;
00072 if ((ret = __db_lget(dbc, 0, pgno, DB_LOCK_READ, 0, &metalock)) != 0)
00073 goto err;
00074 if ((ret = __memp_fget(mpf, &pgno, 0, &meta)) != 0)
00075 goto err;
00076
00077 if (flags == DB_RECORDCOUNT || flags == DB_CACHED_COUNTS)
00078 flags = DB_FAST_STAT;
00079 if (flags == DB_FAST_STAT)
00080 goto meta_only;
00081
00082
00083 for (sp->bt_free = 0, pgno = meta->dbmeta.free; pgno != PGNO_INVALID;) {
00084 ++sp->bt_free;
00085
00086 if ((ret = __memp_fget(mpf, &pgno, 0, &h)) != 0)
00087 goto err;
00088
00089 pgno = h->next_pgno;
00090 if ((ret = __memp_fput(mpf, h, 0)) != 0)
00091 goto err;
00092 h = NULL;
00093 }
00094
00095
00096 pgno = cp->root;
00097 if ((ret = __db_lget(dbc, 0, pgno, DB_LOCK_READ, 0, &lock)) != 0)
00098 goto err;
00099 if ((ret = __memp_fget(mpf, &pgno, 0, &h)) != 0)
00100 goto err;
00101
00102
00103 sp->bt_levels = h->level;
00104
00105
00106 ret = __memp_fput(mpf, h, 0);
00107 h = NULL;
00108 if ((t_ret = __LPUT(dbc, lock)) != 0 && ret == 0)
00109 ret = t_ret;
00110 if (ret != 0)
00111 goto err;
00112
00113
00114 if ((ret = __bam_traverse(dbc,
00115 DB_LOCK_READ, cp->root, __bam_stat_callback, sp)) != 0)
00116 goto err;
00117
00118
00119
00120
00121
00122 write_meta = !F_ISSET(dbp, DB_AM_RDONLY);
00123 meta_only:
00124 if (t->bt_meta != PGNO_BASE_MD || write_meta != 0) {
00125 ret = __memp_fput(mpf, meta, 0);
00126 meta = NULL;
00127 if ((t_ret = __LPUT(dbc, metalock)) != 0 && ret == 0)
00128 ret = t_ret;
00129 if (ret != 0)
00130 goto err;
00131
00132 if ((ret = __db_lget(dbc,
00133 0, t->bt_meta, write_meta == 0 ?
00134 DB_LOCK_READ : DB_LOCK_WRITE, 0, &metalock)) != 0)
00135 goto err;
00136 if ((ret = __memp_fget(mpf, &t->bt_meta, 0, &meta)) != 0)
00137 goto err;
00138 }
00139 if (flags == DB_FAST_STAT) {
00140 if (dbp->type == DB_RECNO ||
00141 (dbp->type == DB_BTREE && F_ISSET(dbp, DB_AM_RECNUM))) {
00142 if ((ret = __db_lget(dbc, 0,
00143 cp->root, DB_LOCK_READ, 0, &lock)) != 0)
00144 goto err;
00145 if ((ret = __memp_fget(mpf, &cp->root, 0, &h)) != 0)
00146 goto err;
00147
00148 sp->bt_nkeys = RE_NREC(h);
00149 } else
00150 sp->bt_nkeys = meta->dbmeta.key_count;
00151
00152 sp->bt_ndata = dbp->type == DB_RECNO ?
00153 sp->bt_nkeys : meta->dbmeta.record_count;
00154 }
00155
00156
00157 sp->bt_metaflags = meta->dbmeta.flags;
00158 sp->bt_minkey = meta->minkey;
00159 sp->bt_re_len = meta->re_len;
00160 sp->bt_re_pad = meta->re_pad;
00161 sp->bt_pagesize = meta->dbmeta.pagesize;
00162 sp->bt_magic = meta->dbmeta.magic;
00163 sp->bt_version = meta->dbmeta.version;
00164
00165 if (write_meta != 0) {
00166 meta->dbmeta.key_count = sp->bt_nkeys;
00167 meta->dbmeta.record_count = sp->bt_ndata;
00168 }
00169
00170 *(DB_BTREE_STAT **)spp = sp;
00171
00172 err:
00173 if ((t_ret = __LPUT(dbc, lock)) != 0 && ret == 0)
00174 ret = t_ret;
00175 if (h != NULL && (t_ret = __memp_fput(mpf, h, 0)) != 0 && ret == 0)
00176 ret = t_ret;
00177
00178
00179 if ((t_ret = __LPUT(dbc, metalock)) != 0 && ret == 0)
00180 ret = t_ret;
00181 if (meta != NULL && (t_ret = __memp_fput(
00182 mpf, meta, write_meta == 0 ? 0 : DB_MPOOL_DIRTY)) != 0 && ret == 0)
00183 ret = t_ret;
00184
00185 if (ret != 0 && sp != NULL) {
00186 __os_ufree(dbenv, sp);
00187 *(DB_BTREE_STAT **)spp = NULL;
00188 }
00189
00190 return (ret);
00191 }
00192
00193
00194
00195
00196
00197
00198
00199 int
00200 __bam_stat_print(dbc, flags)
00201 DBC *dbc;
00202 u_int32_t flags;
00203 {
00204 static const FN fn[] = {
00205 { BTM_DUP, "duplicates" },
00206 { BTM_RECNO, "recno" },
00207 { BTM_RECNUM, "record-numbers" },
00208 { BTM_FIXEDLEN, "fixed-length" },
00209 { BTM_RENUMBER, "renumber" },
00210 { BTM_SUBDB, "multiple-databases" },
00211 { BTM_DUPSORT, "sorted duplicates" },
00212 { 0, NULL }
00213 };
00214 DB *dbp;
00215 DB_BTREE_STAT *sp;
00216 DB_ENV *dbenv;
00217 int lorder, ret;
00218 const char *s;
00219
00220 dbp = dbc->dbp;
00221 dbenv = dbp->dbenv;
00222
00223 if ((ret = __bam_stat(dbc, &sp, 0)) != 0)
00224 return (ret);
00225
00226 if (LF_ISSET(DB_STAT_ALL)) {
00227 __db_msg(dbenv, "%s", DB_GLOBAL(db_line));
00228 __db_msg(dbenv, "Default Btree/Recno database information:");
00229 }
00230
00231 __db_msg(dbenv, "%lx\tBtree magic number", (u_long)sp->bt_magic);
00232 __db_msg(dbenv, "%lu\tBtree version number", (u_long)sp->bt_version);
00233
00234 (void)__db_get_lorder(dbp, &lorder);
00235 switch (lorder) {
00236 case 1234:
00237 s = "Little-endian";
00238 break;
00239 case 4321:
00240 s = "Big-endian";
00241 break;
00242 default:
00243 s = "Unrecognized byte order";
00244 break;
00245 }
00246 __db_msg(dbenv, "%s\tByte order", s);
00247 __db_prflags(dbenv, NULL, sp->bt_metaflags, fn, NULL, "\tFlags");
00248 if (dbp->type == DB_BTREE)
00249 __db_dl(dbenv, "Minimum keys per-page", (u_long)sp->bt_minkey);
00250 if (dbp->type == DB_RECNO) {
00251 __db_dl(dbenv,
00252 "Fixed-length record size", (u_long)sp->bt_re_len);
00253 __db_msg(dbenv,
00254 "%#x\tFixed-length record pad", (u_int)sp->bt_re_pad);
00255 }
00256 __db_dl(dbenv,
00257 "Underlying database page size", (u_long)sp->bt_pagesize);
00258 __db_dl(dbenv, "Number of levels in the tree", (u_long)sp->bt_levels);
00259 __db_dl(dbenv, dbp->type == DB_BTREE ?
00260 "Number of unique keys in the tree" :
00261 "Number of records in the tree", (u_long)sp->bt_nkeys);
00262 __db_dl(dbenv,
00263 "Number of data items in the tree", (u_long)sp->bt_ndata);
00264
00265 __db_dl(dbenv,
00266 "Number of tree internal pages", (u_long)sp->bt_int_pg);
00267 __db_dl_pct(dbenv,
00268 "Number of bytes free in tree internal pages",
00269 (u_long)sp->bt_int_pgfree,
00270 DB_PCT_PG(sp->bt_int_pgfree, sp->bt_int_pg, sp->bt_pagesize), "ff");
00271
00272 __db_dl(dbenv,
00273 "Number of tree leaf pages", (u_long)sp->bt_leaf_pg);
00274 __db_dl_pct(dbenv, "Number of bytes free in tree leaf pages",
00275 (u_long)sp->bt_leaf_pgfree, DB_PCT_PG(
00276 sp->bt_leaf_pgfree, sp->bt_leaf_pg, sp->bt_pagesize), "ff");
00277
00278 __db_dl(dbenv,
00279 "Number of tree duplicate pages", (u_long)sp->bt_dup_pg);
00280 __db_dl_pct(dbenv,
00281 "Number of bytes free in tree duplicate pages",
00282 (u_long)sp->bt_dup_pgfree,
00283 DB_PCT_PG(sp->bt_dup_pgfree, sp->bt_dup_pg, sp->bt_pagesize), "ff");
00284
00285 __db_dl(dbenv,
00286 "Number of tree overflow pages", (u_long)sp->bt_over_pg);
00287 __db_dl_pct(dbenv, "Number of bytes free in tree overflow pages",
00288 (u_long)sp->bt_over_pgfree, DB_PCT_PG(
00289 sp->bt_over_pgfree, sp->bt_over_pg, sp->bt_pagesize), "ff");
00290 __db_dl(dbenv, "Number of empty pages", (u_long)sp->bt_empty_pg);
00291
00292 __db_dl(dbenv, "Number of pages on the free list", (u_long)sp->bt_free);
00293
00294 __os_ufree(dbenv, sp);
00295
00296 return (0);
00297 }
00298
00299
00300
00301
00302
00303
00304
00305 int
00306 __bam_stat_callback(dbp, h, cookie, putp)
00307 DB *dbp;
00308 PAGE *h;
00309 void *cookie;
00310 int *putp;
00311 {
00312 DB_BTREE_STAT *sp;
00313 db_indx_t indx, *inp, top;
00314 u_int8_t type;
00315
00316 sp = cookie;
00317 *putp = 0;
00318 top = NUM_ENT(h);
00319 inp = P_INP(dbp, h);
00320
00321 switch (TYPE(h)) {
00322 case P_IBTREE:
00323 case P_IRECNO:
00324 ++sp->bt_int_pg;
00325 sp->bt_int_pgfree += P_FREESPACE(dbp, h);
00326 break;
00327 case P_LBTREE:
00328 if (top == 0)
00329 ++sp->bt_empty_pg;
00330
00331
00332 for (indx = 0; indx < top; indx += P_INDX) {
00333 type = GET_BKEYDATA(dbp, h, indx + O_INDX)->type;
00334
00335 if (B_DISSET(type))
00336 continue;
00337
00338
00339 if (indx + P_INDX >= top ||
00340 inp[indx] != inp[indx + P_INDX])
00341 ++sp->bt_nkeys;
00342
00343
00344 if (B_TYPE(type) != B_DUPLICATE)
00345 ++sp->bt_ndata;
00346 }
00347
00348 ++sp->bt_leaf_pg;
00349 sp->bt_leaf_pgfree += P_FREESPACE(dbp, h);
00350 break;
00351 case P_LRECNO:
00352 if (top == 0)
00353 ++sp->bt_empty_pg;
00354
00355
00356
00357
00358
00359 if (dbp->type == DB_RECNO) {
00360
00361
00362
00363
00364 if (F_ISSET(dbp, DB_AM_RENUMBER)) {
00365 sp->bt_nkeys += top;
00366 sp->bt_ndata += top;
00367 } else
00368 for (indx = 0; indx < top; indx += O_INDX) {
00369 type = GET_BKEYDATA(dbp, h, indx)->type;
00370 if (!B_DISSET(type)) {
00371 ++sp->bt_ndata;
00372 ++sp->bt_nkeys;
00373 }
00374 }
00375
00376 ++sp->bt_leaf_pg;
00377 sp->bt_leaf_pgfree += P_FREESPACE(dbp, h);
00378 } else {
00379 sp->bt_ndata += top;
00380
00381 ++sp->bt_dup_pg;
00382 sp->bt_dup_pgfree += P_FREESPACE(dbp, h);
00383 }
00384 break;
00385 case P_LDUP:
00386 if (top == 0)
00387 ++sp->bt_empty_pg;
00388
00389
00390 for (indx = 0; indx < top; indx += O_INDX)
00391 if (!B_DISSET(GET_BKEYDATA(dbp, h, indx)->type))
00392 ++sp->bt_ndata;
00393
00394 ++sp->bt_dup_pg;
00395 sp->bt_dup_pgfree += P_FREESPACE(dbp, h);
00396 break;
00397 case P_OVERFLOW:
00398 ++sp->bt_over_pg;
00399 sp->bt_over_pgfree += P_OVFLSPACE(dbp, dbp->pgsize, h);
00400 break;
00401 default:
00402 return (__db_pgfmt(dbp->dbenv, h->pgno));
00403 }
00404 return (0);
00405 }
00406
00407
00408
00409
00410
00411
00412
00413 void
00414 __bam_print_cursor(dbc)
00415 DBC *dbc;
00416 {
00417 static const FN fn[] = {
00418 { C_DELETED, "C_DELETED" },
00419 { C_RECNUM, "C_RECNUM" },
00420 { C_RENUMBER, "C_RENUMBER" },
00421 { 0, NULL }
00422 };
00423 DB_ENV *dbenv;
00424 BTREE_CURSOR *cp;
00425
00426 dbenv = dbc->dbp->dbenv;
00427 cp = (BTREE_CURSOR *)dbc->internal;
00428
00429 STAT_ULONG("Overflow size", cp->ovflsize);
00430 if (dbc->dbtype == DB_RECNO)
00431 STAT_ULONG("Recno", cp->recno);
00432 STAT_ULONG("Order", cp->order);
00433 __db_prflags(dbenv, NULL, cp->flags, fn, NULL, "\tInternal Flags");
00434 }
00435
00436 #else
00437
00438 int
00439 __bam_stat(dbc, spp, flags)
00440 DBC *dbc;
00441 void *spp;
00442 u_int32_t flags;
00443 {
00444 COMPQUIET(spp, NULL);
00445 COMPQUIET(flags, 0);
00446
00447 return (__db_stat_not_built(dbc->dbp->dbenv));
00448 }
00449
00450 int
00451 __bam_stat_print(dbc, flags)
00452 DBC *dbc;
00453 u_int32_t flags;
00454 {
00455 COMPQUIET(flags, 0);
00456
00457 return (__db_stat_not_built(dbc->dbp->dbenv));
00458 }
00459 #endif
00460
00461
00462
00463
00464
00465
00466
00467
00468 int
00469 __bam_key_range(dbc, dbt, kp, flags)
00470 DBC *dbc;
00471 DBT *dbt;
00472 DB_KEY_RANGE *kp;
00473 u_int32_t flags;
00474 {
00475 BTREE_CURSOR *cp;
00476 EPG *sp;
00477 double factor;
00478 int exact, ret;
00479
00480 COMPQUIET(flags, 0);
00481
00482 if ((ret = __bam_search(dbc, PGNO_INVALID,
00483 dbt, S_STK_ONLY, 1, NULL, &exact)) != 0)
00484 return (ret);
00485
00486 cp = (BTREE_CURSOR *)dbc->internal;
00487 kp->less = kp->greater = 0.0;
00488
00489 factor = 1.0;
00490
00491 cp->csp->entries /= 2;
00492 cp->csp->indx /= 2;
00493 for (sp = cp->sp; sp <= cp->csp; ++sp) {
00494
00495
00496
00497
00498
00499
00500
00501
00502 if (sp->indx == 0)
00503 kp->greater += factor * (sp->entries - 1)/sp->entries;
00504 else if (sp->indx == sp->entries)
00505 kp->less += factor;
00506 else {
00507 kp->less += factor * sp->indx / sp->entries;
00508 kp->greater += factor *
00509 ((sp->entries - sp->indx) - 1) / sp->entries;
00510 }
00511 factor *= 1.0/sp->entries;
00512 }
00513
00514
00515
00516
00517
00518
00519 if (exact)
00520 kp->equal = factor;
00521 else {
00522 if (kp->less != 1)
00523 kp->greater += factor;
00524 kp->equal = 0;
00525 }
00526
00527 BT_STK_CLR(cp);
00528
00529 return (0);
00530 }
00531
00532
00533
00534
00535
00536
00537
00538
00539 int
00540 __bam_traverse(dbc, mode, root_pgno, callback, cookie)
00541 DBC *dbc;
00542 db_lockmode_t mode;
00543 db_pgno_t root_pgno;
00544 int (*callback)__P((DB *, PAGE *, void *, int *));
00545 void *cookie;
00546 {
00547 BINTERNAL *bi;
00548 BKEYDATA *bk;
00549 DB *dbp;
00550 DB_LOCK lock;
00551 DB_MPOOLFILE *mpf;
00552 PAGE *h;
00553 RINTERNAL *ri;
00554 db_indx_t indx, *inp;
00555 int already_put, ret, t_ret;
00556
00557 dbp = dbc->dbp;
00558 mpf = dbp->mpf;
00559 already_put = 0;
00560
00561 if ((ret = __db_lget(dbc, 0, root_pgno, mode, 0, &lock)) != 0)
00562 return (ret);
00563 if ((ret = __memp_fget(mpf, &root_pgno, 0, &h)) != 0) {
00564 (void)__TLPUT(dbc, lock);
00565 return (ret);
00566 }
00567
00568 switch (TYPE(h)) {
00569 case P_IBTREE:
00570 for (indx = 0; indx < NUM_ENT(h); indx += O_INDX) {
00571 bi = GET_BINTERNAL(dbp, h, indx);
00572 if (B_TYPE(bi->type) == B_OVERFLOW &&
00573 (ret = __db_traverse_big(dbp,
00574 ((BOVERFLOW *)bi->data)->pgno,
00575 callback, cookie)) != 0)
00576 goto err;
00577 if ((ret = __bam_traverse(
00578 dbc, mode, bi->pgno, callback, cookie)) != 0)
00579 goto err;
00580 }
00581 break;
00582 case P_IRECNO:
00583 for (indx = 0; indx < NUM_ENT(h); indx += O_INDX) {
00584 ri = GET_RINTERNAL(dbp, h, indx);
00585 if ((ret = __bam_traverse(
00586 dbc, mode, ri->pgno, callback, cookie)) != 0)
00587 goto err;
00588 }
00589 break;
00590 case P_LBTREE:
00591 inp = P_INP(dbp, h);
00592 for (indx = 0; indx < NUM_ENT(h); indx += P_INDX) {
00593 bk = GET_BKEYDATA(dbp, h, indx);
00594 if (B_TYPE(bk->type) == B_OVERFLOW &&
00595 (indx + P_INDX >= NUM_ENT(h) ||
00596 inp[indx] != inp[indx + P_INDX])) {
00597 if ((ret = __db_traverse_big(dbp,
00598 GET_BOVERFLOW(dbp, h, indx)->pgno,
00599 callback, cookie)) != 0)
00600 goto err;
00601 }
00602 bk = GET_BKEYDATA(dbp, h, indx + O_INDX);
00603 if (B_TYPE(bk->type) == B_DUPLICATE &&
00604 (ret = __bam_traverse(dbc, mode,
00605 GET_BOVERFLOW(dbp, h, indx + O_INDX)->pgno,
00606 callback, cookie)) != 0)
00607 goto err;
00608 if (B_TYPE(bk->type) == B_OVERFLOW &&
00609 (ret = __db_traverse_big(dbp,
00610 GET_BOVERFLOW(dbp, h, indx + O_INDX)->pgno,
00611 callback, cookie)) != 0)
00612 goto err;
00613 }
00614 break;
00615 case P_LDUP:
00616 case P_LRECNO:
00617 for (indx = 0; indx < NUM_ENT(h); indx += O_INDX) {
00618 bk = GET_BKEYDATA(dbp, h, indx);
00619 if (B_TYPE(bk->type) == B_OVERFLOW &&
00620 (ret = __db_traverse_big(dbp,
00621 GET_BOVERFLOW(dbp, h, indx)->pgno,
00622 callback, cookie)) != 0)
00623 goto err;
00624 }
00625 break;
00626 default:
00627 return (__db_pgfmt(dbp->dbenv, h->pgno));
00628 }
00629
00630 ret = callback(dbp, h, cookie, &already_put);
00631
00632 err: if (!already_put && (t_ret = __memp_fput(mpf, h, 0)) != 0 && ret == 0)
00633 ret = t_ret;
00634 if ((t_ret = __TLPUT(dbc, lock)) != 0 && ret == 0)
00635 ret = t_ret;
00636
00637 return (ret);
00638 }