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

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: hash_stat.c,v 11.48 2002/08/06 06:11:28 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 "dbinc/db_page.h"
  17. #include "dbinc/btree.h"
  18. #include "dbinc/hash.h"
  19. static int __ham_stat_callback __P((DB *, PAGE *, void *, int *));
  20. /*
  21.  * __ham_stat --
  22.  * Gather/print the hash statistics
  23.  *
  24.  * PUBLIC: int __ham_stat __P((DB *, void *, u_int32_t));
  25.  */
  26. int
  27. __ham_stat(dbp, spp, flags)
  28. DB *dbp;
  29. void *spp;
  30. u_int32_t flags;
  31. {
  32. DBC *dbc;
  33. DB_ENV *dbenv;
  34. DB_HASH_STAT *sp;
  35. DB_MPOOLFILE *mpf;
  36. HASH_CURSOR *hcp;
  37. PAGE *h;
  38. db_pgno_t pgno;
  39. int ret;
  40. dbenv = dbp->dbenv;
  41. PANIC_CHECK(dbenv);
  42. DB_ILLEGAL_BEFORE_OPEN(dbp, "DB->stat");
  43. mpf = dbp->mpf;
  44. sp = NULL;
  45. /* Check for invalid flags. */
  46. if ((ret = __db_statchk(dbp, flags)) != 0)
  47. return (ret);
  48. if ((ret = dbp->cursor(dbp, NULL, &dbc, 0)) != 0)
  49. return (ret);
  50. hcp = (HASH_CURSOR *)dbc->internal;
  51. if ((ret = __ham_get_meta(dbc)) != 0)
  52. goto err;
  53. /* Allocate and clear the structure. */
  54. if ((ret = __os_umalloc(dbenv, sizeof(*sp), &sp)) != 0)
  55. goto err;
  56. memset(sp, 0, sizeof(*sp));
  57. /* Copy the fields that we have. */
  58. sp->hash_nkeys = hcp->hdr->dbmeta.key_count;
  59. sp->hash_ndata = hcp->hdr->dbmeta.record_count;
  60. sp->hash_pagesize = dbp->pgsize;
  61. sp->hash_buckets = hcp->hdr->max_bucket + 1;
  62. sp->hash_magic = hcp->hdr->dbmeta.magic;
  63. sp->hash_version = hcp->hdr->dbmeta.version;
  64. sp->hash_metaflags = hcp->hdr->dbmeta.flags;
  65. sp->hash_ffactor = hcp->hdr->ffactor;
  66. if (flags == DB_FAST_STAT || flags == DB_CACHED_COUNTS)
  67. goto done;
  68. /* Walk the free list, counting pages. */
  69. for (sp->hash_free = 0, pgno = hcp->hdr->dbmeta.free;
  70.     pgno != PGNO_INVALID;) {
  71. ++sp->hash_free;
  72. if ((ret = mpf->get(mpf, &pgno, 0, &h)) != 0)
  73. goto err;
  74. pgno = h->next_pgno;
  75. (void)mpf->put(mpf, h, 0);
  76. }
  77. /* Now traverse the rest of the table. */
  78. sp->hash_nkeys = 0;
  79. sp->hash_ndata = 0;
  80. if ((ret = __ham_traverse(dbc,
  81.     DB_LOCK_READ, __ham_stat_callback, sp, 0)) != 0)
  82. goto err;
  83. if (!F_ISSET(dbp, DB_AM_RDONLY)) {
  84. if ((ret = __ham_dirty_meta(dbc)) != 0)
  85. goto err;
  86. hcp->hdr->dbmeta.key_count = sp->hash_nkeys;
  87. hcp->hdr->dbmeta.record_count = sp->hash_ndata;
  88. }
  89. done:
  90. if ((ret = __ham_release_meta(dbc)) != 0)
  91. goto err;
  92. if ((ret = dbc->c_close(dbc)) != 0)
  93. goto err;
  94. *(DB_HASH_STAT **)spp = sp;
  95. return (0);
  96. err: if (sp != NULL)
  97. __os_ufree(dbenv, sp);
  98. if (hcp->hdr != NULL)
  99. (void)__ham_release_meta(dbc);
  100. (void)dbc->c_close(dbc);
  101. return (ret);
  102. }
  103. /*
  104.  * __ham_traverse
  105.  *  Traverse an entire hash table.  We use the callback so that we
  106.  * can use this both for stat collection and for deallocation.
  107.  *
  108.  * PUBLIC: int __ham_traverse __P((DBC *, db_lockmode_t,
  109.  * PUBLIC:     int (*)(DB *, PAGE *, void *, int *), void *, int));
  110.  */
  111. int
  112. __ham_traverse(dbc, mode, callback, cookie, look_past_max)
  113. DBC *dbc;
  114. db_lockmode_t mode;
  115. int (*callback) __P((DB *, PAGE *, void *, int *));
  116. void *cookie;
  117. int look_past_max;
  118. {
  119. DB *dbp;
  120. DBC *opd;
  121. DB_MPOOLFILE *mpf;
  122. HASH_CURSOR *hcp;
  123. HKEYDATA *hk;
  124. db_pgno_t pgno, opgno;
  125. int did_put, i, ret, t_ret;
  126. u_int32_t bucket, spares_entry;
  127. dbp = dbc->dbp;
  128. opd = NULL;
  129. mpf = dbp->mpf;
  130. hcp = (HASH_CURSOR *)dbc->internal;
  131. ret = 0;
  132. /*
  133.  * In a perfect world, we could simply read each page in the file
  134.  * and look at its page type to tally the information necessary.
  135.  * Unfortunately, the bucket locking that hash tables do to make
  136.  * locking easy, makes this a pain in the butt.  We have to traverse
  137.  * duplicate, overflow and big pages from the bucket so that we
  138.  * don't access anything that isn't properly locked.
  139.  *
  140.  */
  141. for (bucket = 0;; bucket++) {
  142. /*
  143.  * We put the loop exit condition check here, because
  144.  * it made for a really vile extended ?: that made SCO's
  145.  * compiler drop core.
  146.  *
  147.  * If look_past_max is not set, we can stop at max_bucket;
  148.  * if it is set, we need to include pages that are part of
  149.  * the current doubling but beyond the highest bucket we've
  150.  * split into, as well as pages from a "future" doubling
  151.  * that may have been created within an aborted
  152.  * transaction.  To do this, keep looping (and incrementing
  153.  * bucket) until the corresponding spares array entries
  154.  * cease to be defined.
  155.  */
  156. if (look_past_max) {
  157. spares_entry = __db_log2(bucket + 1);
  158. if (spares_entry >= NCACHED ||
  159.     hcp->hdr->spares[spares_entry] == 0)
  160. break;
  161. } else {
  162. if (bucket > hcp->hdr->max_bucket)
  163. break;
  164. }
  165. hcp->bucket = bucket;
  166. hcp->pgno = pgno = BUCKET_TO_PAGE(hcp, bucket);
  167. for (ret = __ham_get_cpage(dbc, mode); ret == 0;
  168.     ret = __ham_next_cpage(dbc, pgno, 0)) {
  169. /*
  170.  * If we are cleaning up pages past the max_bucket,
  171.  * then they may be on the free list and have their
  172.  * next pointers set, but the should be ignored.  In
  173.  * fact, we really ought to just skip anybody who is
  174.  * not a valid page.
  175.  */
  176. if (TYPE(hcp->page) == P_INVALID)
  177. break;
  178. pgno = NEXT_PGNO(hcp->page);
  179. /*
  180.  * Go through each item on the page checking for
  181.  * duplicates (in which case we have to count the
  182.  * duplicate pages) or big key/data items (in which
  183.  * case we have to count those pages).
  184.  */
  185. for (i = 0; i < NUM_ENT(hcp->page); i++) {
  186. hk = (HKEYDATA *)P_ENTRY(dbp, hcp->page, i);
  187. switch (HPAGE_PTYPE(hk)) {
  188. case H_OFFDUP:
  189. memcpy(&opgno, HOFFDUP_PGNO(hk),
  190.     sizeof(db_pgno_t));
  191. if ((ret = __db_c_newopd(dbc,
  192.     opgno, NULL, &opd)) != 0)
  193. return (ret);
  194. if ((ret = __bam_traverse(opd,
  195.     DB_LOCK_READ, opgno,
  196.     callback, cookie))
  197.     != 0)
  198. goto err;
  199. if ((ret = opd->c_close(opd)) != 0)
  200. return (ret);
  201. opd = NULL;
  202. break;
  203. case H_OFFPAGE:
  204. /*
  205.  * We are about to get a big page
  206.  * which will use the same spot that
  207.  * the current page uses, so we need
  208.  * to restore the current page before
  209.  * looking at it again.
  210.  */
  211. memcpy(&opgno, HOFFPAGE_PGNO(hk),
  212.     sizeof(db_pgno_t));
  213. if ((ret = __db_traverse_big(dbp,
  214.     opgno, callback, cookie)) != 0)
  215. goto err;
  216. break;
  217. case H_KEYDATA:
  218. break;
  219. }
  220. }
  221. /* Call the callback on main pages. */
  222. if ((ret = callback(dbp,
  223.     hcp->page, cookie, &did_put)) != 0)
  224. goto err;
  225. if (did_put)
  226. hcp->page = NULL;
  227. if (pgno == PGNO_INVALID)
  228. break;
  229. }
  230. if (ret != 0)
  231. goto err;
  232. if (STD_LOCKING(dbc))
  233. (void)dbp->dbenv->lock_put(dbp->dbenv, &hcp->lock);
  234. if (hcp->page != NULL) {
  235. if ((ret = mpf->put(mpf, hcp->page, 0)) != 0)
  236. return (ret);
  237. hcp->page = NULL;
  238. }
  239. }
  240. err: if (opd != NULL &&
  241.     (t_ret = opd->c_close(opd)) != 0 && ret == 0)
  242. ret = t_ret;
  243. return (ret);
  244. }
  245. static int
  246. __ham_stat_callback(dbp, pagep, cookie, putp)
  247. DB *dbp;
  248. PAGE *pagep;
  249. void *cookie;
  250. int *putp;
  251. {
  252. DB_HASH_STAT *sp;
  253. DB_BTREE_STAT bstat;
  254. db_indx_t indx, len, off, tlen, top;
  255. u_int8_t *hk;
  256. int ret;
  257. *putp = 0;
  258. sp = cookie;
  259. switch (pagep->type) {
  260. case P_INVALID:
  261. /*
  262.  * Hash pages may be wholly zeroed;  this is not a bug.
  263.  * Obviously such pages have no data, so we can just proceed.
  264.  */
  265. break;
  266. case P_HASH:
  267. /*
  268.  * We count the buckets and the overflow pages
  269.  * separately and tally their bytes separately
  270.  * as well.  We need to figure out if this page
  271.  * is a bucket.
  272.  */
  273. if (PREV_PGNO(pagep) == PGNO_INVALID)
  274. sp->hash_bfree += P_FREESPACE(dbp, pagep);
  275. else {
  276. sp->hash_overflows++;
  277. sp->hash_ovfl_free += P_FREESPACE(dbp, pagep);
  278. }
  279. top = NUM_ENT(pagep);
  280. /* Correct for on-page duplicates and deleted items. */
  281. for (indx = 0; indx < top; indx += P_INDX) {
  282. switch (*H_PAIRDATA(dbp, pagep, indx)) {
  283. case H_OFFDUP:
  284. case H_OFFPAGE:
  285. break;
  286. case H_KEYDATA:
  287. sp->hash_ndata++;
  288. break;
  289. case H_DUPLICATE:
  290. tlen = LEN_HDATA(dbp, pagep, 0, indx);
  291. hk = H_PAIRDATA(dbp, pagep, indx);
  292. for (off = 0; off < tlen;
  293.     off += len + 2 * sizeof (db_indx_t)) {
  294. sp->hash_ndata++;
  295. memcpy(&len,
  296.     HKEYDATA_DATA(hk)
  297.     + off, sizeof(db_indx_t));
  298. }
  299. }
  300. }
  301. sp->hash_nkeys += H_NUMPAIRS(pagep);
  302. break;
  303. case P_IBTREE:
  304. case P_IRECNO:
  305. case P_LBTREE:
  306. case P_LRECNO:
  307. case P_LDUP:
  308. /*
  309.  * These are all btree pages; get a correct
  310.  * cookie and call them.  Then add appropriate
  311.  * fields into our stat structure.
  312.  */
  313. memset(&bstat, 0, sizeof(bstat));
  314. bstat.bt_dup_pgfree = 0;
  315. bstat.bt_int_pgfree = 0;
  316. bstat.bt_leaf_pgfree = 0;
  317. bstat.bt_ndata = 0;
  318. if ((ret = __bam_stat_callback(dbp, pagep, &bstat, putp)) != 0)
  319. return (ret);
  320. sp->hash_dup++;
  321. sp->hash_dup_free += bstat.bt_leaf_pgfree +
  322.     bstat.bt_dup_pgfree + bstat.bt_int_pgfree;
  323. sp->hash_ndata += bstat.bt_ndata;
  324. break;
  325. case P_OVERFLOW:
  326. sp->hash_bigpages++;
  327. sp->hash_big_bfree += P_OVFLSPACE(dbp, dbp->pgsize, pagep);
  328. break;
  329. default:
  330. return (__db_pgfmt(dbp->dbenv, pagep->pgno));
  331. }
  332. return (0);
  333. }