bt_stat.c
上传用户:romrleung
上传日期:2022-05-23
资源大小:18897k
文件大小:11k
源码类别:

MySQL数据库

开发平台:

Visual C++

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