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

MySQL数据库

开发平台:

Visual C++

  1. /*-
  2.  * See the file LICENSE for redistribution information.
  3.  *
  4.  * Copyright (c) 1999, 2000
  5.  * Sleepycat Software.  All rights reserved.
  6.  *
  7.  * $Id: hash_verify.c,v 1.31 2000/11/30 00:58:37 ubell Exp $
  8.  */
  9. #include "db_config.h"
  10. #ifndef lint
  11. static const char revid[] = "$Id: hash_verify.c,v 1.31 2000/11/30 00:58:37 ubell Exp $";
  12. #endif /* not lint */
  13. #ifndef NO_SYSTEM_INCLUDES
  14. #include <sys/types.h>
  15. #include <string.h>
  16. #endif
  17. #include "db_int.h"
  18. #include "db_page.h"
  19. #include "db_verify.h"
  20. #include "btree.h"
  21. #include "hash.h"
  22. static int __ham_dups_unsorted __P((DB *, u_int8_t *, u_int32_t));
  23. static int __ham_vrfy_bucket __P((DB *, VRFY_DBINFO *, HMETA *, u_int32_t,
  24.     u_int32_t));
  25. static int __ham_vrfy_item __P((DB *,
  26.     VRFY_DBINFO *, db_pgno_t, PAGE *, u_int32_t, u_int32_t));
  27. /*
  28.  * __ham_vrfy_meta --
  29.  * Verify the hash-specific part of a metadata page.
  30.  *
  31.  * Note that unlike btree, we don't save things off, because we
  32.  * will need most everything again to verify each page and the
  33.  * amount of state here is significant.
  34.  *
  35.  * PUBLIC: int __ham_vrfy_meta __P((DB *, VRFY_DBINFO *, HMETA *,
  36.  * PUBLIC:     db_pgno_t, u_int32_t));
  37.  */
  38. int
  39. __ham_vrfy_meta(dbp, vdp, m, pgno, flags)
  40. DB *dbp;
  41. VRFY_DBINFO *vdp;
  42. HMETA *m;
  43. db_pgno_t pgno;
  44. u_int32_t flags;
  45. {
  46. HASH *hashp;
  47. VRFY_PAGEINFO *pip;
  48. int i, ret, t_ret, isbad;
  49. u_int32_t pwr, mbucket;
  50. u_int32_t (*hfunc) __P((DB *, const void *, u_int32_t));
  51. if ((ret = __db_vrfy_getpageinfo(vdp, pgno, &pip)) != 0)
  52. return (ret);
  53. isbad = 0;
  54. hashp = dbp->h_internal;
  55. if (hashp != NULL && hashp->h_hash != NULL)
  56. hfunc = hashp->h_hash;
  57. else
  58. hfunc = __ham_func5;
  59. /*
  60.  * If we haven't already checked the common fields in pagezero,
  61.  * check them.
  62.  */
  63. if (!F_ISSET(pip, VRFY_INCOMPLETE) &&
  64.     (ret = __db_vrfy_meta(dbp, vdp, &m->dbmeta, pgno, flags)) != 0) {
  65. if (ret == DB_VERIFY_BAD)
  66. isbad = 1;
  67. else
  68. goto err;
  69. }
  70. /* h_charkey */
  71. if (!LF_ISSET(DB_NOORDERCHK))
  72. if (m->h_charkey != hfunc(dbp, CHARKEY, sizeof(CHARKEY))) {
  73. EPRINT((dbp->dbenv,
  74. "Database has different custom hash function; reverify with DB_NOORDERCHK set"
  75.     ));
  76. /*
  77.  * Return immediately;  this is probably a sign
  78.  * of user error rather than database corruption, so
  79.  * we want to avoid extraneous errors.
  80.  */
  81. isbad = 1;
  82. goto err;
  83. }
  84. /* max_bucket must be less than the last pgno. */
  85. if (m->max_bucket > vdp->last_pgno) {
  86. EPRINT((dbp->dbenv,
  87.     "Impossible max_bucket %lu on meta page %lu",
  88.     m->max_bucket, pgno));
  89. /*
  90.  * Most other fields depend somehow on max_bucket, so
  91.  * we just return--there will be lots of extraneous
  92.  * errors.
  93.  */
  94. isbad = 1;
  95. goto err;
  96. }
  97. /*
  98.  * max_bucket, high_mask and low_mask: high_mask must be one
  99.  * less than the next power of two above max_bucket, and
  100.  * low_mask must be one less than the power of two below it.
  101.  *
  102.  *
  103.  */
  104. pwr = (m->max_bucket == 0) ? 1 : 1 << __db_log2(m->max_bucket + 1);
  105. if (m->high_mask != pwr - 1) {
  106. EPRINT((dbp->dbenv,
  107.     "Incorrect high_mask %lu on page %lu, should be %lu",
  108.     m->high_mask, pgno, pwr - 1));
  109. isbad = 1;
  110. }
  111. pwr >>= 1;
  112. if (m->low_mask != pwr - 1) {
  113. EPRINT((dbp->dbenv,
  114.     "Incorrect low_mask %lu on page %lu, should be %lu",
  115.     m->low_mask, pgno, pwr - 1));
  116. isbad = 1;
  117. }
  118. /* ffactor: no check possible. */
  119. pip->h_ffactor = m->ffactor;
  120. /*
  121.  * nelem: just make sure it's not astronomical for now. This is the
  122.  * same check that hash_upgrade does, since there was a bug in 2.X
  123.  * which could make nelem go "negative".
  124.  */
  125. if (m->nelem > 0x80000000) {
  126. EPRINT((dbp->dbenv,
  127.     "Suspiciously high nelem of %lu on page %lu",
  128.     m->nelem, pgno));
  129. isbad = 1;
  130. pip->h_nelem = 0;
  131. } else
  132. pip->h_nelem = m->nelem;
  133. /* flags */
  134. if (F_ISSET(&m->dbmeta, DB_HASH_DUP))
  135. F_SET(pip, VRFY_HAS_DUPS);
  136. if (F_ISSET(&m->dbmeta, DB_HASH_DUPSORT))
  137. F_SET(pip, VRFY_HAS_DUPSORT);
  138. /* XXX: Why is the DB_HASH_SUBDB flag necessary? */
  139. /* spares array */
  140. for (i = 0; m->spares[i] != 0 && i < NCACHED; i++) {
  141. /*
  142.  * We set mbucket to the maximum bucket that would use a given
  143.  * spares entry;  we want to ensure that it's always less
  144.  * than last_pgno.
  145.  */
  146. mbucket = (1 << i) - 1;
  147. if (BS_TO_PAGE(mbucket, m->spares) > vdp->last_pgno) {
  148. EPRINT((dbp->dbenv,
  149.     "Spares array entry %lu, page %lu is invalid",
  150.     i, pgno));
  151. isbad = 1;
  152. }
  153. }
  154. err: if ((t_ret = __db_vrfy_putpageinfo(vdp, pip)) != 0 && ret == 0)
  155. ret = t_ret;
  156. return ((ret == 0 && isbad == 1) ? DB_VERIFY_BAD : ret);
  157. }
  158. /*
  159.  * __ham_vrfy --
  160.  * Verify hash page.
  161.  *
  162.  * PUBLIC: int __ham_vrfy __P((DB *, VRFY_DBINFO *, PAGE *, db_pgno_t,
  163.  * PUBLIC:     u_int32_t));
  164.  */
  165. int
  166. __ham_vrfy(dbp, vdp, h, pgno, flags)
  167. DB *dbp;
  168. VRFY_DBINFO *vdp;
  169. PAGE *h;
  170. db_pgno_t pgno;
  171. u_int32_t flags;
  172. {
  173. VRFY_PAGEINFO *pip;
  174. u_int32_t ent, himark, inpend;
  175. int isbad, ret, t_ret;
  176. isbad = 0;
  177. if ((ret = __db_vrfy_getpageinfo(vdp, pgno, &pip)) != 0)
  178. return (ret);
  179. /* Sanity check our flags and page type. */
  180. if ((ret = __db_fchk(dbp->dbenv, "__ham_vrfy",
  181.     flags, DB_AGGRESSIVE | DB_NOORDERCHK | DB_SALVAGE)) != 0)
  182. goto err;
  183. if (TYPE(h) != P_HASH) {
  184. TYPE_ERR_PRINT(dbp->dbenv, "__ham_vrfy", pgno, TYPE(h));
  185. DB_ASSERT(0);
  186. ret = EINVAL;
  187. goto err;
  188. }
  189. /* Verify and save off fields common to all PAGEs. */
  190. if ((ret = __db_vrfy_datapage(dbp, vdp, h, pgno, flags)) != 0) {
  191. if (ret == DB_VERIFY_BAD)
  192. isbad = 1;
  193. else
  194. goto err;
  195. }
  196. /*
  197.  * Verify inp[].  Each offset from 0 to NUM_ENT(h) must be lower
  198.  * than the previous one, higher than the current end of the inp array,
  199.  * and lower than the page size.
  200.  *
  201.  * In any case, we return immediately if things are bad, as it would
  202.  * be unsafe to proceed.
  203.  */
  204. for (ent = 0, himark = dbp->pgsize,
  205.     inpend = (u_int8_t *)h->inp - (u_int8_t *)h;
  206.     ent < NUM_ENT(h); ent++)
  207. if (h->inp[ent] >= himark) {
  208. EPRINT((dbp->dbenv,
  209.     "Item %lu on page %lu out of order or nonsensical",
  210.     ent, pgno));
  211. isbad = 1;
  212. goto err;
  213. } else if (inpend >= himark) {
  214. EPRINT((dbp->dbenv,
  215.     "inp array collided with data on page %lu",
  216.     pgno));
  217. isbad = 1;
  218. goto err;
  219. } else {
  220. himark = h->inp[ent];
  221. inpend += sizeof(db_indx_t);
  222. if ((ret = __ham_vrfy_item(
  223.     dbp, vdp, pgno, h, ent, flags)) != 0)
  224. goto err;
  225. }
  226. err: if ((t_ret = __db_vrfy_putpageinfo(vdp, pip)) != 0 && ret == 0)
  227. ret = t_ret;
  228. return (ret == 0 && isbad == 1 ? DB_VERIFY_BAD : ret);
  229. }
  230. /*
  231.  * __ham_vrfy_item --
  232.  * Given a hash page and an offset, sanity-check the item itself,
  233.  * and save off any overflow items or off-page dup children as necessary.
  234.  */
  235. static int
  236. __ham_vrfy_item(dbp, vdp, pgno, h, i, flags)
  237. DB *dbp;
  238. VRFY_DBINFO *vdp;
  239. db_pgno_t pgno;
  240. PAGE *h;
  241. u_int32_t i, flags;
  242. {
  243. HOFFPAGE hop;
  244. HOFFDUP hod;
  245. VRFY_CHILDINFO child;
  246. VRFY_PAGEINFO *pip;
  247. db_indx_t offset, len, dlen, elen;
  248. int ret, t_ret;
  249. u_int8_t *databuf;
  250. if ((ret = __db_vrfy_getpageinfo(vdp, pgno, &pip)) != 0)
  251. return (ret);
  252. switch (HPAGE_TYPE(h, i)) {
  253. case H_KEYDATA:
  254. /* Nothing to do here--everything but the type field is data */
  255. break;
  256. case H_DUPLICATE:
  257. /* Are we a datum or a key?  Better be the former. */
  258. if (i % 2 == 0) {
  259. EPRINT((dbp->dbenv,
  260.     "Hash key stored as duplicate at page %lu item %lu",
  261.     pip->pgno, i));
  262. }
  263. /*
  264.  * Dups are encoded as a series within a single HKEYDATA,
  265.  * in which each dup is surrounded by a copy of its length
  266.  * on either side (so that the series can be walked in either
  267.  * direction.  We loop through this series and make sure
  268.  * each dup is reasonable.
  269.  *
  270.  * Note that at this point, we've verified item i-1, so
  271.  * it's safe to use LEN_HKEYDATA (which looks at inp[i-1]).
  272.  */
  273. len = LEN_HKEYDATA(h, dbp->pgsize, i);
  274. databuf = HKEYDATA_DATA(P_ENTRY(h, i));
  275. for (offset = 0; offset < len; offset += DUP_SIZE(dlen)) {
  276. memcpy(&dlen, databuf + offset, sizeof(db_indx_t));
  277. /* Make sure the length is plausible. */
  278. if (offset + DUP_SIZE(dlen) > len) {
  279. EPRINT((dbp->dbenv,
  280.     "Duplicate item %lu, page %lu has bad length",
  281.     i, pip->pgno));
  282. ret = DB_VERIFY_BAD;
  283. goto err;
  284. }
  285. /*
  286.  * Make sure the second copy of the length is the
  287.  * same as the first.
  288.  */
  289. memcpy(&elen,
  290.     databuf + offset + dlen + sizeof(db_indx_t),
  291.     sizeof(db_indx_t));
  292. if (elen != dlen) {
  293. EPRINT((dbp->dbenv,
  294. "Duplicate item %lu, page %lu has two different lengths",
  295.     i, pip->pgno));
  296. ret = DB_VERIFY_BAD;
  297. goto err;
  298. }
  299. }
  300. F_SET(pip, VRFY_HAS_DUPS);
  301. if (!LF_ISSET(DB_NOORDERCHK) &&
  302.     __ham_dups_unsorted(dbp, databuf, len))
  303. F_SET(pip, VRFY_DUPS_UNSORTED);
  304. break;
  305. case H_OFFPAGE:
  306. /* Offpage item.  Make sure pgno is sane, save off. */
  307. memcpy(&hop, P_ENTRY(h, i), HOFFPAGE_SIZE);
  308. if (!IS_VALID_PGNO(hop.pgno) || hop.pgno == pip->pgno ||
  309.     hop.pgno == PGNO_INVALID) {
  310. EPRINT((dbp->dbenv,
  311.     "Offpage item %lu, page %lu has bad page number",
  312.     i, pip->pgno));
  313. ret = DB_VERIFY_BAD;
  314. goto err;
  315. }
  316. memset(&child, 0, sizeof(VRFY_CHILDINFO));
  317. child.pgno = hop.pgno;
  318. child.type = V_OVERFLOW;
  319. child.tlen = hop.tlen; /* This will get checked later. */
  320. if ((ret = __db_vrfy_childput(vdp, pip->pgno, &child)) != 0)
  321. goto err;
  322. break;
  323. case H_OFFDUP:
  324. /* Offpage duplicate item.  Same drill. */
  325. memcpy(&hod, P_ENTRY(h, i), HOFFDUP_SIZE);
  326. if (!IS_VALID_PGNO(hod.pgno) || hod.pgno == pip->pgno ||
  327.     hod.pgno == PGNO_INVALID) {
  328. EPRINT((dbp->dbenv,
  329.     "Offpage item %lu, page %lu has bad page number",
  330.     i, pip->pgno));
  331. ret = DB_VERIFY_BAD;
  332. goto err;
  333. }
  334. memset(&child, 0, sizeof(VRFY_CHILDINFO));
  335. child.pgno = hod.pgno;
  336. child.type = V_DUPLICATE;
  337. if ((ret = __db_vrfy_childput(vdp, pip->pgno, &child)) != 0)
  338. goto err;
  339. F_SET(pip, VRFY_HAS_DUPS);
  340. break;
  341. default:
  342. EPRINT((dbp->dbenv,
  343.     "Item %i, page %lu has bad type", i, pip->pgno));
  344. ret = DB_VERIFY_BAD;
  345. break;
  346. }
  347. err: if ((t_ret = __db_vrfy_putpageinfo(vdp, pip)) != 0 && ret == 0)
  348. ret = t_ret;
  349. return (ret);
  350. }
  351. /*
  352.  * __ham_vrfy_structure --
  353.  * Verify the structure of a hash database.
  354.  *
  355.  * PUBLIC: int __ham_vrfy_structure __P((DB *, VRFY_DBINFO *, db_pgno_t,
  356.  * PUBLIC:     u_int32_t));
  357.  */
  358. int
  359. __ham_vrfy_structure(dbp, vdp, meta_pgno, flags)
  360. DB *dbp;
  361. VRFY_DBINFO *vdp;
  362. db_pgno_t meta_pgno;
  363. u_int32_t flags;
  364. {
  365. DB *pgset;
  366. HMETA *m;
  367. PAGE *h;
  368. VRFY_PAGEINFO *pip;
  369. int isbad, p, ret, t_ret;
  370. db_pgno_t pgno;
  371. u_int32_t bucket;
  372. ret = isbad = 0;
  373. h = NULL;
  374. pgset = vdp->pgset;
  375. if ((ret = __db_vrfy_pgset_get(pgset, meta_pgno, &p)) != 0)
  376. return (ret);
  377. if (p != 0) {
  378. EPRINT((dbp->dbenv,
  379.     "Hash meta page %lu referenced twice", meta_pgno));
  380. return (DB_VERIFY_BAD);
  381. }
  382. if ((ret = __db_vrfy_pgset_inc(pgset, meta_pgno)) != 0)
  383. return (ret);
  384. /* Get the meta page;  we'll need it frequently. */
  385. if ((ret = memp_fget(dbp->mpf, &meta_pgno, 0, &m)) != 0)
  386. return (ret);
  387. /* Loop through bucket by bucket. */
  388. for (bucket = 0; bucket <= m->max_bucket; bucket++)
  389. if ((ret =
  390.     __ham_vrfy_bucket(dbp, vdp, m, bucket, flags)) != 0) {
  391. if (ret == DB_VERIFY_BAD)
  392. isbad = 1;
  393. else
  394. goto err;
  395.     }
  396. /*
  397.  * There may be unused hash pages corresponding to buckets
  398.  * that have been allocated but not yet used.  These may be
  399.  * part of the current doubling above max_bucket, or they may
  400.  * correspond to buckets that were used in a transaction
  401.  * that then aborted.
  402.  *
  403.  * Loop through them, as far as the spares array defines them,
  404.  * and make sure they're all empty.
  405.  *
  406.  * Note that this should be safe, since we've already verified
  407.  * that the spares array is sane.
  408.  */
  409. for (bucket = m->max_bucket + 1;
  410.     m->spares[__db_log2(bucket + 1)] != 0; bucket++) {
  411. pgno = BS_TO_PAGE(bucket, m->spares);
  412. if ((ret = __db_vrfy_getpageinfo(vdp, pgno, &pip)) != 0)
  413. goto err;
  414. /* It's okay if these pages are totally zeroed;  unmark it. */
  415. F_CLR(pip, VRFY_IS_ALLZEROES);
  416. if (pip->type != P_HASH) {
  417. EPRINT((dbp->dbenv,
  418.     "Hash bucket %lu maps to non-hash page %lu",
  419.     bucket, pgno));
  420. isbad = 1;
  421. } else if (pip->entries != 0) {
  422. EPRINT((dbp->dbenv,
  423.     "Non-empty page %lu in unused hash bucket %lu",
  424.     pgno, bucket));
  425. isbad = 1;
  426. } else {
  427. if ((ret = __db_vrfy_pgset_get(pgset, pgno, &p)) != 0)
  428. goto err;
  429. if (p != 0) {
  430. EPRINT((dbp->dbenv,
  431.     "Hash page %lu above max_bucket referenced",
  432.     pgno));
  433. isbad = 1;
  434. } else {
  435. if ((ret =
  436.     __db_vrfy_pgset_inc(pgset, pgno)) != 0)
  437. goto err;
  438. if ((ret =
  439.     __db_vrfy_putpageinfo(vdp, pip)) != 0)
  440. goto err;
  441. continue;
  442. }
  443. }
  444. /* If we got here, it's an error. */
  445. (void)__db_vrfy_putpageinfo(vdp, pip);
  446. goto err;
  447. }
  448. err: if ((t_ret = memp_fput(dbp->mpf, m, 0)) != 0)
  449. return (t_ret);
  450. if (h != NULL && (t_ret = memp_fput(dbp->mpf, h, 0)) != 0)
  451. return (t_ret);
  452. return ((isbad == 1 && ret == 0) ? DB_VERIFY_BAD: ret);
  453. }
  454. /*
  455.  * __ham_vrfy_bucket --
  456.  * Verify a given bucket.
  457.  */
  458. static int
  459. __ham_vrfy_bucket(dbp, vdp, m, bucket, flags)
  460. DB *dbp;
  461. VRFY_DBINFO *vdp;
  462. HMETA *m;
  463. u_int32_t bucket, flags;
  464. {
  465. HASH *hashp;
  466. VRFY_CHILDINFO *child;
  467. VRFY_PAGEINFO *mip, *pip;
  468. int ret, t_ret, isbad, p;
  469. db_pgno_t pgno, next_pgno;
  470. DBC *cc;
  471. u_int32_t (*hfunc) __P((DB *, const void *, u_int32_t));
  472. isbad = 0;
  473. pip = NULL;
  474. cc = NULL;
  475. hashp = dbp->h_internal;
  476. if (hashp != NULL && hashp->h_hash != NULL)
  477. hfunc = hashp->h_hash;
  478. else
  479. hfunc = __ham_func5;
  480. if ((ret = __db_vrfy_getpageinfo(vdp, PGNO(m), &mip)) != 0)
  481. return (ret);
  482. /* Calculate the first pgno for this bucket. */
  483. pgno = BS_TO_PAGE(bucket, m->spares);
  484. if ((ret = __db_vrfy_getpageinfo(vdp, pgno, &pip)) != 0)
  485. goto err;
  486. /* Make sure we got a plausible page number. */
  487. if (pgno > vdp->last_pgno || pip->type != P_HASH) {
  488. EPRINT((dbp->dbenv, "Bucket %lu has impossible first page %lu",
  489.     bucket, pgno));
  490. /* Unsafe to continue. */
  491. isbad = 1;
  492. goto err;
  493. }
  494. if (pip->prev_pgno != PGNO_INVALID) {
  495. EPRINT((dbp->dbenv,
  496.     "First hash page %lu in bucket %lu has a prev_pgno", pgno));
  497. isbad = 1;
  498. }
  499. /*
  500.  * Set flags for dups and sorted dups.
  501.  */
  502. flags |= F_ISSET(mip, VRFY_HAS_DUPS) ? ST_DUPOK : 0;
  503. flags |= F_ISSET(mip, VRFY_HAS_DUPSORT) ? ST_DUPSORT : 0;
  504. /* Loop until we find a fatal bug, or until we run out of pages. */
  505. for (;;) {
  506. /* Provide feedback on our progress to the application. */
  507. if (!LF_ISSET(DB_SALVAGE))
  508. __db_vrfy_struct_feedback(dbp, vdp);
  509. if ((ret = __db_vrfy_pgset_get(vdp->pgset, pgno, &p)) != 0)
  510. goto err;
  511. if (p != 0) {
  512. EPRINT((dbp->dbenv,
  513.     "Hash page %lu referenced twice", pgno));
  514. isbad = 1;
  515. /* Unsafe to continue. */
  516. goto err;
  517. } else if ((ret = __db_vrfy_pgset_inc(vdp->pgset, pgno)) != 0)
  518. goto err;
  519. /*
  520.  * Hash pages that nothing has ever hashed to may never
  521.  * have actually come into existence, and may appear to be
  522.  * entirely zeroed.  This is acceptable, and since there's
  523.  * no real way for us to know whether this has actually
  524.  * occurred, we clear the "wholly zeroed" flag on every
  525.  * hash page.  A wholly zeroed page, by nature, will appear
  526.  * to have no flags set and zero entries, so should
  527.  * otherwise verify correctly.
  528.  */
  529. F_CLR(pip, VRFY_IS_ALLZEROES);
  530. /* If we have dups, our meta page had better know about it. */
  531. if (F_ISSET(pip, VRFY_HAS_DUPS)
  532.     && !F_ISSET(mip, VRFY_HAS_DUPS)) {
  533. EPRINT((dbp->dbenv,
  534.     "Duplicates present in non-duplicate database, page %lu",
  535.     pgno));
  536. isbad = 1;
  537. }
  538. /*
  539.  * If the database has sorted dups, this page had better
  540.  * not have unsorted ones.
  541.  */
  542. if (F_ISSET(mip, VRFY_HAS_DUPSORT) &&
  543.     F_ISSET(pip, VRFY_DUPS_UNSORTED)) {
  544. EPRINT((dbp->dbenv,
  545.     "Unsorted dups in sorted-dup database, page %lu",
  546.     pgno));
  547. isbad = 1;
  548. }
  549. /* Walk overflow chains and offpage dup trees. */
  550. if ((ret = __db_vrfy_childcursor(vdp, &cc)) != 0)
  551. goto err;
  552. for (ret = __db_vrfy_ccset(cc, pip->pgno, &child); ret == 0;
  553.     ret = __db_vrfy_ccnext(cc, &child))
  554. if (child->type == V_OVERFLOW) {
  555. if ((ret = __db_vrfy_ovfl_structure(dbp, vdp,
  556.     child->pgno, child->tlen, flags)) != 0) {
  557. if (ret == DB_VERIFY_BAD)
  558. isbad = 1;
  559. else
  560. goto err;
  561. }
  562. } else if (child->type == V_DUPLICATE) {
  563. if ((ret = __db_vrfy_duptype(dbp,
  564.     vdp, child->pgno, flags)) != 0) {
  565. isbad = 1;
  566. continue;
  567. }
  568. if ((ret = __bam_vrfy_subtree(dbp, vdp,
  569.     child->pgno, NULL, NULL,
  570.     flags | ST_RECNUM | ST_DUPSET, NULL,
  571.     NULL, NULL)) != 0) {
  572. if (ret == DB_VERIFY_BAD)
  573. isbad = 1;
  574. else
  575. goto err;
  576. }
  577. }
  578. if ((ret = __db_vrfy_ccclose(cc)) != 0)
  579. goto err;
  580. cc = NULL;
  581. /* If it's safe to check that things hash properly, do so. */
  582. if (isbad == 0 && !LF_ISSET(DB_NOORDERCHK) &&
  583.     (ret = __ham_vrfy_hashing(dbp, pip->entries,
  584.     m, bucket, pgno, flags, hfunc)) != 0) {
  585. if (ret == DB_VERIFY_BAD)
  586. isbad = 1;
  587. else
  588. goto err;
  589. }
  590. next_pgno = pip->next_pgno;
  591. ret = __db_vrfy_putpageinfo(vdp, pip);
  592. pip = NULL;
  593. if (ret != 0)
  594. goto err;
  595. if (next_pgno == PGNO_INVALID)
  596. break; /* End of the bucket. */
  597. /* We already checked this, but just in case... */
  598. if (!IS_VALID_PGNO(next_pgno)) {
  599. DB_ASSERT(0);
  600. EPRINT((dbp->dbenv,
  601.     "Hash page %lu has bad next_pgno", pgno));
  602. isbad = 1;
  603. goto err;
  604. }
  605. if ((ret = __db_vrfy_getpageinfo(vdp, next_pgno, &pip)) != 0)
  606. goto err;
  607. if (pip->prev_pgno != pgno) {
  608. EPRINT((dbp->dbenv, "Hash page %lu has bad prev_pgno",
  609.     next_pgno));
  610. isbad = 1;
  611. }
  612. pgno = next_pgno;
  613. }
  614. err: if (cc != NULL && ((t_ret = __db_vrfy_ccclose(cc)) != 0) && ret == 0)
  615. ret = t_ret;
  616. if (mip != NULL && ((t_ret = __db_vrfy_putpageinfo(vdp, mip)) != 0) &&
  617.     ret == 0)
  618. ret = t_ret;
  619. if (pip != NULL && ((t_ret = __db_vrfy_putpageinfo(vdp, pip)) != 0) &&
  620.     ret == 0)
  621. ret = t_ret;
  622. return ((ret == 0 && isbad == 1) ? DB_VERIFY_BAD : ret);
  623. }
  624. /*
  625.  * __ham_vrfy_hashing --
  626.  * Verify that all items on a given hash page hash correctly.
  627.  *
  628.  * PUBLIC: int __ham_vrfy_hashing __P((DB *,
  629.  * PUBLIC:     u_int32_t, HMETA *, u_int32_t, db_pgno_t, u_int32_t,
  630.  * PUBLIC:     u_int32_t (*) __P((DB *, const void *, u_int32_t))));
  631.  */
  632. int
  633. __ham_vrfy_hashing(dbp, nentries, m, thisbucket, pgno, flags, hfunc)
  634. DB *dbp;
  635. u_int32_t nentries;
  636. HMETA *m;
  637. u_int32_t thisbucket;
  638. db_pgno_t pgno;
  639. u_int32_t flags;
  640. u_int32_t (*hfunc) __P((DB *, const void *, u_int32_t));
  641. {
  642. DBT dbt;
  643. PAGE *h;
  644. db_indx_t i;
  645. int ret, t_ret, isbad;
  646. u_int32_t hval, bucket;
  647. ret = isbad = 0;
  648. memset(&dbt, 0, sizeof(DBT));
  649. F_SET(&dbt, DB_DBT_REALLOC);
  650. if ((ret = memp_fget(dbp->mpf, &pgno, 0, &h)) != 0)
  651. return (ret);
  652. for (i = 0; i < nentries; i += 2) {
  653. /*
  654.  * We've already verified the page integrity and that of any
  655.  * overflow chains linked off it;  it is therefore safe to use
  656.  * __db_ret.  It's also not all that much slower, since we have
  657.  * to copy every hash item to deal with alignment anyway;  we
  658.  * can tweak this a bit if this proves to be a bottleneck,
  659.  * but for now, take the easy route.
  660.  */
  661. if ((ret = __db_ret(dbp, h, i, &dbt, NULL, NULL)) != 0)
  662. goto err;
  663. hval = hfunc(dbp, dbt.data, dbt.size);
  664. bucket = hval & m->high_mask;
  665. if (bucket > m->max_bucket)
  666. bucket = bucket & m->low_mask;
  667. if (bucket != thisbucket) {
  668. EPRINT((dbp->dbenv,
  669.     "Item %lu on page %lu hashes incorrectly",
  670.     i, pgno));
  671. isbad = 1;
  672. }
  673. }
  674. err: if (dbt.data != NULL)
  675. __os_free(dbt.data, 0);
  676. if ((t_ret = memp_fput(dbp->mpf, h, 0)) != 0)
  677. return (t_ret);
  678. return ((ret == 0 && isbad == 1) ? DB_VERIFY_BAD : ret);
  679. }
  680. /*
  681.  * __ham_salvage --
  682.  * Safely dump out anything that looks like a key on an alleged
  683.  * hash page.
  684.  *
  685.  * PUBLIC: int __ham_salvage __P((DB *, VRFY_DBINFO *, db_pgno_t, PAGE *,
  686.  * PUBLIC:     void *, int (*)(void *, const void *), u_int32_t));
  687.  */
  688. int
  689. __ham_salvage(dbp, vdp, pgno, h, handle, callback, flags)
  690. DB *dbp;
  691. VRFY_DBINFO *vdp;
  692. db_pgno_t pgno;
  693. PAGE *h;
  694. void *handle;
  695. int (*callback) __P((void *, const void *));
  696. u_int32_t flags;
  697. {
  698. DBT dbt, unkdbt;
  699. db_pgno_t dpgno;
  700. int ret, err_ret, t_ret;
  701. u_int32_t himark, tlen;
  702. u_int8_t *hk;
  703. void *buf;
  704. u_int32_t dlen, len, i;
  705. memset(&dbt, 0, sizeof(DBT));
  706. dbt.flags = DB_DBT_REALLOC;
  707. memset(&unkdbt, 0, sizeof(DBT));
  708. unkdbt.size = strlen("UNKNOWN") + 1;
  709. unkdbt.data = "UNKNOWN";
  710. err_ret = 0;
  711. /*
  712.  * Allocate a buffer for overflow items.  Start at one page;
  713.  * __db_safe_goff will realloc as needed.
  714.  */
  715. if ((ret = __os_malloc(dbp->dbenv, dbp->pgsize, NULL, &buf)) != 0)
  716. return (ret);
  717. himark = dbp->pgsize;
  718. for (i = 0;; i++) {
  719. /* If we're not aggressive, break when we hit NUM_ENT(h). */
  720. if (!LF_ISSET(DB_AGGRESSIVE) && i >= NUM_ENT(h))
  721. break;
  722. /* Verify the current item. */
  723. ret = __db_vrfy_inpitem(dbp,
  724.     h, pgno, i, 0, flags, &himark, NULL);
  725. /* If this returned a fatality, it's time to break. */
  726. if (ret == DB_VERIFY_FATAL)
  727. break;
  728. if (ret == 0) {
  729. hk = P_ENTRY(h, i);
  730. len = LEN_HKEYDATA(h, dbp->pgsize, i);
  731. if ((u_int32_t)(hk + len - (u_int8_t *)h) >
  732.     dbp->pgsize) {
  733. /*
  734.  * Item is unsafely large;  either continue
  735.  * or set it to the whole page, depending on
  736.  * aggressiveness.
  737.  */
  738. if (!LF_ISSET(DB_AGGRESSIVE))
  739. continue;
  740. len = dbp->pgsize -
  741.     (u_int32_t)(hk - (u_int8_t *)h);
  742. err_ret = DB_VERIFY_BAD;
  743. }
  744. switch (HPAGE_PTYPE(hk)) {
  745. default:
  746. if (!LF_ISSET(DB_AGGRESSIVE))
  747. break;
  748. err_ret = DB_VERIFY_BAD;
  749. /* FALLTHROUGH */
  750. case H_KEYDATA:
  751. keydata: memcpy(buf, HKEYDATA_DATA(hk), len);
  752. dbt.size = len;
  753. dbt.data = buf;
  754. if ((ret = __db_prdbt(&dbt,
  755.     0, " ", handle, callback, 0, NULL)) != 0)
  756. err_ret = ret;
  757. break;
  758. case H_OFFPAGE:
  759. if (len < HOFFPAGE_SIZE) {
  760. err_ret = DB_VERIFY_BAD;
  761. continue;
  762. }
  763. memcpy(&dpgno,
  764.     HOFFPAGE_PGNO(hk), sizeof(dpgno));
  765. if ((ret = __db_safe_goff(dbp, vdp,
  766.     dpgno, &dbt, &buf, flags)) != 0) {
  767. err_ret = ret;
  768. (void)__db_prdbt(&unkdbt, 0, " ",
  769.     handle, callback, 0, NULL);
  770. break;
  771. }
  772. if ((ret = __db_prdbt(&dbt,
  773.     0, " ", handle, callback, 0, NULL)) != 0)
  774. err_ret = ret;
  775. break;
  776. case H_OFFDUP:
  777. if (len < HOFFPAGE_SIZE) {
  778. err_ret = DB_VERIFY_BAD;
  779. continue;
  780. }
  781. memcpy(&dpgno,
  782.     HOFFPAGE_PGNO(hk), sizeof(dpgno));
  783. /* UNKNOWN iff pgno is bad or we're a key. */
  784. if (!IS_VALID_PGNO(dpgno) || (i % 2 == 0)) {
  785. if ((ret = __db_prdbt(&unkdbt, 0, " ",
  786.     handle, callback, 0, NULL)) != 0)
  787. err_ret = ret;
  788. } else if ((ret = __db_salvage_duptree(dbp,
  789.     vdp, dpgno, &dbt, handle, callback,
  790.     flags | SA_SKIPFIRSTKEY)) != 0)
  791. err_ret = ret;
  792. break;
  793. case H_DUPLICATE:
  794. /*
  795.  * We're a key;  printing dups will seriously
  796.  * foul the output.  If we're being aggressive,
  797.  * pretend this is a key and let the app.
  798.  * programmer sort out the mess.
  799.  */
  800. if (i % 2 == 0) {
  801. err_ret = ret;
  802. if (LF_ISSET(DB_AGGRESSIVE))
  803. goto keydata;
  804. break;
  805. }
  806. /* Too small to have any data. */
  807. if (len <
  808.     HKEYDATA_SIZE(2 * sizeof(db_indx_t))) {
  809. err_ret = DB_VERIFY_BAD;
  810. continue;
  811. }
  812. /* Loop until we hit the total length. */
  813. for (tlen = 0; tlen + sizeof(db_indx_t) < len;
  814.     tlen += dlen) {
  815. tlen += sizeof(db_indx_t);
  816. memcpy(&dlen, hk, sizeof(db_indx_t));
  817. /*
  818.  * If dlen is too long, print all the
  819.  * rest of the dup set in a chunk.
  820.  */
  821. if (dlen + tlen > len)
  822. dlen = len - tlen;
  823. memcpy(buf, hk + tlen, dlen);
  824. dbt.size = dlen;
  825. dbt.data = buf;
  826. if ((ret = __db_prdbt(&dbt, 0, " ",
  827.     handle, callback, 0, NULL)) != 0)
  828. err_ret = ret;
  829. tlen += sizeof(db_indx_t);
  830. }
  831. break;
  832. }
  833. }
  834. }
  835. __os_free(buf, 0);
  836. if ((t_ret = __db_salvage_markdone(vdp, pgno)) != 0)
  837. return (t_ret);
  838. return ((ret == 0 && err_ret != 0) ? err_ret : ret);
  839. }
  840. /*
  841.  * __ham_meta2pgset --
  842.  * Return the set of hash pages corresponding to the given
  843.  * known-good meta page.
  844.  *
  845.  * PUBLIC: int __ham_meta2pgset __P((DB *, VRFY_DBINFO *, HMETA *, u_int32_t,
  846.  * PUBLIC:     DB *));
  847.  */
  848. int __ham_meta2pgset(dbp, vdp, hmeta, flags, pgset)
  849. DB *dbp;
  850. VRFY_DBINFO *vdp;
  851. HMETA *hmeta;
  852. u_int32_t flags;
  853. DB *pgset;
  854. {
  855. PAGE *h;
  856. db_pgno_t pgno;
  857. u_int32_t bucket, totpgs;
  858. int ret, val;
  859. /*
  860.  * We don't really need flags, but leave them for consistency with
  861.  * __bam_meta2pgset.
  862.  */
  863. COMPQUIET(flags, 0);
  864. DB_ASSERT(pgset != NULL);
  865. totpgs = 0;
  866. /*
  867.  * Loop through all the buckets, pushing onto pgset the corresponding
  868.  * page(s) for each one.
  869.  */
  870. for (bucket = 0; bucket <= hmeta->max_bucket; bucket++) {
  871. pgno = BS_TO_PAGE(bucket, hmeta->spares);
  872. /*
  873.  * We know the initial pgno is safe because the spares array has
  874.  * been verified.
  875.  *
  876.  * Safely walk the list of pages in this bucket.
  877.  */
  878. for (;;) {
  879. if ((ret = memp_fget(dbp->mpf, &pgno, 0, &h)) != 0)
  880. return (ret);
  881. if (TYPE(h) == P_HASH) {
  882. /*
  883.  * Make sure we don't go past the end of
  884.  * pgset.
  885.  */
  886. if (++totpgs > vdp->last_pgno) {
  887. (void)memp_fput(dbp->mpf, h, 0);
  888. return (DB_VERIFY_BAD);
  889. }
  890. if ((ret =
  891.     __db_vrfy_pgset_inc(pgset, pgno)) != 0)
  892. return (ret);
  893. pgno = NEXT_PGNO(h);
  894. } else
  895. pgno = PGNO_INVALID;
  896. if ((ret = memp_fput(dbp->mpf, h, 0)) != 0)
  897. return (ret);
  898. /* If the new pgno is wonky, go onto the next bucket. */
  899. if (!IS_VALID_PGNO(pgno) ||
  900.     pgno == PGNO_INVALID)
  901. goto nextbucket;
  902. /*
  903.  * If we've touched this page before, we have a cycle;
  904.  * go on to the next bucket.
  905.  */
  906. if ((ret = __db_vrfy_pgset_get(pgset, pgno, &val)) != 0)
  907. return (ret);
  908. if (val != 0)
  909. goto nextbucket;
  910. }
  911. nextbucket: ;
  912. }
  913. return (0);
  914. }
  915. /*
  916.  * __ham_dups_unsorted --
  917.  * Takes a known-safe hash duplicate set and its total length.
  918.  * Returns 1 if there are out-of-order duplicates in this set,
  919.  * 0 if there are not.
  920.  */
  921. static int
  922. __ham_dups_unsorted(dbp, buf, len)
  923. DB *dbp;
  924. u_int8_t *buf;
  925. u_int32_t len;
  926. {
  927. DBT a, b;
  928. db_indx_t offset, dlen;
  929. int (*func) __P((DB *, const DBT *, const DBT *));
  930. memset(&a, 0, sizeof(DBT));
  931. memset(&b, 0, sizeof(DBT));
  932. func = (dbp->dup_compare == NULL) ? __bam_defcmp : dbp->dup_compare;
  933. /*
  934.  * Loop through the dup set until we hit the end or we find
  935.  * a pair of dups that's out of order.  b is always the current
  936.  * dup, a the one before it.
  937.  */
  938. for (offset = 0; offset < len; offset += DUP_SIZE(dlen)) {
  939. memcpy(&dlen, buf + offset, sizeof(db_indx_t));
  940. b.data = buf + offset + sizeof(db_indx_t);
  941. b.size = dlen;
  942. if (a.data != NULL && func(dbp, &a, &b) > 0)
  943. return (1);
  944. a.data = b.data;
  945. a.size = b.size;
  946. }
  947. return (0);
  948. }