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

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