00001
00002
00003
00004
00005
00006
00007
00008 #include "db_config.h"
00009
00010 #ifndef lint
00011 static const char revid[] = "$Id: bt_stat.c,v 11.52 2002/05/30 15:40:27 krinsky Exp $";
00012 #endif
00013
00014 #ifndef NO_SYSTEM_INCLUDES
00015 #include <sys/types.h>
00016
00017 #include <string.h>
00018 #endif
00019
00020 #include "db_int.h"
00021 #include "dbinc/db_page.h"
00022 #include "dbinc/db_shash.h"
00023 #include "dbinc/btree.h"
00024 #include "dbinc/lock.h"
00025 #include "dbinc/log.h"
00026
00027
00028
00029
00030
00031
00032
00033 int
00034 __bam_stat(dbp, spp, flags)
00035 DB *dbp;
00036 void *spp;
00037 u_int32_t flags;
00038 {
00039 BTMETA *meta;
00040 BTREE *t;
00041 BTREE_CURSOR *cp;
00042 DBC *dbc;
00043 DB_BTREE_STAT *sp;
00044 DB_LOCK lock, metalock;
00045 DB_MPOOLFILE *mpf;
00046 PAGE *h;
00047 db_pgno_t pgno;
00048 int ret, t_ret, write_meta;
00049
00050 PANIC_CHECK(dbp->dbenv);
00051 DB_ILLEGAL_BEFORE_OPEN(dbp, "DB->stat");
00052
00053 meta = NULL;
00054 t = dbp->bt_internal;
00055 sp = NULL;
00056 LOCK_INIT(metalock);
00057 LOCK_INIT(lock);
00058 mpf = dbp->mpf;
00059 h = NULL;
00060 ret = 0;
00061 write_meta = 0;
00062
00063
00064 if ((ret = __db_statchk(dbp, flags)) != 0)
00065 return (ret);
00066
00067
00068 if ((ret = dbp->cursor(dbp, NULL, &dbc, 0)) != 0)
00069 return (ret);
00070 cp = (BTREE_CURSOR *)dbc->internal;
00071
00072 DEBUG_LWRITE(dbc, NULL, "bam_stat", NULL, NULL, flags);
00073
00074
00075 if ((ret = __os_umalloc(dbp->dbenv, sizeof(*sp), &sp)) != 0)
00076 goto err;
00077 memset(sp, 0, sizeof(*sp));
00078
00079
00080 pgno = PGNO_BASE_MD;
00081 if ((ret = __db_lget(dbc, 0, pgno, DB_LOCK_READ, 0, &metalock)) != 0)
00082 goto err;
00083 if ((ret = mpf->get(mpf, &pgno, 0, (PAGE **)&meta)) != 0)
00084 goto err;
00085
00086 if (flags == DB_RECORDCOUNT || flags == DB_CACHED_COUNTS)
00087 flags = DB_FAST_STAT;
00088 if (flags == DB_FAST_STAT)
00089 goto meta_only;
00090
00091
00092 for (sp->bt_free = 0, pgno = meta->dbmeta.free; pgno != PGNO_INVALID;) {
00093 ++sp->bt_free;
00094
00095 if ((ret = mpf->get(mpf, &pgno, 0, &h)) != 0)
00096 goto err;
00097
00098 pgno = h->next_pgno;
00099 if ((ret = mpf->put(mpf, h, 0)) != 0)
00100 goto err;
00101 h = NULL;
00102 }
00103
00104
00105 pgno = cp->root;
00106 if ((ret = __db_lget(dbc, 0, pgno, DB_LOCK_READ, 0, &lock)) != 0)
00107 goto err;
00108 if ((ret = mpf->get(mpf, &pgno, 0, &h)) != 0)
00109 goto err;
00110
00111
00112 sp->bt_levels = h->level;
00113
00114
00115 if ((ret = mpf->put(mpf, h, 0)) != 0)
00116 goto err;
00117 h = NULL;
00118 __LPUT(dbc, lock);
00119
00120
00121 if ((ret = __bam_traverse(dbc,
00122 DB_LOCK_READ, cp->root, __bam_stat_callback, sp)) != 0)
00123 goto err;
00124
00125
00126
00127
00128
00129 write_meta = !F_ISSET(dbp, DB_AM_RDONLY);
00130 meta_only:
00131 if (t->bt_meta != PGNO_BASE_MD || write_meta != 0) {
00132 if ((ret = mpf->put(mpf, meta, 0)) != 0)
00133 goto err;
00134 meta = NULL;
00135 __LPUT(dbc, metalock);
00136
00137 if ((ret = __db_lget(dbc,
00138 0, t->bt_meta, write_meta == 0 ?
00139 DB_LOCK_READ : DB_LOCK_WRITE, 0, &metalock)) != 0)
00140 goto err;
00141 if ((ret = mpf->get(mpf, &t->bt_meta, 0, (PAGE **)&meta)) != 0)
00142 goto err;
00143 }
00144 if (flags == DB_FAST_STAT) {
00145 if (dbp->type == DB_RECNO ||
00146 (dbp->type == DB_BTREE && F_ISSET(dbp, DB_AM_RECNUM))) {
00147 if ((ret = __db_lget(dbc, 0,
00148 cp->root, DB_LOCK_READ, 0, &lock)) != 0)
00149 goto err;
00150 if ((ret =
00151 mpf->get(mpf, &cp->root, 0, (PAGE **)&h)) != 0)
00152 goto err;
00153
00154 sp->bt_nkeys = RE_NREC(h);
00155 } else
00156 sp->bt_nkeys = meta->dbmeta.key_count;
00157 sp->bt_ndata = meta->dbmeta.record_count;
00158 }
00159
00160
00161 sp->bt_metaflags = meta->dbmeta.flags;
00162 sp->bt_maxkey = meta->maxkey;
00163 sp->bt_minkey = meta->minkey;
00164 sp->bt_re_len = meta->re_len;
00165 sp->bt_re_pad = meta->re_pad;
00166 sp->bt_pagesize = meta->dbmeta.pagesize;
00167 sp->bt_magic = meta->dbmeta.magic;
00168 sp->bt_version = meta->dbmeta.version;
00169
00170 if (write_meta != 0) {
00171 meta->dbmeta.key_count = sp->bt_nkeys;
00172 meta->dbmeta.record_count = sp->bt_ndata;
00173 }
00174
00175 *(DB_BTREE_STAT **)spp = sp;
00176
00177 err:
00178 __LPUT(dbc, lock);
00179 if (h != NULL && (t_ret = mpf->put(mpf, h, 0)) != 0 && ret == 0)
00180 ret = t_ret;
00181
00182
00183 __LPUT(dbc, metalock);
00184 if (meta != NULL && (t_ret = mpf->put(
00185 mpf, meta, write_meta == 0 ? 0 : DB_MPOOL_DIRTY)) != 0 && ret == 0)
00186 ret = t_ret;
00187
00188 if ((t_ret = dbc->c_close(dbc)) != 0 && ret == 0)
00189 ret = t_ret;
00190
00191 if (ret != 0 && sp != NULL) {
00192 __os_ufree(dbp->dbenv, sp);
00193 *(DB_BTREE_STAT **)spp = NULL;
00194 }
00195
00196 return (ret);
00197 }
00198
00199
00200
00201
00202
00203
00204
00205
00206 int
00207 __bam_traverse(dbc, mode, root_pgno, callback, cookie)
00208 DBC *dbc;
00209 db_lockmode_t mode;
00210 db_pgno_t root_pgno;
00211 int (*callback)__P((DB *, PAGE *, void *, int *));
00212 void *cookie;
00213 {
00214 BINTERNAL *bi;
00215 BKEYDATA *bk;
00216 DB *dbp;
00217 DB_LOCK lock;
00218 DB_MPOOLFILE *mpf;
00219 PAGE *h;
00220 RINTERNAL *ri;
00221 db_indx_t indx;
00222 int already_put, ret, t_ret;
00223
00224 dbp = dbc->dbp;
00225 mpf = dbp->mpf;
00226 already_put = 0;
00227
00228 if ((ret = __db_lget(dbc, 0, root_pgno, mode, 0, &lock)) != 0)
00229 return (ret);
00230 if ((ret = mpf->get(mpf, &root_pgno, 0, &h)) != 0) {
00231 __LPUT(dbc, lock);
00232 return (ret);
00233 }
00234
00235 switch (TYPE(h)) {
00236 case P_IBTREE:
00237 for (indx = 0; indx < NUM_ENT(h); indx += O_INDX) {
00238 bi = GET_BINTERNAL(dbp, h, indx);
00239 if (B_TYPE(bi->type) == B_OVERFLOW &&
00240 (ret = __db_traverse_big(dbp,
00241 ((BOVERFLOW *)bi->data)->pgno,
00242 callback, cookie)) != 0)
00243 goto err;
00244 if ((ret = __bam_traverse(
00245 dbc, mode, bi->pgno, callback, cookie)) != 0)
00246 goto err;
00247 }
00248 break;
00249 case P_IRECNO:
00250 for (indx = 0; indx < NUM_ENT(h); indx += O_INDX) {
00251 ri = GET_RINTERNAL(dbp, h, indx);
00252 if ((ret = __bam_traverse(
00253 dbc, mode, ri->pgno, callback, cookie)) != 0)
00254 goto err;
00255 }
00256 break;
00257 case P_LBTREE:
00258 for (indx = 0; indx < NUM_ENT(h); indx += P_INDX) {
00259 bk = GET_BKEYDATA(dbp, h, indx);
00260 if (B_TYPE(bk->type) == B_OVERFLOW &&
00261 (ret = __db_traverse_big(dbp,
00262 GET_BOVERFLOW(dbp, h, indx)->pgno,
00263 callback, cookie)) != 0)
00264 goto err;
00265 bk = GET_BKEYDATA(dbp, h, indx + O_INDX);
00266 if (B_TYPE(bk->type) == B_DUPLICATE &&
00267 (ret = __bam_traverse(dbc, mode,
00268 GET_BOVERFLOW(dbp, h, indx + O_INDX)->pgno,
00269 callback, cookie)) != 0)
00270 goto err;
00271 if (B_TYPE(bk->type) == B_OVERFLOW &&
00272 (ret = __db_traverse_big(dbp,
00273 GET_BOVERFLOW(dbp, h, indx + O_INDX)->pgno,
00274 callback, cookie)) != 0)
00275 goto err;
00276 }
00277 break;
00278 case P_LDUP:
00279 case P_LRECNO:
00280 for (indx = 0; indx < NUM_ENT(h); indx += O_INDX) {
00281 bk = GET_BKEYDATA(dbp, h, indx);
00282 if (B_TYPE(bk->type) == B_OVERFLOW &&
00283 (ret = __db_traverse_big(dbp,
00284 GET_BOVERFLOW(dbp, h, indx)->pgno,
00285 callback, cookie)) != 0)
00286 goto err;
00287 }
00288 break;
00289 }
00290
00291 ret = callback(dbp, h, cookie, &already_put);
00292
00293 err: if (!already_put && (t_ret = mpf->put(mpf, h, 0)) != 0 && ret != 0)
00294 ret = t_ret;
00295 __LPUT(dbc, lock);
00296
00297 return (ret);
00298 }
00299
00300
00301
00302
00303
00304
00305
00306 int
00307 __bam_stat_callback(dbp, h, cookie, putp)
00308 DB *dbp;
00309 PAGE *h;
00310 void *cookie;
00311 int *putp;
00312 {
00313 DB_BTREE_STAT *sp;
00314 db_indx_t indx, *inp, top;
00315 u_int8_t type;
00316
00317 sp = cookie;
00318 *putp = 0;
00319 top = NUM_ENT(h);
00320 inp = P_INP(dbp, h);
00321
00322 switch (TYPE(h)) {
00323 case P_IBTREE:
00324 case P_IRECNO:
00325 ++sp->bt_int_pg;
00326 sp->bt_int_pgfree += P_FREESPACE(dbp, h);
00327 break;
00328 case P_LBTREE:
00329
00330 for (indx = 0; indx < top; indx += P_INDX) {
00331 if (indx + P_INDX >= top ||
00332 inp[indx] != inp[indx + P_INDX])
00333 ++sp->bt_nkeys;
00334
00335 type = GET_BKEYDATA(dbp, h, indx + O_INDX)->type;
00336 if (!B_DISSET(type) && B_TYPE(type) != B_DUPLICATE)
00337 ++sp->bt_ndata;
00338 }
00339
00340 ++sp->bt_leaf_pg;
00341 sp->bt_leaf_pgfree += P_FREESPACE(dbp, h);
00342 break;
00343 case P_LRECNO:
00344
00345
00346
00347
00348 if (dbp->type == DB_RECNO) {
00349 sp->bt_nkeys += top;
00350
00351
00352
00353
00354
00355 if (F_ISSET(dbp, DB_AM_RENUMBER))
00356 sp->bt_ndata += top;
00357 else
00358 for (indx = 0; indx < top; indx += O_INDX) {
00359 type = GET_BKEYDATA(dbp, h, indx)->type;
00360 if (!B_DISSET(type))
00361 ++sp->bt_ndata;
00362 }
00363
00364 ++sp->bt_leaf_pg;
00365 sp->bt_leaf_pgfree += P_FREESPACE(dbp, h);
00366 } else {
00367 sp->bt_ndata += top;
00368
00369 ++sp->bt_dup_pg;
00370 sp->bt_dup_pgfree += P_FREESPACE(dbp, h);
00371 }
00372 break;
00373 case P_LDUP:
00374
00375 for (indx = 0; indx < top; indx += O_INDX)
00376 if (!B_DISSET(GET_BKEYDATA(dbp, h, indx)->type))
00377 ++sp->bt_ndata;
00378
00379 ++sp->bt_dup_pg;
00380 sp->bt_dup_pgfree += P_FREESPACE(dbp, h);
00381 break;
00382 case P_OVERFLOW:
00383 ++sp->bt_over_pg;
00384 sp->bt_over_pgfree += P_OVFLSPACE(dbp, dbp->pgsize, h);
00385 break;
00386 default:
00387 return (__db_pgfmt(dbp->dbenv, h->pgno));
00388 }
00389 return (0);
00390 }
00391
00392
00393
00394
00395
00396
00397
00398
00399
00400 int
00401 __bam_key_range(dbp, txn, dbt, kp, flags)
00402 DB *dbp;
00403 DB_TXN *txn;
00404 DBT *dbt;
00405 DB_KEY_RANGE *kp;
00406 u_int32_t flags;
00407 {
00408 BTREE_CURSOR *cp;
00409 DBC *dbc;
00410 EPG *sp;
00411 double factor;
00412 int exact, ret, t_ret;
00413
00414 PANIC_CHECK(dbp->dbenv);
00415 DB_ILLEGAL_BEFORE_OPEN(dbp, "DB->key_range");
00416
00417 if (flags != 0)
00418 return (__db_ferr(dbp->dbenv, "DB->key_range", 0));
00419
00420
00421 if ((ret = __db_check_txn(dbp, txn, DB_LOCK_INVALIDID, 1)) != 0)
00422 return (ret);
00423
00424
00425 if ((ret = dbp->cursor(dbp, txn, &dbc, 0)) != 0)
00426 return (ret);
00427
00428 DEBUG_LWRITE(dbc, NULL, "bam_key_range", NULL, NULL, 0);
00429
00430 if ((ret = __bam_search(dbc, PGNO_INVALID,
00431 dbt, S_STK_ONLY, 1, NULL, &exact)) != 0)
00432 goto err;
00433
00434 cp = (BTREE_CURSOR *)dbc->internal;
00435 kp->less = kp->greater = 0.0;
00436
00437 factor = 1.0;
00438
00439 cp->csp->entries /= 2;
00440 cp->csp->indx /= 2;
00441 for (sp = cp->sp; sp <= cp->csp; ++sp) {
00442
00443
00444
00445
00446
00447
00448
00449
00450 if (sp->indx == 0)
00451 kp->greater += factor * (sp->entries - 1)/sp->entries;
00452 else if (sp->indx == sp->entries)
00453 kp->less += factor;
00454 else {
00455 kp->less += factor * sp->indx / sp->entries;
00456 kp->greater += factor *
00457 (sp->entries - sp->indx - 1) / sp->entries;
00458 }
00459 factor *= 1.0/sp->entries;
00460 }
00461
00462
00463
00464
00465
00466
00467 if (exact)
00468 kp->equal = factor;
00469 else {
00470 if (kp->less != 1)
00471 kp->greater += factor;
00472 kp->equal = 0;
00473 }
00474
00475 BT_STK_CLR(cp);
00476
00477 err: if ((t_ret = dbc->c_close(dbc)) != 0 && ret == 0)
00478 ret = t_ret;
00479
00480 return (ret);
00481 }