bt_stat.c
上传用户:tsgydb
上传日期:2007-04-14
资源大小:10674k
文件大小:11k
源码类别:

MySQL数据库

开发平台:

Visual C++

  1. /*-
  2.  * See the file LICENSE for redistribution information.
  3.  *
  4.  * Copyright (c) 1996, 1997, 1998, 1999, 2000
  5.  * Sleepycat Software.  All rights reserved.
  6.  */
  7. #include "db_config.h"
  8. #ifndef lint
  9. static const char revid[] = "$Id: bt_stat.c,v 11.29 2000/11/28 21:42:27 bostic Exp $";
  10. #endif /* not lint */
  11. #ifndef NO_SYSTEM_INCLUDES
  12. #include <sys/types.h>
  13. #include <string.h>
  14. #endif
  15. #include "db_int.h"
  16. #include "db_page.h"
  17. #include "db_shash.h"
  18. #include "lock.h"
  19. #include "btree.h"
  20. /*
  21.  * __bam_stat --
  22.  * Gather/print the btree statistics
  23.  *
  24.  * PUBLIC: int __bam_stat __P((DB *, void *, void *(*)(size_t), u_int32_t));
  25.  */
  26. int
  27. __bam_stat(dbp, spp, db_malloc, flags)
  28. DB *dbp;
  29. void *spp;
  30. void *(*db_malloc) __P((size_t));
  31. u_int32_t flags;
  32. {
  33. BTMETA *meta;
  34. BTREE *t;
  35. BTREE_CURSOR *cp;
  36. DBC *dbc;
  37. DB_BTREE_STAT *sp;
  38. DB_LOCK lock, metalock;
  39. PAGE *h;
  40. db_pgno_t pgno;
  41. int ret, t_ret;
  42. PANIC_CHECK(dbp->dbenv);
  43. DB_ILLEGAL_BEFORE_OPEN(dbp, "DB->stat");
  44. meta = NULL;
  45. t = dbp->bt_internal;
  46. sp = NULL;
  47. metalock.off = lock.off = LOCK_INVALID;
  48. h = NULL;
  49. ret = 0;
  50. /* Check for invalid flags. */
  51. if ((ret = __db_statchk(dbp, flags)) != 0)
  52. return (ret);
  53. /* Acquire a cursor. */
  54. if ((ret = dbp->cursor(dbp, NULL, &dbc, 0)) != 0)
  55. return (ret);
  56. cp = (BTREE_CURSOR *)dbc->internal;
  57. DEBUG_LWRITE(dbc, NULL, "bam_stat", NULL, NULL, flags);
  58. /* Allocate and clear the structure. */
  59. if ((ret = __os_malloc(dbp->dbenv, sizeof(*sp), db_malloc, &sp)) != 0)
  60. goto err;
  61. memset(sp, 0, sizeof(*sp));
  62. /* If the app just wants the record count, make it fast. */
  63. if (flags == DB_RECORDCOUNT) {
  64. if ((ret = __db_lget(dbc, 0,
  65.     cp->root, DB_LOCK_READ, 0, &lock)) != 0)
  66. goto err;
  67. if ((ret = memp_fget(dbp->mpf,
  68.     &cp->root, 0, (PAGE **)&h)) != 0)
  69. goto err;
  70. sp->bt_nkeys = RE_NREC(h);
  71. goto done;
  72. }
  73. if (flags == DB_CACHED_COUNTS) {
  74. if ((ret = __db_lget(dbc,
  75.     0, t->bt_meta, DB_LOCK_READ, 0, &lock)) != 0)
  76. goto err;
  77. if ((ret =
  78.     memp_fget(dbp->mpf, &t->bt_meta, 0, (PAGE **)&meta)) != 0)
  79. goto err;
  80. sp->bt_nkeys = meta->dbmeta.key_count;
  81. sp->bt_ndata = meta->dbmeta.record_count;
  82. goto done;
  83. }
  84. /* Get the metadata page for the entire database. */
  85. pgno = PGNO_BASE_MD;
  86. if ((ret = __db_lget(dbc, 0, pgno, DB_LOCK_READ, 0, &metalock)) != 0)
  87. goto err;
  88. if ((ret = memp_fget(dbp->mpf, &pgno, 0, (PAGE **)&meta)) != 0)
  89. goto err;
  90. /* Walk the metadata free list, counting pages. */
  91. for (sp->bt_free = 0, pgno = meta->dbmeta.free; pgno != PGNO_INVALID;) {
  92. ++sp->bt_free;
  93. if ((ret = memp_fget(dbp->mpf, &pgno, 0, &h)) != 0)
  94. goto err;
  95. pgno = h->next_pgno;
  96. if ((ret = memp_fput(dbp->mpf, h, 0)) != 0)
  97. goto err;
  98. h = NULL;
  99. }
  100. /* Get the root page. */
  101. pgno = cp->root;
  102. if ((ret = __db_lget(dbc, 0, pgno, DB_LOCK_READ, 0, &lock)) != 0)
  103. goto err;
  104. if ((ret = memp_fget(dbp->mpf, &pgno, 0, &h)) != 0)
  105. goto err;
  106. /* Get the levels from the root page. */
  107. sp->bt_levels = h->level;
  108. /* Discard the root page. */
  109. if ((ret = memp_fput(dbp->mpf, h, 0)) != 0)
  110. goto err;
  111. h = NULL;
  112. __LPUT(dbc, lock);
  113. /* Walk the tree. */
  114. if ((ret = __bam_traverse(dbc,
  115.     DB_LOCK_READ, cp->root, __bam_stat_callback, sp)) != 0)
  116. goto err;
  117. /*
  118.  * Get the subdatabase metadata page if it's not the same as the
  119.  * one we already have.
  120.  */
  121. if (t->bt_meta != PGNO_BASE_MD || !F_ISSET(dbp, DB_AM_RDONLY)) {
  122. if ((ret = memp_fput(dbp->mpf, meta, 0)) != 0)
  123. goto err;
  124. meta = NULL;
  125. __LPUT(dbc, metalock);
  126. if ((ret = __db_lget(dbc,
  127.     0, t->bt_meta, F_ISSET(dbp, DB_AM_RDONLY) ?
  128.     DB_LOCK_READ : DB_LOCK_WRITE, 0, &metalock)) != 0)
  129. goto err;
  130. if ((ret =
  131.     memp_fget(dbp->mpf, &t->bt_meta, 0, (PAGE **)&meta)) != 0)
  132. goto err;
  133. }
  134. /* Get metadata page statistics. */
  135. sp->bt_metaflags = meta->dbmeta.flags;
  136. sp->bt_maxkey = meta->maxkey;
  137. sp->bt_minkey = meta->minkey;
  138. sp->bt_re_len = meta->re_len;
  139. sp->bt_re_pad = meta->re_pad;
  140. sp->bt_pagesize = meta->dbmeta.pagesize;
  141. sp->bt_magic = meta->dbmeta.magic;
  142. sp->bt_version = meta->dbmeta.version;
  143. if (!F_ISSET(dbp, DB_AM_RDONLY)) {
  144. meta->dbmeta.key_count = sp->bt_nkeys;
  145. meta->dbmeta.record_count = sp->bt_ndata;
  146. }
  147. /* Discard the metadata page. */
  148. if ((ret = memp_fput(dbp->mpf,
  149.     meta, F_ISSET(dbp, DB_AM_RDONLY) ? 0 : DB_MPOOL_DIRTY)) != 0)
  150. goto err;
  151. meta = NULL;
  152. __LPUT(dbc, metalock);
  153. done: *(DB_BTREE_STAT **)spp = sp;
  154. if (0) {
  155. err: if (sp != NULL)
  156. __os_free(sp, sizeof(*sp));
  157. }
  158. if (h != NULL &&
  159.     (t_ret = memp_fput(dbp->mpf, h, 0)) != 0 && ret == 0)
  160. ret = t_ret;
  161. if (meta != NULL &&
  162.     (t_ret = memp_fput(dbp->mpf, meta, 0)) != 0 && ret == 0)
  163. ret = t_ret;
  164. if (lock.off != LOCK_INVALID)
  165. __LPUT(dbc, lock);
  166. if ((t_ret = dbc->c_close(dbc)) != 0 && ret == 0)
  167. ret = t_ret;
  168. return (ret);
  169. }
  170. /*
  171.  * __bam_traverse --
  172.  * Walk a Btree database.
  173.  *
  174.  * PUBLIC: int __bam_traverse __P((DBC *, db_lockmode_t,
  175.  * PUBLIC:     db_pgno_t, int (*)(DB *, PAGE *, void *, int *), void *));
  176.  */
  177. int
  178. __bam_traverse(dbc, mode, root_pgno, callback, cookie)
  179. DBC *dbc;
  180. db_lockmode_t mode;
  181. db_pgno_t root_pgno;
  182. int (*callback)__P((DB *, PAGE *, void *, int *));
  183. void *cookie;
  184. {
  185. BINTERNAL *bi;
  186. BKEYDATA *bk;
  187. DB *dbp;
  188. DB_LOCK lock;
  189. PAGE *h;
  190. RINTERNAL *ri;
  191. db_indx_t indx;
  192. int already_put, ret, t_ret;
  193. dbp = dbc->dbp;
  194. if ((ret = __db_lget(dbc, 0, root_pgno, mode, 0, &lock)) != 0)
  195. return (ret);
  196. if ((ret = memp_fget(dbp->mpf, &root_pgno, 0, &h)) != 0)
  197. goto err;
  198. switch (TYPE(h)) {
  199. case P_IBTREE:
  200. for (indx = 0; indx < NUM_ENT(h); indx += O_INDX) {
  201. bi = GET_BINTERNAL(h, indx);
  202. if (B_TYPE(bi->type) == B_OVERFLOW &&
  203.     (ret = __db_traverse_big(dbp,
  204.     ((BOVERFLOW *)bi->data)->pgno,
  205.     callback, cookie)) != 0)
  206. goto err;
  207. if ((ret = __bam_traverse(
  208.     dbc, mode, bi->pgno, callback, cookie)) != 0)
  209. break;
  210. }
  211. break;
  212. case P_IRECNO:
  213. for (indx = 0; indx < NUM_ENT(h); indx += O_INDX) {
  214. ri = GET_RINTERNAL(h, indx);
  215. if ((ret = __bam_traverse(
  216.     dbc, mode, ri->pgno, callback, cookie)) != 0)
  217. break;
  218. }
  219. break;
  220. case P_LBTREE:
  221. for (indx = 0; indx < NUM_ENT(h); indx += P_INDX) {
  222. bk = GET_BKEYDATA(h, indx);
  223. if (B_TYPE(bk->type) == B_OVERFLOW &&
  224.     (ret = __db_traverse_big(dbp,
  225.     GET_BOVERFLOW(h, indx)->pgno,
  226.     callback, cookie)) != 0)
  227. goto err;
  228. bk = GET_BKEYDATA(h, indx + O_INDX);
  229. if (B_TYPE(bk->type) == B_DUPLICATE &&
  230.     (ret = __bam_traverse(dbc, mode,
  231.     GET_BOVERFLOW(h, indx + O_INDX)->pgno,
  232.     callback, cookie)) != 0)
  233. goto err;
  234. if (B_TYPE(bk->type) == B_OVERFLOW &&
  235.     (ret = __db_traverse_big(dbp,
  236.     GET_BOVERFLOW(h, indx + O_INDX)->pgno,
  237.     callback, cookie)) != 0)
  238. goto err;
  239. }
  240. break;
  241. case P_LDUP:
  242. case P_LRECNO:
  243. for (indx = 0; indx < NUM_ENT(h); indx += O_INDX) {
  244. bk = GET_BKEYDATA(h, indx);
  245. if (B_TYPE(bk->type) == B_OVERFLOW &&
  246.     (ret = __db_traverse_big(dbp,
  247.     GET_BOVERFLOW(h, indx)->pgno,
  248.     callback, cookie)) != 0)
  249. goto err;
  250. }
  251. break;
  252. }
  253. already_put = 0;
  254. if ((ret = callback(dbp, h, cookie, &already_put)) != 0)
  255. goto err;
  256. err: if (!already_put &&
  257.     (t_ret = memp_fput(dbp->mpf, h, 0)) != 0 && ret != 0)
  258. ret = t_ret;
  259. __LPUT(dbc, lock);
  260. return (ret);
  261. }
  262. /*
  263.  * __bam_stat_callback --
  264.  * Statistics callback.
  265.  *
  266.  * PUBLIC: int __bam_stat_callback __P((DB *, PAGE *, void *, int *));
  267.  */
  268. int
  269. __bam_stat_callback(dbp, h, cookie, putp)
  270. DB *dbp;
  271. PAGE *h;
  272. void *cookie;
  273. int *putp;
  274. {
  275. DB_BTREE_STAT *sp;
  276. db_indx_t indx, top;
  277. u_int8_t type;
  278. sp = cookie;
  279. *putp = 0;
  280. top = NUM_ENT(h);
  281. switch (TYPE(h)) {
  282. case P_IBTREE:
  283. case P_IRECNO:
  284. ++sp->bt_int_pg;
  285. sp->bt_int_pgfree += P_FREESPACE(h);
  286. break;
  287. case P_LBTREE:
  288. /* Correct for on-page duplicates and deleted items. */
  289. for (indx = 0; indx < top; indx += P_INDX) {
  290. if (indx + P_INDX >= top ||
  291.     h->inp[indx] != h->inp[indx + P_INDX])
  292. ++sp->bt_nkeys;
  293. type = GET_BKEYDATA(h, indx + O_INDX)->type;
  294. if (!B_DISSET(type) && B_TYPE(type) != B_DUPLICATE)
  295. ++sp->bt_ndata;
  296. }
  297. ++sp->bt_leaf_pg;
  298. sp->bt_leaf_pgfree += P_FREESPACE(h);
  299. break;
  300. case P_LRECNO:
  301. /*
  302.  * If walking a recno tree, then each of these items is a key.
  303.  * Otherwise, we're walking an off-page duplicate set.
  304.  */
  305. if (dbp->type == DB_RECNO) {
  306. sp->bt_nkeys += top;
  307. /*
  308.  * Correct for deleted items in non-renumbering
  309.  * Recno databases.
  310.  */
  311. if (F_ISSET(dbp, DB_RE_RENUMBER))
  312. sp->bt_ndata += top;
  313. else
  314. for (indx = 0; indx < top; indx += O_INDX) {
  315. type = GET_BKEYDATA(h, indx)->type;
  316. if (!B_DISSET(type))
  317. ++sp->bt_ndata;
  318. }
  319. ++sp->bt_leaf_pg;
  320. sp->bt_leaf_pgfree += P_FREESPACE(h);
  321. } else {
  322. sp->bt_ndata += top;
  323. ++sp->bt_dup_pg;
  324. sp->bt_dup_pgfree += P_FREESPACE(h);
  325. }
  326. break;
  327. case P_LDUP:
  328. /* Correct for deleted items. */
  329. for (indx = 0; indx < top; indx += O_INDX)
  330. if (!B_DISSET(GET_BKEYDATA(h, indx)->type))
  331. ++sp->bt_ndata;
  332. ++sp->bt_dup_pg;
  333. sp->bt_dup_pgfree += P_FREESPACE(h);
  334. break;
  335. case P_OVERFLOW:
  336. ++sp->bt_over_pg;
  337. sp->bt_over_pgfree += P_OVFLSPACE(dbp->pgsize, h);
  338. break;
  339. default:
  340. return (__db_pgfmt(dbp, h->pgno));
  341. }
  342. return (0);
  343. }
  344. /*
  345.  * __bam_key_range --
  346.  * Return proportion of keys relative to given key.  The numbers are
  347.  * slightly skewed due to on page duplicates.
  348.  *
  349.  * PUBLIC: int __bam_key_range __P((DB *,
  350.  * PUBLIC:     DB_TXN *, DBT *, DB_KEY_RANGE *, u_int32_t));
  351.  */
  352. int
  353. __bam_key_range(dbp, txn, dbt, kp, flags)
  354. DB *dbp;
  355. DB_TXN *txn;
  356. DBT *dbt;
  357. DB_KEY_RANGE *kp;
  358. u_int32_t flags;
  359. {
  360. BTREE_CURSOR *cp;
  361. DBC *dbc;
  362. EPG *sp;
  363. double factor;
  364. int exact, ret, t_ret;
  365. PANIC_CHECK(dbp->dbenv);
  366. DB_ILLEGAL_BEFORE_OPEN(dbp, "DB->key_range");
  367. if (flags != 0)
  368. return (__db_ferr(dbp->dbenv, "DB->key_range", 0));
  369. /* Acquire a cursor. */
  370. if ((ret = dbp->cursor(dbp, txn, &dbc, 0)) != 0)
  371. return (ret);
  372. DEBUG_LWRITE(dbc, NULL, "bam_key_range", NULL, NULL, 0);
  373. if ((ret = __bam_search(dbc, dbt, S_STK_ONLY, 1, NULL, &exact)) != 0)
  374. goto err;
  375. cp = (BTREE_CURSOR *)dbc->internal;
  376. kp->less = kp->greater = 0.0;
  377. factor = 1.0;
  378. /* Correct the leaf page. */
  379. cp->csp->entries /= 2;
  380. cp->csp->indx /= 2;
  381. for (sp = cp->sp; sp <= cp->csp; ++sp) {
  382. /*
  383.  * At each level we know that pages greater than indx contain
  384.  * keys greater than what we are looking for and those less
  385.  * than indx are less than.  The one pointed to by indx may
  386.  * have some less, some greater or even equal.  If indx is
  387.  * equal to the number of entries, then the key is out of range
  388.  * and everything is less.
  389.  */
  390. if (sp->indx == 0)
  391. kp->greater += factor * (sp->entries - 1)/sp->entries;
  392. else if (sp->indx == sp->entries)
  393. kp->less += factor;
  394. else {
  395. kp->less += factor * sp->indx / sp->entries;
  396. kp->greater += factor *
  397.     (sp->entries - sp->indx - 1) / sp->entries;
  398. }
  399. factor *= 1.0/sp->entries;
  400. }
  401. /*
  402.  * If there was an exact match then assign 1 n'th to the key itself.
  403.  * Otherwise that factor belongs to those greater than the key, unless
  404.  * the key was out of range.
  405.  */
  406. if (exact)
  407. kp->equal = factor;
  408. else {
  409. if (kp->less != 1)
  410. kp->greater += factor;
  411. kp->equal = 0;
  412. }
  413. BT_STK_CLR(cp);
  414. err: if ((t_ret = dbc->c_close(dbc)) != 0 && ret == 0)
  415. ret = t_ret;
  416. return (ret);
  417. }