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