2 * See the file LICENSE for redistribution information.
4 * Copyright (c) 1999-2001
5 * Sleepycat Software. All rights reserved.
7 * Id: hash_verify.c,v 1.39 2001/07/02 01:05:39 bostic Exp
10 #include "db_config.h"
13 static const char revid[] = "Id: hash_verify.c,v 1.39 2001/07/02 01:05:39 bostic Exp ";
16 #ifndef NO_SYSTEM_INCLUDES
17 #include <sys/types.h>
24 #include "db_verify.h"
28 static int __ham_dups_unsorted __P((DB *, u_int8_t *, u_int32_t));
29 static int __ham_vrfy_bucket __P((DB *, VRFY_DBINFO *, HMETA *, u_int32_t,
31 static int __ham_vrfy_item __P((DB *,
32 VRFY_DBINFO *, db_pgno_t, PAGE *, u_int32_t, u_int32_t));
35 * XXX Doing a db->del followed by a db->put for the same record
36 * causes the nelem/page count to go awry, causing db->verify failure.
37 * Turn off the message for now.
39 int db_hash_nelem_debug = 0;
43 * Verify the hash-specific part of a metadata page.
45 * Note that unlike btree, we don't save things off, because we
46 * will need most everything again to verify each page and the
47 * amount of state here is significant.
49 * PUBLIC: int __ham_vrfy_meta __P((DB *, VRFY_DBINFO *, HMETA *,
50 * PUBLIC: db_pgno_t, u_int32_t));
53 __ham_vrfy_meta(dbp, vdp, m, pgno, flags)
62 int i, ret, t_ret, isbad;
63 u_int32_t pwr, mbucket;
64 u_int32_t (*hfunc) __P((DB *, const void *, u_int32_t));
66 if ((ret = __db_vrfy_getpageinfo(vdp, pgno, &pip)) != 0)
70 hashp = dbp->h_internal;
72 if (hashp != NULL && hashp->h_hash != NULL)
73 hfunc = hashp->h_hash;
78 * If we haven't already checked the common fields in pagezero,
81 if (!F_ISSET(pip, VRFY_INCOMPLETE) &&
82 (ret = __db_vrfy_meta(dbp, vdp, &m->dbmeta, pgno, flags)) != 0) {
83 if (ret == DB_VERIFY_BAD)
90 if (!LF_ISSET(DB_NOORDERCHK))
91 if (m->h_charkey != hfunc(dbp, CHARKEY, sizeof(CHARKEY))) {
93 "Database has different custom hash function; reverify with DB_NOORDERCHK set"
96 * Return immediately; this is probably a sign
97 * of user error rather than database corruption, so
98 * we want to avoid extraneous errors.
104 /* max_bucket must be less than the last pgno. */
105 if (m->max_bucket > vdp->last_pgno) {
107 "Impossible max_bucket %lu on meta page %lu",
108 (u_long)m->max_bucket, (u_long)pgno));
110 * Most other fields depend somehow on max_bucket, so
111 * we just return--there will be lots of extraneous
119 * max_bucket, high_mask and low_mask: high_mask must be one
120 * less than the next power of two above max_bucket, and
121 * low_mask must be one less than the power of two below it.
125 pwr = (m->max_bucket == 0) ? 1 : 1 << __db_log2(m->max_bucket + 1);
126 if (m->high_mask != pwr - 1) {
128 "Incorrect high_mask %lu on page %lu, should be %lu",
129 (u_long)m->high_mask, (u_long)pgno, (u_long)pwr - 1));
133 if (m->low_mask != pwr - 1) {
135 "Incorrect low_mask %lu on page %lu, should be %lu",
136 (u_long)m->low_mask, (u_long)pgno, (u_long)pwr - 1));
140 /* ffactor: no check possible. */
141 pip->h_ffactor = m->ffactor;
144 * nelem: just make sure it's not astronomical for now. This is the
145 * same check that hash_upgrade does, since there was a bug in 2.X
146 * which could make nelem go "negative".
148 if (m->nelem > 0x80000000) {
149 if (db_hash_nelem_debug) {
151 "Suspiciously high nelem of %lu on page %lu",
152 (u_long)m->nelem, (u_long)pgno));
157 pip->h_nelem = m->nelem;
160 if (F_ISSET(&m->dbmeta, DB_HASH_DUP))
161 F_SET(pip, VRFY_HAS_DUPS);
162 if (F_ISSET(&m->dbmeta, DB_HASH_DUPSORT))
163 F_SET(pip, VRFY_HAS_DUPSORT);
164 /* XXX: Why is the DB_HASH_SUBDB flag necessary? */
167 for (i = 0; m->spares[i] != 0 && i < NCACHED; i++) {
169 * We set mbucket to the maximum bucket that would use a given
170 * spares entry; we want to ensure that it's always less
173 mbucket = (1 << i) - 1;
174 if (BS_TO_PAGE(mbucket, m->spares) > vdp->last_pgno) {
176 "Spares array entry %d, page %lu is invalid",
183 __db_vrfy_putpageinfo(dbp->dbenv, vdp, pip)) != 0 && ret == 0)
185 return ((ret == 0 && isbad == 1) ? DB_VERIFY_BAD : ret);
192 * PUBLIC: int __ham_vrfy __P((DB *, VRFY_DBINFO *, PAGE *, db_pgno_t,
193 * PUBLIC: u_int32_t));
196 __ham_vrfy(dbp, vdp, h, pgno, flags)
204 u_int32_t ent, himark, inpend;
205 int isbad, ret, t_ret;
208 if ((ret = __db_vrfy_getpageinfo(vdp, pgno, &pip)) != 0)
211 /* Sanity check our flags and page type. */
212 if ((ret = __db_fchk(dbp->dbenv, "__ham_vrfy",
213 flags, DB_AGGRESSIVE | DB_NOORDERCHK | DB_SALVAGE)) != 0)
216 if (TYPE(h) != P_HASH) {
217 TYPE_ERR_PRINT(dbp->dbenv, "__ham_vrfy", pgno, TYPE(h));
223 /* Verify and save off fields common to all PAGEs. */
224 if ((ret = __db_vrfy_datapage(dbp, vdp, h, pgno, flags)) != 0) {
225 if (ret == DB_VERIFY_BAD)
232 * Verify inp[]. Each offset from 0 to NUM_ENT(h) must be lower
233 * than the previous one, higher than the current end of the inp array,
234 * and lower than the page size.
236 * In any case, we return immediately if things are bad, as it would
237 * be unsafe to proceed.
239 for (ent = 0, himark = dbp->pgsize,
240 inpend = (u_int8_t *)h->inp - (u_int8_t *)h;
241 ent < NUM_ENT(h); ent++)
242 if (h->inp[ent] >= himark) {
244 "Item %lu on page %lu out of order or nonsensical",
245 (u_long)ent, (u_long)pgno));
248 } else if (inpend >= himark) {
250 "inp array collided with data on page %lu",
256 himark = h->inp[ent];
257 inpend += sizeof(db_indx_t);
258 if ((ret = __ham_vrfy_item(
259 dbp, vdp, pgno, h, ent, flags)) != 0)
264 __db_vrfy_putpageinfo(dbp->dbenv, vdp, pip)) != 0 && ret == 0)
266 return (ret == 0 && isbad == 1 ? DB_VERIFY_BAD : ret);
271 * Given a hash page and an offset, sanity-check the item itself,
272 * and save off any overflow items or off-page dup children as necessary.
275 __ham_vrfy_item(dbp, vdp, pgno, h, i, flags)
284 VRFY_CHILDINFO child;
286 db_indx_t offset, len, dlen, elen;
290 if ((ret = __db_vrfy_getpageinfo(vdp, pgno, &pip)) != 0)
293 switch (HPAGE_TYPE(h, i)) {
295 /* Nothing to do here--everything but the type field is data */
298 /* Are we a datum or a key? Better be the former. */
301 "Hash key stored as duplicate at page %lu item %lu",
302 (u_long)pip->pgno, (u_long)i));
305 * Dups are encoded as a series within a single HKEYDATA,
306 * in which each dup is surrounded by a copy of its length
307 * on either side (so that the series can be walked in either
308 * direction. We loop through this series and make sure
309 * each dup is reasonable.
311 * Note that at this point, we've verified item i-1, so
312 * it's safe to use LEN_HKEYDATA (which looks at inp[i-1]).
314 len = LEN_HKEYDATA(h, dbp->pgsize, i);
315 databuf = HKEYDATA_DATA(P_ENTRY(h, i));
316 for (offset = 0; offset < len; offset += DUP_SIZE(dlen)) {
317 memcpy(&dlen, databuf + offset, sizeof(db_indx_t));
319 /* Make sure the length is plausible. */
320 if (offset + DUP_SIZE(dlen) > len) {
322 "Duplicate item %lu, page %lu has bad length",
323 (u_long)i, (u_long)pip->pgno));
329 * Make sure the second copy of the length is the
333 databuf + offset + dlen + sizeof(db_indx_t),
337 "Duplicate item %lu, page %lu has two different lengths",
338 (u_long)i, (u_long)pip->pgno));
343 F_SET(pip, VRFY_HAS_DUPS);
344 if (!LF_ISSET(DB_NOORDERCHK) &&
345 __ham_dups_unsorted(dbp, databuf, len))
346 F_SET(pip, VRFY_DUPS_UNSORTED);
349 /* Offpage item. Make sure pgno is sane, save off. */
350 memcpy(&hop, P_ENTRY(h, i), HOFFPAGE_SIZE);
351 if (!IS_VALID_PGNO(hop.pgno) || hop.pgno == pip->pgno ||
352 hop.pgno == PGNO_INVALID) {
354 "Offpage item %lu, page %lu has bad pgno %lu",
355 (u_long)i, (u_long)pip->pgno, (u_long)hop.pgno));
359 memset(&child, 0, sizeof(VRFY_CHILDINFO));
360 child.pgno = hop.pgno;
361 child.type = V_OVERFLOW;
362 child.tlen = hop.tlen; /* This will get checked later. */
363 if ((ret = __db_vrfy_childput(vdp, pip->pgno, &child)) != 0)
367 /* Offpage duplicate item. Same drill. */
368 memcpy(&hod, P_ENTRY(h, i), HOFFDUP_SIZE);
369 if (!IS_VALID_PGNO(hod.pgno) || hod.pgno == pip->pgno ||
370 hod.pgno == PGNO_INVALID) {
372 "Offpage item %lu, page %lu has bad page number",
373 (u_long)i, (u_long)pip->pgno));
377 memset(&child, 0, sizeof(VRFY_CHILDINFO));
378 child.pgno = hod.pgno;
379 child.type = V_DUPLICATE;
380 if ((ret = __db_vrfy_childput(vdp, pip->pgno, &child)) != 0)
382 F_SET(pip, VRFY_HAS_DUPS);
386 "Item %i, page %lu has bad type",
387 (u_long)i, (u_long)pip->pgno));
393 __db_vrfy_putpageinfo(dbp->dbenv, vdp, pip)) != 0 && ret == 0)
399 * __ham_vrfy_structure --
400 * Verify the structure of a hash database.
402 * PUBLIC: int __ham_vrfy_structure __P((DB *, VRFY_DBINFO *, db_pgno_t,
403 * PUBLIC: u_int32_t));
406 __ham_vrfy_structure(dbp, vdp, meta_pgno, flags)
416 int isbad, p, ret, t_ret;
418 u_int32_t bucket, spares_entry;
424 if ((ret = __db_vrfy_pgset_get(pgset, meta_pgno, &p)) != 0)
428 "Hash meta page %lu referenced twice", (u_long)meta_pgno));
429 return (DB_VERIFY_BAD);
431 if ((ret = __db_vrfy_pgset_inc(pgset, meta_pgno)) != 0)
434 /* Get the meta page; we'll need it frequently. */
435 if ((ret = memp_fget(dbp->mpf, &meta_pgno, 0, &m)) != 0)
438 /* Loop through bucket by bucket. */
439 for (bucket = 0; bucket <= m->max_bucket; bucket++)
441 __ham_vrfy_bucket(dbp, vdp, m, bucket, flags)) != 0) {
442 if (ret == DB_VERIFY_BAD)
449 * There may be unused hash pages corresponding to buckets
450 * that have been allocated but not yet used. These may be
451 * part of the current doubling above max_bucket, or they may
452 * correspond to buckets that were used in a transaction
455 * Loop through them, as far as the spares array defines them,
456 * and make sure they're all empty.
458 * Note that this should be safe, since we've already verified
459 * that the spares array is sane.
461 for (bucket = m->max_bucket + 1; spares_entry = __db_log2(bucket + 1),
462 spares_entry < NCACHED && m->spares[spares_entry] != 0; bucket++) {
463 pgno = BS_TO_PAGE(bucket, m->spares);
464 if ((ret = __db_vrfy_getpageinfo(vdp, pgno, &pip)) != 0)
467 /* It's okay if these pages are totally zeroed; unmark it. */
468 F_CLR(pip, VRFY_IS_ALLZEROES);
470 if (pip->type != P_HASH) {
472 "Hash bucket %lu maps to non-hash page %lu",
473 (u_long)bucket, (u_long)pgno));
475 } else if (pip->entries != 0) {
477 "Non-empty page %lu in unused hash bucket %lu",
478 (u_long)pgno, (u_long)bucket));
481 if ((ret = __db_vrfy_pgset_get(pgset, pgno, &p)) != 0)
485 "Hash page %lu above max_bucket referenced",
490 __db_vrfy_pgset_inc(pgset, pgno)) != 0)
492 if ((ret = __db_vrfy_putpageinfo(dbp->dbenv,
499 /* If we got here, it's an error. */
500 (void)__db_vrfy_putpageinfo(dbp->dbenv, vdp, pip);
504 err: if ((t_ret = memp_fput(dbp->mpf, m, 0)) != 0)
506 if (h != NULL && (t_ret = memp_fput(dbp->mpf, h, 0)) != 0)
508 return ((isbad == 1 && ret == 0) ? DB_VERIFY_BAD: ret);
512 * __ham_vrfy_bucket --
513 * Verify a given bucket.
516 __ham_vrfy_bucket(dbp, vdp, m, bucket, flags)
520 u_int32_t bucket, flags;
523 VRFY_CHILDINFO *child;
524 VRFY_PAGEINFO *mip, *pip;
525 int ret, t_ret, isbad, p;
526 db_pgno_t pgno, next_pgno;
528 u_int32_t (*hfunc) __P((DB *, const void *, u_int32_t));
534 hashp = dbp->h_internal;
535 if (hashp != NULL && hashp->h_hash != NULL)
536 hfunc = hashp->h_hash;
540 if ((ret = __db_vrfy_getpageinfo(vdp, PGNO(m), &mip)) != 0)
543 /* Calculate the first pgno for this bucket. */
544 pgno = BS_TO_PAGE(bucket, m->spares);
546 if ((ret = __db_vrfy_getpageinfo(vdp, pgno, &pip)) != 0)
549 /* Make sure we got a plausible page number. */
550 if (pgno > vdp->last_pgno || pip->type != P_HASH) {
551 EPRINT((dbp->dbenv, "Bucket %lu has impossible first page %lu",
552 (u_long)bucket, (u_long)pgno));
553 /* Unsafe to continue. */
558 if (pip->prev_pgno != PGNO_INVALID) {
560 "First hash page %lu in bucket %lu has a prev_pgno",
566 * Set flags for dups and sorted dups.
568 flags |= F_ISSET(mip, VRFY_HAS_DUPS) ? ST_DUPOK : 0;
569 flags |= F_ISSET(mip, VRFY_HAS_DUPSORT) ? ST_DUPSORT : 0;
571 /* Loop until we find a fatal bug, or until we run out of pages. */
573 /* Provide feedback on our progress to the application. */
574 if (!LF_ISSET(DB_SALVAGE))
575 __db_vrfy_struct_feedback(dbp, vdp);
577 if ((ret = __db_vrfy_pgset_get(vdp->pgset, pgno, &p)) != 0)
581 "Hash page %lu referenced twice", (u_long)pgno));
583 /* Unsafe to continue. */
585 } else if ((ret = __db_vrfy_pgset_inc(vdp->pgset, pgno)) != 0)
589 * Hash pages that nothing has ever hashed to may never
590 * have actually come into existence, and may appear to be
591 * entirely zeroed. This is acceptable, and since there's
592 * no real way for us to know whether this has actually
593 * occurred, we clear the "wholly zeroed" flag on every
594 * hash page. A wholly zeroed page, by nature, will appear
595 * to have no flags set and zero entries, so should
596 * otherwise verify correctly.
598 F_CLR(pip, VRFY_IS_ALLZEROES);
600 /* If we have dups, our meta page had better know about it. */
601 if (F_ISSET(pip, VRFY_HAS_DUPS)
602 && !F_ISSET(mip, VRFY_HAS_DUPS)) {
604 "Duplicates present in non-duplicate database, page %lu",
610 * If the database has sorted dups, this page had better
611 * not have unsorted ones.
613 if (F_ISSET(mip, VRFY_HAS_DUPSORT) &&
614 F_ISSET(pip, VRFY_DUPS_UNSORTED)) {
616 "Unsorted dups in sorted-dup database, page %lu",
621 /* Walk overflow chains and offpage dup trees. */
622 if ((ret = __db_vrfy_childcursor(vdp, &cc)) != 0)
624 for (ret = __db_vrfy_ccset(cc, pip->pgno, &child); ret == 0;
625 ret = __db_vrfy_ccnext(cc, &child))
626 if (child->type == V_OVERFLOW) {
627 if ((ret = __db_vrfy_ovfl_structure(dbp, vdp,
628 child->pgno, child->tlen, flags)) != 0) {
629 if (ret == DB_VERIFY_BAD)
634 } else if (child->type == V_DUPLICATE) {
635 if ((ret = __db_vrfy_duptype(dbp,
636 vdp, child->pgno, flags)) != 0) {
640 if ((ret = __bam_vrfy_subtree(dbp, vdp,
641 child->pgno, NULL, NULL,
642 flags | ST_RECNUM | ST_DUPSET, NULL,
644 if (ret == DB_VERIFY_BAD)
650 if ((ret = __db_vrfy_ccclose(cc)) != 0)
654 /* If it's safe to check that things hash properly, do so. */
655 if (isbad == 0 && !LF_ISSET(DB_NOORDERCHK) &&
656 (ret = __ham_vrfy_hashing(dbp, pip->entries,
657 m, bucket, pgno, flags, hfunc)) != 0) {
658 if (ret == DB_VERIFY_BAD)
664 next_pgno = pip->next_pgno;
665 ret = __db_vrfy_putpageinfo(dbp->dbenv, vdp, pip);
671 if (next_pgno == PGNO_INVALID)
672 break; /* End of the bucket. */
674 /* We already checked this, but just in case... */
675 if (!IS_VALID_PGNO(next_pgno)) {
678 "Hash page %lu has bad next_pgno", (u_long)pgno));
683 if ((ret = __db_vrfy_getpageinfo(vdp, next_pgno, &pip)) != 0)
686 if (pip->prev_pgno != pgno) {
687 EPRINT((dbp->dbenv, "Hash page %lu has bad prev_pgno",
694 err: if (cc != NULL && ((t_ret = __db_vrfy_ccclose(cc)) != 0) && ret == 0)
696 if (mip != NULL && ((t_ret =
697 __db_vrfy_putpageinfo(dbp->dbenv, vdp, mip)) != 0) && ret == 0)
699 if (pip != NULL && ((t_ret =
700 __db_vrfy_putpageinfo(dbp->dbenv, vdp, pip)) != 0) && ret == 0)
702 return ((ret == 0 && isbad == 1) ? DB_VERIFY_BAD : ret);
706 * __ham_vrfy_hashing --
707 * Verify that all items on a given hash page hash correctly.
709 * PUBLIC: int __ham_vrfy_hashing __P((DB *,
710 * PUBLIC: u_int32_t, HMETA *, u_int32_t, db_pgno_t, u_int32_t,
711 * PUBLIC: u_int32_t (*) __P((DB *, const void *, u_int32_t))));
714 __ham_vrfy_hashing(dbp, nentries, m, thisbucket, pgno, flags, hfunc)
718 u_int32_t thisbucket;
721 u_int32_t (*hfunc) __P((DB *, const void *, u_int32_t));
726 int ret, t_ret, isbad;
727 u_int32_t hval, bucket;
730 memset(&dbt, 0, sizeof(DBT));
731 F_SET(&dbt, DB_DBT_REALLOC);
733 if ((ret = memp_fget(dbp->mpf, &pgno, 0, &h)) != 0)
736 for (i = 0; i < nentries; i += 2) {
738 * We've already verified the page integrity and that of any
739 * overflow chains linked off it; it is therefore safe to use
740 * __db_ret. It's also not all that much slower, since we have
741 * to copy every hash item to deal with alignment anyway; we
742 * can tweak this a bit if this proves to be a bottleneck,
743 * but for now, take the easy route.
745 if ((ret = __db_ret(dbp, h, i, &dbt, NULL, NULL)) != 0)
747 hval = hfunc(dbp, dbt.data, dbt.size);
749 bucket = hval & m->high_mask;
750 if (bucket > m->max_bucket)
751 bucket = bucket & m->low_mask;
753 if (bucket != thisbucket) {
755 "Item %lu on page %lu hashes incorrectly",
756 (u_long)i, (u_long)pgno));
761 err: if (dbt.data != NULL)
762 __os_free(dbp->dbenv, dbt.data, 0);
763 if ((t_ret = memp_fput(dbp->mpf, h, 0)) != 0)
766 return ((ret == 0 && isbad == 1) ? DB_VERIFY_BAD : ret);
771 * Safely dump out anything that looks like a key on an alleged
774 * PUBLIC: int __ham_salvage __P((DB *, VRFY_DBINFO *, db_pgno_t, PAGE *,
775 * PUBLIC: void *, int (*)(void *, const void *), u_int32_t));
778 __ham_salvage(dbp, vdp, pgno, h, handle, callback, flags)
784 int (*callback) __P((void *, const void *));
789 int ret, err_ret, t_ret;
790 u_int32_t himark, tlen;
793 u_int32_t dlen, len, i;
795 memset(&dbt, 0, sizeof(DBT));
796 dbt.flags = DB_DBT_REALLOC;
798 memset(&unkdbt, 0, sizeof(DBT));
799 unkdbt.size = strlen("UNKNOWN") + 1;
800 unkdbt.data = "UNKNOWN";
805 * Allocate a buffer for overflow items. Start at one page;
806 * __db_safe_goff will realloc as needed.
808 if ((ret = __os_malloc(dbp->dbenv, dbp->pgsize, &buf)) != 0)
811 himark = dbp->pgsize;
813 /* If we're not aggressive, break when we hit NUM_ENT(h). */
814 if (!LF_ISSET(DB_AGGRESSIVE) && i >= NUM_ENT(h))
817 /* Verify the current item. */
818 ret = __db_vrfy_inpitem(dbp,
819 h, pgno, i, 0, flags, &himark, NULL);
820 /* If this returned a fatality, it's time to break. */
821 if (ret == DB_VERIFY_FATAL)
826 len = LEN_HKEYDATA(h, dbp->pgsize, i);
827 if ((u_int32_t)(hk + len - (u_int8_t *)h) >
830 * Item is unsafely large; either continue
831 * or set it to the whole page, depending on
834 if (!LF_ISSET(DB_AGGRESSIVE))
837 (u_int32_t)(hk - (u_int8_t *)h);
838 err_ret = DB_VERIFY_BAD;
840 switch (HPAGE_PTYPE(hk)) {
842 if (!LF_ISSET(DB_AGGRESSIVE))
844 err_ret = DB_VERIFY_BAD;
847 keydata: memcpy(buf, HKEYDATA_DATA(hk), len);
850 if ((ret = __db_prdbt(&dbt,
851 0, " ", handle, callback, 0, NULL)) != 0)
855 if (len < HOFFPAGE_SIZE) {
856 err_ret = DB_VERIFY_BAD;
860 HOFFPAGE_PGNO(hk), sizeof(dpgno));
861 if ((ret = __db_safe_goff(dbp, vdp,
862 dpgno, &dbt, &buf, flags)) != 0) {
864 (void)__db_prdbt(&unkdbt, 0, " ",
865 handle, callback, 0, NULL);
868 if ((ret = __db_prdbt(&dbt,
869 0, " ", handle, callback, 0, NULL)) != 0)
873 if (len < HOFFPAGE_SIZE) {
874 err_ret = DB_VERIFY_BAD;
878 HOFFPAGE_PGNO(hk), sizeof(dpgno));
879 /* UNKNOWN iff pgno is bad or we're a key. */
880 if (!IS_VALID_PGNO(dpgno) || (i % 2 == 0)) {
881 if ((ret = __db_prdbt(&unkdbt, 0, " ",
882 handle, callback, 0, NULL)) != 0)
884 } else if ((ret = __db_salvage_duptree(dbp,
885 vdp, dpgno, &dbt, handle, callback,
886 flags | SA_SKIPFIRSTKEY)) != 0)
891 * We're a key; printing dups will seriously
892 * foul the output. If we're being aggressive,
893 * pretend this is a key and let the app.
894 * programmer sort out the mess.
898 if (LF_ISSET(DB_AGGRESSIVE))
903 /* Too small to have any data. */
905 HKEYDATA_SIZE(2 * sizeof(db_indx_t))) {
906 err_ret = DB_VERIFY_BAD;
910 /* Loop until we hit the total length. */
911 for (tlen = 0; tlen + sizeof(db_indx_t) < len;
913 tlen += sizeof(db_indx_t);
914 memcpy(&dlen, hk, sizeof(db_indx_t));
916 * If dlen is too long, print all the
917 * rest of the dup set in a chunk.
919 if (dlen + tlen > len)
921 memcpy(buf, hk + tlen, dlen);
924 if ((ret = __db_prdbt(&dbt, 0, " ",
925 handle, callback, 0, NULL)) != 0)
927 tlen += sizeof(db_indx_t);
934 __os_free(dbp->dbenv, buf, 0);
935 if ((t_ret = __db_salvage_markdone(vdp, pgno)) != 0)
937 return ((ret == 0 && err_ret != 0) ? err_ret : ret);
941 * __ham_meta2pgset --
942 * Return the set of hash pages corresponding to the given
943 * known-good meta page.
945 * PUBLIC: int __ham_meta2pgset __P((DB *, VRFY_DBINFO *, HMETA *, u_int32_t,
948 int __ham_meta2pgset(dbp, vdp, hmeta, flags, pgset)
957 u_int32_t bucket, totpgs;
961 * We don't really need flags, but leave them for consistency with
966 DB_ASSERT(pgset != NULL);
971 * Loop through all the buckets, pushing onto pgset the corresponding
972 * page(s) for each one.
974 for (bucket = 0; bucket <= hmeta->max_bucket; bucket++) {
975 pgno = BS_TO_PAGE(bucket, hmeta->spares);
978 * We know the initial pgno is safe because the spares array has
981 * Safely walk the list of pages in this bucket.
984 if ((ret = memp_fget(dbp->mpf, &pgno, 0, &h)) != 0)
986 if (TYPE(h) == P_HASH) {
989 * Make sure we don't go past the end of
992 if (++totpgs > vdp->last_pgno) {
993 (void)memp_fput(dbp->mpf, h, 0);
994 return (DB_VERIFY_BAD);
997 __db_vrfy_pgset_inc(pgset, pgno)) != 0) {
998 (void)memp_fput(dbp->mpf, h, 0);
1002 pgno = NEXT_PGNO(h);
1004 pgno = PGNO_INVALID;
1006 if ((ret = memp_fput(dbp->mpf, h, 0)) != 0)
1009 /* If the new pgno is wonky, go onto the next bucket. */
1010 if (!IS_VALID_PGNO(pgno) ||
1011 pgno == PGNO_INVALID)
1015 * If we've touched this page before, we have a cycle;
1016 * go on to the next bucket.
1018 if ((ret = __db_vrfy_pgset_get(pgset, pgno, &val)) != 0)
1028 * __ham_dups_unsorted --
1029 * Takes a known-safe hash duplicate set and its total length.
1030 * Returns 1 if there are out-of-order duplicates in this set,
1031 * 0 if there are not.
1034 __ham_dups_unsorted(dbp, buf, len)
1040 db_indx_t offset, dlen;
1041 int (*func) __P((DB *, const DBT *, const DBT *));
1043 memset(&a, 0, sizeof(DBT));
1044 memset(&b, 0, sizeof(DBT));
1046 func = (dbp->dup_compare == NULL) ? __bam_defcmp : dbp->dup_compare;
1049 * Loop through the dup set until we hit the end or we find
1050 * a pair of dups that's out of order. b is always the current
1051 * dup, a the one before it.
1053 for (offset = 0; offset < len; offset += DUP_SIZE(dlen)) {
1054 memcpy(&dlen, buf + offset, sizeof(db_indx_t));
1055 b.data = buf + offset + sizeof(db_indx_t);
1058 if (a.data != NULL && func(dbp, &a, &b) > 0)