summaryrefslogtreecommitdiff
path: root/db/btree/bt_verify.c
diff options
context:
space:
mode:
Diffstat (limited to 'db/btree/bt_verify.c')
-rw-r--r--db/btree/bt_verify.c733
1 files changed, 473 insertions, 260 deletions
diff --git a/db/btree/bt_verify.c b/db/btree/bt_verify.c
index 9f8647e7e..cd8c57a4d 100644
--- a/db/btree/bt_verify.c
+++ b/db/btree/bt_verify.c
@@ -1,16 +1,16 @@
/*-
* See the file LICENSE for redistribution information.
*
- * Copyright (c) 1999, 2000
+ * Copyright (c) 1999-2003
* Sleepycat Software. All rights reserved.
*
- * $Id: bt_verify.c,v 1.44 2000/12/06 19:55:44 ubell Exp $
+ * $Id: bt_verify.c,v 1.87 2003/10/06 14:09:23 bostic Exp $
*/
#include "db_config.h"
#ifndef lint
-static const char revid[] = "$Id: bt_verify.c,v 1.44 2000/12/06 19:55:44 ubell Exp $";
+static const char revid[] = "$Id: bt_verify.c,v 1.87 2003/10/06 14:09:23 bostic Exp $";
#endif /* not lint */
#ifndef NO_SYSTEM_INCLUDES
@@ -20,9 +20,11 @@ static const char revid[] = "$Id: bt_verify.c,v 1.44 2000/12/06 19:55:44 ubell E
#endif
#include "db_int.h"
-#include "db_page.h"
-#include "db_verify.h"
-#include "btree.h"
+#include "dbinc/db_page.h"
+#include "dbinc/db_shash.h"
+#include "dbinc/db_verify.h"
+#include "dbinc/btree.h"
+#include "dbinc/mp.h"
static int __bam_safe_getdata __P((DB *, PAGE *, u_int32_t, int, DBT *, int *));
static int __bam_vrfy_inp __P((DB *, VRFY_DBINFO *, PAGE *, db_pgno_t,
@@ -49,15 +51,17 @@ __bam_vrfy_meta(dbp, vdp, meta, pgno, flags)
db_pgno_t pgno;
u_int32_t flags;
{
+ DB_ENV *dbenv;
VRFY_PAGEINFO *pip;
int isbad, t_ret, ret;
db_indx_t ovflsize;
+ dbenv = dbp->dbenv;
+ isbad = 0;
+
if ((ret = __db_vrfy_getpageinfo(vdp, pgno, &pip)) != 0)
return (ret);
- isbad = 0;
-
/*
* If VRFY_INCOMPLETE is not set, then we didn't come through
* __db_vrfy_pagezero and didn't incompletely
@@ -79,19 +83,19 @@ __bam_vrfy_meta(dbp, vdp, meta, pgno, flags)
/* avoid division by zero */
ovflsize = meta->minkey > 0 ?
- B_MINKEY_TO_OVFLSIZE(meta->minkey, dbp->pgsize) : 0;
+ B_MINKEY_TO_OVFLSIZE(dbp, meta->minkey, dbp->pgsize) : 0;
if (meta->minkey < 2 ||
- ovflsize > B_MINKEY_TO_OVFLSIZE(DEFMINKEYPAGE, dbp->pgsize)) {
+ ovflsize > B_MINKEY_TO_OVFLSIZE(dbp, DEFMINKEYPAGE, dbp->pgsize)) {
pip->bt_minkey = 0;
isbad = 1;
- EPRINT((dbp->dbenv,
- "Nonsensical bt_minkey value %lu on metadata page %lu",
- (u_long)meta->minkey, (u_long)pgno));
+ EPRINT((dbenv,
+ "Page %lu: nonsensical bt_minkey value %lu on metadata page",
+ (u_long)pgno, (u_long)meta->minkey));
} else
pip->bt_minkey = meta->minkey;
- /* bt_maxkey: no constraints (XXX: right?) */
+ /* bt_maxkey: unsupported so no constraints. */
pip->bt_maxkey = meta->maxkey;
/* re_len: no constraints on this (may be zero or huge--we make rope) */
@@ -103,13 +107,13 @@ __bam_vrfy_meta(dbp, vdp, meta, pgno, flags)
* of the file, then the root page had better be page 1.
*/
pip->root = 0;
- if (meta->root == PGNO_INVALID
- || meta->root == pgno || !IS_VALID_PGNO(meta->root) ||
+ if (meta->root == PGNO_INVALID ||
+ meta->root == pgno || !IS_VALID_PGNO(meta->root) ||
(pgno == PGNO_BASE_MD && meta->root != 1)) {
isbad = 1;
- EPRINT((dbp->dbenv,
- "Nonsensical root page %lu on metadata page %lu",
- (u_long)meta->root, (u_long)vdp->last_pgno));
+ EPRINT((dbenv,
+ "Page %lu: nonsensical root page %lu on metadata page",
+ (u_long)pgno, (u_long)meta->root));
} else
pip->root = meta->root;
@@ -124,8 +128,8 @@ __bam_vrfy_meta(dbp, vdp, meta, pgno, flags)
*/
if (F_ISSET(&meta->dbmeta, BTM_DUP) && pgno == PGNO_BASE_MD) {
isbad = 1;
- EPRINT((dbp->dbenv,
- "Btree metadata page %lu has both duplicates and multiple databases",
+ EPRINT((dbenv,
+"Page %lu: Btree metadata page has both duplicates and multiple databases",
(u_long)pgno));
}
F_SET(pip, VRFY_HAS_SUBDBS);
@@ -138,8 +142,8 @@ __bam_vrfy_meta(dbp, vdp, meta, pgno, flags)
if (F_ISSET(&meta->dbmeta, BTM_RECNUM))
F_SET(pip, VRFY_HAS_RECNUMS);
if (F_ISSET(pip, VRFY_HAS_RECNUMS) && F_ISSET(pip, VRFY_HAS_DUPS)) {
- EPRINT((dbp->dbenv,
- "Btree metadata page %lu illegally has both recnums and dups",
+ EPRINT((dbenv,
+ "Page %lu: Btree metadata page illegally has both recnums and dups",
(u_long)pgno));
isbad = 1;
}
@@ -149,14 +153,14 @@ __bam_vrfy_meta(dbp, vdp, meta, pgno, flags)
dbp->type = DB_RECNO;
} else if (F_ISSET(pip, VRFY_IS_RRECNO)) {
isbad = 1;
- EPRINT((dbp->dbenv,
- "Metadata page %lu has renumber flag set but is not recno",
+ EPRINT((dbenv,
+ "Page %lu: metadata page has renumber flag set but is not recno",
(u_long)pgno));
}
if (F_ISSET(pip, VRFY_IS_RECNO) && F_ISSET(pip, VRFY_HAS_DUPS)) {
- EPRINT((dbp->dbenv,
- "Recno metadata page %lu specifies duplicates",
+ EPRINT((dbenv,
+ "Page %lu: recno metadata page specifies duplicates",
(u_long)pgno));
isbad = 1;
}
@@ -169,9 +173,9 @@ __bam_vrfy_meta(dbp, vdp, meta, pgno, flags)
* database
*/
isbad = 1;
- EPRINT((dbp->dbenv,
- "re_len of %lu in non-fixed-length database",
- (u_long)pip->re_len));
+ EPRINT((dbenv,
+ "Page %lu: re_len of %lu in non-fixed-length database",
+ (u_long)pgno, (u_long)pip->re_len));
}
/*
@@ -179,7 +183,7 @@ __bam_vrfy_meta(dbp, vdp, meta, pgno, flags)
* not be and may still be correct.
*/
-err: if ((t_ret = __db_vrfy_putpageinfo(vdp, pip)) != 0 && ret == 0)
+err: if ((t_ret = __db_vrfy_putpageinfo(dbenv, vdp, pip)) != 0 && ret == 0)
ret = t_ret;
return ((ret == 0 && isbad == 1) ? DB_VERIFY_BAD : ret);
}
@@ -200,22 +204,24 @@ __ram_vrfy_leaf(dbp, vdp, h, pgno, flags)
u_int32_t flags;
{
BKEYDATA *bk;
+ DB_ENV *dbenv;
VRFY_PAGEINFO *pip;
db_indx_t i;
int ret, t_ret, isbad;
u_int32_t re_len_guess, len;
+ dbenv = dbp->dbenv;
isbad = 0;
+
if ((ret = __db_vrfy_getpageinfo(vdp, pgno, &pip)) != 0)
return (ret);
- if ((ret = __db_fchk(dbp->dbenv,
- "__ram_vrfy_leaf", flags, OKFLAGS)) != 0)
+ if ((ret = __db_fchk(dbenv, "__ram_vrfy_leaf", flags, OKFLAGS)) != 0)
goto err;
if (TYPE(h) != P_LRECNO) {
/* We should not have been called. */
- TYPE_ERR_PRINT(dbp->dbenv, "__ram_vrfy_leaf", pgno, TYPE(h));
+ TYPE_ERR_PRINT(dbenv, "__ram_vrfy_leaf", pgno, TYPE(h));
DB_ASSERT(0);
ret = EINVAL;
goto err;
@@ -241,8 +247,8 @@ __ram_vrfy_leaf(dbp, vdp, h, pgno, flags)
goto err;
if (F_ISSET(pip, VRFY_HAS_DUPS)) {
- EPRINT((dbp->dbenv,
- "Recno database has dups on page %lu", (u_long)pgno));
+ EPRINT((dbenv,
+ "Page %lu: Recno database has dups", (u_long)pgno));
ret = DB_VERIFY_BAD;
goto err;
}
@@ -255,7 +261,7 @@ __ram_vrfy_leaf(dbp, vdp, h, pgno, flags)
*/
re_len_guess = 0;
for (i = 0; i < NUM_ENT(h); i++) {
- bk = GET_BKEYDATA(h, i);
+ bk = GET_BKEYDATA(dbp, h, i);
/* KEYEMPTY. Go on. */
if (B_DISSET(bk->type))
continue;
@@ -265,9 +271,9 @@ __ram_vrfy_leaf(dbp, vdp, h, pgno, flags)
len = bk->len;
else {
isbad = 1;
- EPRINT((dbp->dbenv,
- "Nonsensical type for item %lu, page %lu",
- (u_long)i, (u_long)pgno));
+ EPRINT((dbenv,
+ "Page %lu: nonsensical type for item %lu",
+ (u_long)pgno, (u_long)i));
continue;
}
if (re_len_guess == 0)
@@ -288,9 +294,9 @@ __ram_vrfy_leaf(dbp, vdp, h, pgno, flags)
/* Save off record count. */
pip->rec_cnt = NUM_ENT(h);
-err: if ((t_ret = __db_vrfy_putpageinfo(vdp, pip)) != 0 && ret == 0)
+err: if ((t_ret = __db_vrfy_putpageinfo(dbenv, vdp, pip)) != 0 && ret == 0)
ret = t_ret;
- return ((ret == 0 && isbad == 1) ? DB_VERIFY_BAD : 0);
+ return ((ret == 0 && isbad == 1) ? DB_VERIFY_BAD : ret);
}
/*
@@ -308,10 +314,13 @@ __bam_vrfy(dbp, vdp, h, pgno, flags)
db_pgno_t pgno;
u_int32_t flags;
{
+ DB_ENV *dbenv;
VRFY_PAGEINFO *pip;
int ret, t_ret, isbad;
+ dbenv = dbp->dbenv;
isbad = 0;
+
if ((ret = __db_vrfy_getpageinfo(vdp, pgno, &pip)) != 0)
return (ret);
@@ -322,7 +331,7 @@ __bam_vrfy(dbp, vdp, h, pgno, flags)
case P_LDUP:
break;
default:
- TYPE_ERR_PRINT(dbp->dbenv, "__bam_vrfy", pgno, TYPE(h));
+ TYPE_ERR_PRINT(dbenv, "__bam_vrfy", pgno, TYPE(h));
DB_ASSERT(0);
ret = EINVAL;
goto err;
@@ -361,8 +370,8 @@ __bam_vrfy(dbp, vdp, h, pgno, flags)
isbad = 1;
else
goto err;
- EPRINT((dbp->dbenv,
- "item order check on page %lu unsafe: skipping",
+ EPRINT((dbenv,
+ "Page %lu: item order check unsafe: skipping",
(u_long)pgno));
} else if (!LF_ISSET(DB_NOORDERCHK) && (ret =
__bam_vrfy_itemorder(dbp, vdp, h, pgno, 0, 0, 0, flags)) != 0) {
@@ -377,9 +386,9 @@ __bam_vrfy(dbp, vdp, h, pgno, flags)
goto err;
}
-err: if ((t_ret = __db_vrfy_putpageinfo(vdp, pip)) != 0 && ret == 0)
+err: if ((t_ret = __db_vrfy_putpageinfo(dbenv, vdp, pip)) != 0 && ret == 0)
ret = t_ret;
- return ((ret == 0 && isbad == 1) ? DB_VERIFY_BAD : 0);
+ return ((ret == 0 && isbad == 1) ? DB_VERIFY_BAD : ret);
}
/*
@@ -398,13 +407,16 @@ __ram_vrfy_inp(dbp, vdp, h, pgno, nentriesp, flags)
db_indx_t *nentriesp;
u_int32_t flags;
{
+ DB_ENV *dbenv;
RINTERNAL *ri;
VRFY_CHILDINFO child;
VRFY_PAGEINFO *pip;
int ret, t_ret, isbad;
u_int32_t himark, i, offset, nentries;
+ db_indx_t *inp;
u_int8_t *pagelayout, *p;
+ dbenv = dbp->dbenv;
isbad = 0;
memset(&child, 0, sizeof(VRFY_CHILDINFO));
nentries = 0;
@@ -414,38 +426,38 @@ __ram_vrfy_inp(dbp, vdp, h, pgno, nentriesp, flags)
return (ret);
if (TYPE(h) != P_IRECNO) {
- TYPE_ERR_PRINT(dbp->dbenv, "__ram_vrfy_inp", pgno, TYPE(h));
+ TYPE_ERR_PRINT(dbenv, "__ram_vrfy_inp", pgno, TYPE(h));
DB_ASSERT(0);
ret = EINVAL;
goto err;
}
himark = dbp->pgsize;
- if ((ret =
- __os_malloc(dbp->dbenv, dbp->pgsize, NULL, &pagelayout)) != 0)
+ if ((ret = __os_malloc(dbenv, dbp->pgsize, &pagelayout)) != 0)
goto err;
memset(pagelayout, 0, dbp->pgsize);
+ inp = P_INP(dbp, h);
for (i = 0; i < NUM_ENT(h); i++) {
- if ((u_int8_t *)h->inp + i >= (u_int8_t *)h + himark) {
- EPRINT((dbp->dbenv,
- "Page %lu entries listing %lu overlaps data",
+ if ((u_int8_t *)inp + i >= (u_int8_t *)h + himark) {
+ EPRINT((dbenv,
+ "Page %lu: entries listing %lu overlaps data",
(u_long)pgno, (u_long)i));
ret = DB_VERIFY_BAD;
goto err;
}
- offset = h->inp[i];
+ offset = inp[i];
/*
* Check that the item offset is reasonable: it points
* somewhere after the inp array and before the end of the
* page.
*/
- if (offset <= (u_int32_t)((u_int8_t *)h->inp + i -
+ if (offset <= (u_int32_t)((u_int8_t *)inp + i -
(u_int8_t *)h) ||
offset > (u_int32_t)(dbp->pgsize - RINTERNAL_SIZE)) {
isbad = 1;
- EPRINT((dbp->dbenv,
- "Bad offset %lu at page %lu index %lu",
- (u_long)offset, (u_long)pgno, (u_long)i));
+ EPRINT((dbenv,
+ "Page %lu: bad offset %lu at index %lu",
+ (u_long)pgno, (u_long)offset, (u_long)i));
continue;
}
@@ -456,7 +468,7 @@ __ram_vrfy_inp(dbp, vdp, h, pgno, nentriesp, flags)
nentries++;
/* Make sure this RINTERNAL is not multiply referenced. */
- ri = GET_RINTERNAL(h, i);
+ ri = GET_RINTERNAL(dbp, h, i);
if (pagelayout[offset] == 0) {
pagelayout[offset] = 1;
child.pgno = ri->pgno;
@@ -465,9 +477,9 @@ __ram_vrfy_inp(dbp, vdp, h, pgno, nentriesp, flags)
if ((ret = __db_vrfy_childput(vdp, pgno, &child)) != 0)
goto err;
} else {
- EPRINT((dbp->dbenv,
- "RINTERNAL structure at offset %lu, page %lu referenced twice",
- (u_long)offset, (u_long)pgno));
+ EPRINT((dbenv,
+ "Page %lu: RINTERNAL structure at offset %lu referenced twice",
+ (u_long)pgno, (u_long)offset));
isbad = 1;
}
}
@@ -476,24 +488,25 @@ __ram_vrfy_inp(dbp, vdp, h, pgno, nentriesp, flags)
p < pagelayout + dbp->pgsize;
p += RINTERNAL_SIZE)
if (*p != 1) {
- EPRINT((dbp->dbenv,
- "Gap between items at offset %lu, page %lu",
- (u_long)(p - pagelayout), (u_long)pgno));
+ EPRINT((dbenv,
+ "Page %lu: gap between items at offset %lu",
+ (u_long)pgno, (u_long)(p - pagelayout)));
isbad = 1;
}
if ((db_indx_t)himark != HOFFSET(h)) {
- EPRINT((dbp->dbenv, "Bad HOFFSET %lu, appears to be %lu",
- (u_long)(HOFFSET(h)), (u_long)himark));
+ EPRINT((dbenv,
+ "Page %lu: bad HOFFSET %lu, appears to be %lu",
+ (u_long)pgno, (u_long)(HOFFSET(h)), (u_long)himark));
isbad = 1;
}
*nentriesp = nentries;
-err: if ((t_ret = __db_vrfy_putpageinfo(vdp, pip)) != 0 && ret == 0)
+err: if ((t_ret = __db_vrfy_putpageinfo(dbenv, vdp, pip)) != 0 && ret == 0)
ret = t_ret;
if (pagelayout != NULL)
- __os_free(pagelayout, dbp->pgsize);
+ __os_free(dbenv, pagelayout);
return ((ret == 0 && isbad == 1) ? DB_VERIFY_BAD : ret);
}
@@ -513,6 +526,7 @@ __bam_vrfy_inp(dbp, vdp, h, pgno, nentriesp, flags)
{
BKEYDATA *bk;
BOVERFLOW *bo;
+ DB_ENV *dbenv;
VRFY_CHILDINFO child;
VRFY_PAGEINFO *pip;
int isbad, initem, isdupitem, ret, t_ret;
@@ -520,6 +534,7 @@ __bam_vrfy_inp(dbp, vdp, h, pgno, nentriesp, flags)
u_int32_t i, endoff, nentries;
u_int8_t *pagelayout;
+ dbenv = dbp->dbenv;
isbad = isdupitem = 0;
nentries = 0;
memset(&child, 0, sizeof(VRFY_CHILDINFO));
@@ -540,7 +555,7 @@ __bam_vrfy_inp(dbp, vdp, h, pgno, nentriesp, flags)
*/
if (LF_ISSET(DB_SALVAGE))
break;
- TYPE_ERR_PRINT(dbp->dbenv, "__bam_vrfy_inp", pgno, TYPE(h));
+ TYPE_ERR_PRINT(dbenv, "__bam_vrfy_inp", pgno, TYPE(h));
DB_ASSERT(0);
ret = EINVAL;
goto err;
@@ -558,22 +573,24 @@ __bam_vrfy_inp(dbp, vdp, h, pgno, nentriesp, flags)
* it and the region immediately after it.
*/
himark = dbp->pgsize;
- if ((ret = __os_malloc(dbp->dbenv,
- dbp->pgsize, NULL, &pagelayout)) != 0)
+ if ((ret = __os_malloc(dbenv, dbp->pgsize, &pagelayout)) != 0)
goto err;
memset(pagelayout, 0, dbp->pgsize);
for (i = 0; i < NUM_ENT(h); i++) {
-
- ret = __db_vrfy_inpitem(dbp,
- h, pgno, i, 1, flags, &himark, &offset);
- if (ret == DB_VERIFY_BAD) {
+ switch (ret = __db_vrfy_inpitem(dbp,
+ h, pgno, i, 1, flags, &himark, &offset)) {
+ case 0:
+ break;
+ case DB_VERIFY_BAD:
isbad = 1;
continue;
- } else if (ret == DB_VERIFY_FATAL) {
+ case DB_VERIFY_FATAL:
isbad = 1;
goto err;
- } else if (ret != 0)
- DB_ASSERT(0);
+ default:
+ DB_ASSERT(ret != 0);
+ break;
+ }
/*
* We now have a plausible beginning for the item, and we know
@@ -582,7 +599,7 @@ __bam_vrfy_inp(dbp, vdp, h, pgno, nentriesp, flags)
* Mark the beginning and end in pagelayout so we can make sure
* items have no overlaps or gaps.
*/
- bk = GET_BKEYDATA(h, i);
+ bk = GET_BKEYDATA(dbp, h, i);
#define ITEM_BEGIN 1
#define ITEM_END 2
if (pagelayout[offset] == 0)
@@ -608,9 +625,8 @@ __bam_vrfy_inp(dbp, vdp, h, pgno, nentriesp, flags)
isdupitem = 1;
} else {
isbad = 1;
- EPRINT((dbp->dbenv,
- "Duplicated item %lu on page %lu",
- (u_long)i, (u_long)pgno));
+ EPRINT((dbenv, "Page %lu: duplicated item %lu",
+ (u_long)pgno, (u_long)i));
}
}
@@ -621,7 +637,7 @@ __bam_vrfy_inp(dbp, vdp, h, pgno, nentriesp, flags)
* If the end already has a sign other than 0, do nothing--
* it's an overlap that we'll catch later.
*/
- switch(B_TYPE(bk->type)) {
+ switch (B_TYPE(bk->type)) {
case B_KEYDATA:
if (TYPE(h) == P_IBTREE)
/* It's a BINTERNAL. */
@@ -661,9 +677,8 @@ __bam_vrfy_inp(dbp, vdp, h, pgno, nentriesp, flags)
* the end had better coincide too.
*/
if (isdupitem && pagelayout[endoff] != ITEM_END) {
- EPRINT((dbp->dbenv,
- "Duplicated item %lu on page %lu",
- (u_long)i, (u_long)pgno));
+ EPRINT((dbenv, "Page %lu: duplicated item %lu",
+ (u_long)pgno, (u_long)i));
isbad = 1;
} else if (pagelayout[endoff] == 0)
pagelayout[endoff] = ITEM_END;
@@ -675,9 +690,8 @@ __bam_vrfy_inp(dbp, vdp, h, pgno, nentriesp, flags)
*/
if (B_DISSET(bk->type) && TYPE(h) != P_LRECNO) {
isbad = 1;
- EPRINT((dbp->dbenv,
- "Item %lu on page %lu marked deleted",
- (u_long)i, (u_long)pgno));
+ EPRINT((dbenv, "Page %lu: item %lu marked deleted",
+ (u_long)pgno, (u_long)i));
}
/*
@@ -695,14 +709,14 @@ __bam_vrfy_inp(dbp, vdp, h, pgno, nentriesp, flags)
case B_DUPLICATE:
if (TYPE(h) == P_IBTREE) {
isbad = 1;
- EPRINT((dbp->dbenv,
- "Duplicate page referenced by internal btree page %lu at item %lu",
+ EPRINT((dbenv,
+ "Page %lu: duplicate page referenced by internal btree page at item %lu",
(u_long)pgno, (u_long)i));
break;
} else if (TYPE(h) == P_LRECNO) {
isbad = 1;
- EPRINT((dbp->dbenv,
- "Duplicate page referenced by recno page %lu at item %lu",
+ EPRINT((dbenv,
+ "Page %lu: duplicate page referenced by recno page at item %lu",
(u_long)pgno, (u_long)i));
break;
}
@@ -716,10 +730,10 @@ __bam_vrfy_inp(dbp, vdp, h, pgno, nentriesp, flags)
/* Make sure tlen is reasonable. */
if (bo->tlen > dbp->pgsize * vdp->last_pgno) {
isbad = 1;
- EPRINT((dbp->dbenv,
- "Impossible tlen %lu, item %lu, page %lu",
- (u_long)bo->tlen, (u_long)i,
- (u_long)pgno));
+ EPRINT((dbenv,
+ "Page %lu: impossible tlen %lu, item %lu",
+ (u_long)pgno,
+ (u_long)bo->tlen, (u_long)i));
/* Don't save as a child. */
break;
}
@@ -727,9 +741,9 @@ __bam_vrfy_inp(dbp, vdp, h, pgno, nentriesp, flags)
if (!IS_VALID_PGNO(bo->pgno) || bo->pgno == pgno ||
bo->pgno == PGNO_INVALID) {
isbad = 1;
- EPRINT((dbp->dbenv,
- "Offpage item %lu, page %lu has bad pgno",
- (u_long)i, (u_long)pgno));
+ EPRINT((dbenv,
+ "Page %lu: offpage item %lu has bad pgno %lu",
+ (u_long)pgno, (u_long)i, (u_long)bo->pgno));
/* Don't save as a child. */
break;
}
@@ -743,9 +757,8 @@ __bam_vrfy_inp(dbp, vdp, h, pgno, nentriesp, flags)
break;
default:
isbad = 1;
- EPRINT((dbp->dbenv,
- "Item %lu on page %lu of invalid type %lu",
- (u_long)i, (u_long)pgno));
+ EPRINT((dbenv, "Page %lu: item %lu of invalid type %lu",
+ (u_long)pgno, (u_long)i, (u_long)B_TYPE(bk->type)));
break;
}
}
@@ -764,8 +777,8 @@ __bam_vrfy_inp(dbp, vdp, h, pgno, nentriesp, flags)
continue;
isbad = 1;
- EPRINT((dbp->dbenv,
- "Gap between items, page %lu offset %lu",
+ EPRINT((dbenv,
+ "Page %lu: gap between items at offset %lu",
(u_long)pgno, (u_long)i));
/* Find the end of the gap */
for ( ; pagelayout[i + 1] == 0 &&
@@ -776,9 +789,9 @@ __bam_vrfy_inp(dbp, vdp, h, pgno, nentriesp, flags)
/* We've found an item. Check its alignment. */
if (i != ALIGN(i, sizeof(u_int32_t))) {
isbad = 1;
- EPRINT((dbp->dbenv,
- "Offset %lu page %lu unaligned",
- (u_long)i, (u_long)pgno));
+ EPRINT((dbenv,
+ "Page %lu: offset %lu unaligned",
+ (u_long)pgno, (u_long)i));
}
initem = 1;
nentries++;
@@ -790,8 +803,8 @@ __bam_vrfy_inp(dbp, vdp, h, pgno, nentriesp, flags)
* be an overlap.
*/
isbad = 1;
- EPRINT((dbp->dbenv,
- "Overlapping items, page %lu offset %lu",
+ EPRINT((dbenv,
+ "Page %lu: overlapping items at offset %lu",
(u_long)pgno, (u_long)i));
break;
default:
@@ -815,25 +828,25 @@ __bam_vrfy_inp(dbp, vdp, h, pgno, nentriesp, flags)
* end. Overlap.
*/
isbad = 1;
- EPRINT((dbp->dbenv,
- "Overlapping items, page %lu offset %lu",
+ EPRINT((dbenv,
+ "Page %lu: overlapping items at offset %lu",
(u_long)pgno, (u_long)i));
break;
}
- (void)__os_free(pagelayout, dbp->pgsize);
+ __os_free(dbenv, pagelayout);
/* Verify HOFFSET. */
if ((db_indx_t)himark != HOFFSET(h)) {
- EPRINT((dbp->dbenv, "Bad HOFFSET %lu, appears to be %lu",
- (u_long)HOFFSET(h), (u_long)himark));
+ EPRINT((dbenv, "Page %lu: bad HOFFSET %lu, appears to be %lu",
+ (u_long)pgno, (u_long)HOFFSET(h), (u_long)himark));
isbad = 1;
}
err: if (nentriesp != NULL)
*nentriesp = nentries;
- if ((t_ret = __db_vrfy_putpageinfo(vdp, pip)) != 0 && ret == 0)
+ if ((t_ret = __db_vrfy_putpageinfo(dbenv, vdp, pip)) != 0 && ret == 0)
ret = t_ret;
return ((isbad == 1 && ret == 0) ? DB_VERIFY_BAD : ret);
@@ -865,14 +878,15 @@ __bam_vrfy_itemorder(dbp, vdp, h, pgno, nentries, ovflok, hasdups, flags)
int ovflok, hasdups;
u_int32_t flags;
{
- DBT dbta, dbtb, dup1, dup2, *p1, *p2, *tmp;
- BTREE *bt;
BINTERNAL *bi;
BKEYDATA *bk;
BOVERFLOW *bo;
+ BTREE *bt;
+ DBT dbta, dbtb, dup_1, dup_2, *p1, *p2, *tmp;
+ DB_ENV *dbenv;
VRFY_PAGEINFO *pip;
db_indx_t i;
- int cmp, freedup1, freedup2, isbad, ret, t_ret;
+ int cmp, freedup_1, freedup_2, isbad, ret, t_ret;
int (*dupfunc) __P((DB *, const DBT *, const DBT *));
int (*func) __P((DB *, const DBT *, const DBT *));
void *buf1, *buf2, *tmpbuf;
@@ -889,6 +903,7 @@ __bam_vrfy_itemorder(dbp, vdp, h, pgno, nentries, ovflok, hasdups, flags)
} else
pip = NULL;
+ dbenv = dbp->dbenv;
ret = isbad = 0;
bo = NULL; /* Shut up compiler. */
@@ -949,7 +964,7 @@ __bam_vrfy_itemorder(dbp, vdp, h, pgno, nentries, ovflok, hasdups, flags)
*/
switch (TYPE(h)) {
case P_IBTREE:
- bi = GET_BINTERNAL(h, i);
+ bi = GET_BINTERNAL(dbp, h, i);
if (B_TYPE(bi->type) == B_OVERFLOW) {
bo = (BOVERFLOW *)(bi->data);
goto overflow;
@@ -971,15 +986,15 @@ __bam_vrfy_itemorder(dbp, vdp, h, pgno, nentries, ovflok, hasdups, flags)
#if 0
if (i == 0 && bi->len != 0) {
isbad = 1;
- EPRINT((dbp->dbenv,
- "Lowest key on internal page %lu of nonzero length",
+ EPRINT((dbenv,
+ "Page %lu: lowest key on internal page of nonzero length",
(u_long)pgno));
}
#endif
break;
case P_LBTREE:
case P_LDUP:
- bk = GET_BKEYDATA(h, i);
+ bk = GET_BKEYDATA(dbp, h, i);
if (B_TYPE(bk->type) == B_OVERFLOW) {
bo = (BOVERFLOW *)bk;
goto overflow;
@@ -993,7 +1008,7 @@ __bam_vrfy_itemorder(dbp, vdp, h, pgno, nentries, ovflok, hasdups, flags)
* This means our caller screwed up and sent us
* an inappropriate page.
*/
- TYPE_ERR_PRINT(dbp->dbenv,
+ TYPE_ERR_PRINT(dbenv,
"__bam_vrfy_itemorder", pgno, TYPE(h))
DB_ASSERT(0);
ret = EINVAL;
@@ -1029,9 +1044,9 @@ overflow: if (!ovflok) {
if ((ret = __db_goff(dbp,
p2, bo->tlen, bo->pgno, NULL, NULL)) != 0) {
isbad = 1;
- EPRINT((dbp->dbenv,
- "Error %lu in fetching overflow item %lu, page %lu",
- (u_long)ret, (u_long)i, (u_long)pgno));
+ EPRINT((dbenv,
+ "Page %lu: error %lu in fetching overflow item %lu",
+ (u_long)pgno, (u_long)ret, (u_long)i));
}
/* In case it got realloc'ed and thus changed. */
buf2 = p2->data;
@@ -1044,8 +1059,8 @@ overflow: if (!ovflok) {
/* comparison succeeded */
if (cmp > 0) {
isbad = 1;
- EPRINT((dbp->dbenv,
- "Out-of-order key, page %lu item %lu",
+ EPRINT((dbenv,
+ "Page %lu: out-of-order key at entry %lu",
(u_long)pgno, (u_long)i));
/* proceed */
} else if (cmp == 0) {
@@ -1059,8 +1074,8 @@ overflow: if (!ovflok) {
F_SET(pip, VRFY_HAS_DUPS);
else if (hasdups == 0) {
isbad = 1;
- EPRINT((dbp->dbenv,
- "Database with no duplicates has duplicated keys on page %lu",
+ EPRINT((dbenv,
+ "Page %lu: database with no duplicates has duplicated keys",
(u_long)pgno));
}
@@ -1092,11 +1107,11 @@ overflow: if (!ovflok) {
* dups are probably (?) rare.
*/
if (((ret = __bam_safe_getdata(dbp,
- h, i - 1, ovflok, &dup1,
- &freedup1)) != 0) ||
+ h, i - 1, ovflok, &dup_1,
+ &freedup_1)) != 0) ||
((ret = __bam_safe_getdata(dbp,
- h, i + 1, ovflok, &dup2,
- &freedup2)) != 0))
+ h, i + 1, ovflok, &dup_2,
+ &freedup_2)) != 0))
goto err;
/*
@@ -1105,8 +1120,8 @@ overflow: if (!ovflok) {
* it's not safe to chase them now.
* Mark an incomplete and return.
*/
- if (dup1.data == NULL ||
- dup2.data == NULL) {
+ if (dup_1.data == NULL ||
+ dup_2.data == NULL) {
DB_ASSERT(!ovflok);
F_SET(pip, VRFY_INCOMPLETE);
goto err;
@@ -1118,26 +1133,26 @@ overflow: if (!ovflok) {
* until we do the structure check
* and see whether DUPSORT is set.
*/
- if (dupfunc(dbp, &dup1, &dup2) > 0)
+ if (dupfunc(dbp, &dup_1, &dup_2) > 0)
F_SET(pip, VRFY_DUPS_UNSORTED);
- if (freedup1)
- __os_free(dup1.data, 0);
- if (freedup2)
- __os_free(dup2.data, 0);
+ if (freedup_1)
+ __os_ufree(dbenv, dup_1.data);
+ if (freedup_2)
+ __os_ufree(dbenv, dup_2.data);
}
}
}
}
-err: if (pip != NULL &&
- ((t_ret = __db_vrfy_putpageinfo(vdp, pip)) != 0) && ret == 0)
+err: if (pip != NULL && ((t_ret =
+ __db_vrfy_putpageinfo(dbenv, vdp, pip)) != 0) && ret == 0)
ret = t_ret;
if (buf1 != NULL)
- __os_free(buf1, 0);
+ __os_ufree(dbenv, buf1);
if (buf2 != NULL)
- __os_free(buf2, 0);
+ __os_ufree(dbenv, buf2);
return ((ret == 0 && isbad == 1) ? DB_VERIFY_BAD : ret);
}
@@ -1158,11 +1173,13 @@ __bam_vrfy_structure(dbp, vdp, meta_pgno, flags)
u_int32_t flags;
{
DB *pgset;
+ DB_ENV *dbenv;
VRFY_PAGEINFO *mip, *rip;
db_pgno_t root, p;
int t_ret, ret;
u_int32_t nrecs, level, relen, stflags;
+ dbenv = dbp->dbenv;
mip = rip = 0;
pgset = vdp->pgset;
@@ -1172,8 +1189,8 @@ __bam_vrfy_structure(dbp, vdp, meta_pgno, flags)
if ((ret = __db_vrfy_pgset_get(pgset, meta_pgno, (int *)&p)) != 0)
goto err;
if (p != 0) {
- EPRINT((dbp->dbenv,
- "Btree metadata page number %lu observed twice",
+ EPRINT((dbenv,
+ "Page %lu: btree metadata page observed twice",
(u_long)meta_pgno));
ret = DB_VERIFY_BAD;
goto err;
@@ -1184,8 +1201,9 @@ __bam_vrfy_structure(dbp, vdp, meta_pgno, flags)
root = mip->root;
if (root == 0) {
- EPRINT((dbp->dbenv,
- "Btree metadata page %lu has no root", (u_long)meta_pgno));
+ EPRINT((dbenv,
+ "Page %lu: btree metadata page has no root",
+ (u_long)meta_pgno));
ret = DB_VERIFY_BAD;
goto err;
}
@@ -1221,8 +1239,8 @@ __bam_vrfy_structure(dbp, vdp, meta_pgno, flags)
* that should never happen.
*/
if (mip->re_len > 0 && relen > 0 && mip->re_len != relen) {
- EPRINT((dbp->dbenv,
- "Recno database with meta page %lu has bad re_len %lu",
+ EPRINT((dbenv,
+ "Page %lu: recno database has bad re_len %lu",
(u_long)meta_pgno, (u_long)relen));
ret = DB_VERIFY_BAD;
goto err;
@@ -1230,25 +1248,25 @@ __bam_vrfy_structure(dbp, vdp, meta_pgno, flags)
ret = 0;
break;
case P_LDUP:
- EPRINT((dbp->dbenv,
- "Duplicate tree referenced from metadata page %lu",
+ EPRINT((dbenv,
+ "Page %lu: duplicate tree referenced from metadata page",
(u_long)meta_pgno));
ret = DB_VERIFY_BAD;
break;
default:
- EPRINT((dbp->dbenv,
- "Btree root of incorrect type %lu on meta page %lu",
- (u_long)rip->type, (u_long)meta_pgno));
+ EPRINT((dbenv,
+ "Page %lu: btree root of incorrect type %lu on metadata page",
+ (u_long)meta_pgno, (u_long)rip->type));
ret = DB_VERIFY_BAD;
break;
}
-err: if (mip != NULL &&
- ((t_ret = __db_vrfy_putpageinfo(vdp, mip)) != 0) && ret == 0)
- t_ret = ret;
- if (rip != NULL &&
- ((t_ret = __db_vrfy_putpageinfo(vdp, rip)) != 0) && ret == 0)
- t_ret = ret;
+err: if (mip != NULL && ((t_ret =
+ __db_vrfy_putpageinfo(dbenv, vdp, mip)) != 0) && ret == 0)
+ ret = t_ret;
+ if (rip != NULL && ((t_ret =
+ __db_vrfy_putpageinfo(dbenv, vdp, rip)) != 0) && ret == 0)
+ ret = t_ret;
return (ret);
}
@@ -1263,8 +1281,7 @@ err: if (mip != NULL &&
* PUBLIC: void *, u_int32_t, u_int32_t *, u_int32_t *, u_int32_t *));
*/
int
-__bam_vrfy_subtree(dbp,
- vdp, pgno, l, r, flags, levelp, nrecsp, relenp)
+__bam_vrfy_subtree(dbp, vdp, pgno, l, r, flags, levelp, nrecsp, relenp)
DB *dbp;
VRFY_DBINFO *vdp;
db_pgno_t pgno;
@@ -1274,19 +1291,27 @@ __bam_vrfy_subtree(dbp,
BINTERNAL *li, *ri, *lp, *rp;
DB *pgset;
DBC *cc;
+ DB_ENV *dbenv;
+ DB_MPOOLFILE *mpf;
PAGE *h;
VRFY_CHILDINFO *child;
VRFY_PAGEINFO *pip;
- db_recno_t nrecs, child_nrecs;
db_indx_t i;
- int ret, t_ret, isbad, toplevel, p;
+ db_pgno_t next_pgno, prev_pgno;
+ db_recno_t child_nrecs, nrecs;
+ u_int32_t child_level, child_relen, j, level, relen, stflags;
+ u_int8_t leaf_type;
int (*func) __P((DB *, const DBT *, const DBT *));
- u_int32_t level, child_level, stflags, child_relen, relen;
+ int isbad, p, ret, t_ret, toplevel;
+ dbenv = dbp->dbenv;
+ mpf = dbp->mpf;
ret = isbad = 0;
nrecs = 0;
h = NULL;
relen = 0;
+ leaf_type = P_INVALID;
+ next_pgno = prev_pgno = PGNO_INVALID;
rp = (BINTERNAL *)r;
lp = (BINTERNAL *)l;
@@ -1300,10 +1325,33 @@ __bam_vrfy_subtree(dbp,
cc = NULL;
level = pip->bt_level;
- toplevel = LF_ISSET(ST_TOPLEVEL);
+ toplevel = LF_ISSET(ST_TOPLEVEL) ? 1 : 0;
LF_CLR(ST_TOPLEVEL);
/*
+ * If this is the root, initialize the vdp's prev- and next-pgno
+ * accounting.
+ *
+ * For each leaf page we hit, we'll want to make sure that
+ * vdp->prev_pgno is the same as pip->prev_pgno and vdp->next_pgno is
+ * our page number. Then, we'll set vdp->next_pgno to pip->next_pgno
+ * and vdp->prev_pgno to our page number, and the next leaf page in
+ * line should be able to do the same verification.
+ */
+ if (toplevel) {
+ /*
+ * Cache the values stored in the vdp so that if we're an
+ * auxiliary tree such as an off-page duplicate set, our
+ * caller's leaf page chain doesn't get lost.
+ */
+ prev_pgno = vdp->prev_pgno;
+ next_pgno = vdp->next_pgno;
+ leaf_type = vdp->leaf_type;
+ vdp->next_pgno = vdp->prev_pgno = PGNO_INVALID;
+ vdp->leaf_type = P_INVALID;
+ }
+
+ /*
* We are recursively descending a btree, starting from the root
* and working our way out to the leaves.
*
@@ -1333,8 +1381,63 @@ __bam_vrfy_subtree(dbp,
case P_LDUP:
case P_LBTREE:
/*
- * Cases 1, 2 and 3 (overflow pages are common to all three);
- * traverse child list, looking for overflows.
+ * Cases 1, 2 and 3.
+ *
+ * We're some sort of leaf page; verify
+ * that our linked list of leaves is consistent.
+ */
+ if (vdp->leaf_type == P_INVALID) {
+ /*
+ * First leaf page. Set the type that all its
+ * successors should be, and verify that our prev_pgno
+ * is PGNO_INVALID.
+ */
+ vdp->leaf_type = pip->type;
+ if (pip->prev_pgno != PGNO_INVALID)
+ goto bad_prev;
+ } else {
+ /*
+ * Successor leaf page. Check our type, the previous
+ * page's next_pgno, and our prev_pgno.
+ */
+ if (pip->type != vdp->leaf_type) {
+ EPRINT((dbenv,
+ "Page %lu: unexpected page type %lu found in leaf chain (expected %lu)",
+ (u_long)pip->pgno, (u_long)pip->type,
+ (u_long)vdp->leaf_type));
+ isbad = 1;
+ }
+
+ /*
+ * Don't do the prev/next_pgno checks if we've lost
+ * leaf pages due to another corruption.
+ */
+ if (!F_ISSET(vdp, VRFY_LEAFCHAIN_BROKEN)) {
+ if (pip->pgno != vdp->next_pgno) {
+ EPRINT((dbenv,
+ "Page %lu: incorrect next_pgno %lu found in leaf chain (should be %lu)",
+ (u_long)vdp->prev_pgno,
+ (u_long)vdp->next_pgno,
+ (u_long)pip->pgno));
+ isbad = 1;
+ }
+ if (pip->prev_pgno != vdp->prev_pgno) {
+bad_prev: EPRINT((dbenv,
+ "Page %lu: incorrect prev_pgno %lu found in leaf chain (should be %lu)",
+ (u_long)pip->pgno,
+ (u_long)pip->prev_pgno,
+ (u_long)vdp->prev_pgno));
+ isbad = 1;
+ }
+ }
+ }
+ vdp->prev_pgno = pip->pgno;
+ vdp->next_pgno = pip->next_pgno;
+ F_CLR(vdp, VRFY_LEAFCHAIN_BROKEN);
+
+ /*
+ * Overflow pages are common to all three leaf types;
+ * traverse the child list, looking for overflows.
*/
if ((ret = __db_vrfy_childcursor(vdp, &cc)) != 0)
goto err;
@@ -1359,8 +1462,8 @@ __bam_vrfy_subtree(dbp,
if (!LF_ISSET(ST_IS_RECNO) &&
!(LF_ISSET(ST_DUPOK) && !LF_ISSET(ST_DUPSORT))) {
isbad = 1;
- EPRINT((dbp->dbenv,
- "Recno leaf page %lu in non-recno tree",
+ EPRINT((dbenv,
+ "Page %lu: recno leaf page non-recno tree",
(u_long)pgno));
goto done;
}
@@ -1371,8 +1474,8 @@ __bam_vrfy_subtree(dbp,
* subtree.
*/
isbad = 1;
- EPRINT((dbp->dbenv,
- "Non-recno leaf page %lu in recno tree",
+ EPRINT((dbenv,
+ "Page %lu: non-recno leaf page in recno tree",
(u_long)pgno));
goto done;
}
@@ -1388,8 +1491,8 @@ __bam_vrfy_subtree(dbp,
/* If dups aren't allowed in this btree, trouble. */
if (!LF_ISSET(ST_DUPOK)) {
isbad = 1;
- EPRINT((dbp->dbenv,
- "Duplicates on page %lu in non-dup btree",
+ EPRINT((dbenv,
+ "Page %lu: duplicates in non-dup btree",
(u_long)pgno));
} else {
/*
@@ -1414,8 +1517,8 @@ __bam_vrfy_subtree(dbp,
}
if ((ret = __bam_vrfy_subtree(
dbp, vdp, child->pgno, NULL,
- NULL, stflags, NULL, NULL,
- NULL)) != 0) {
+ NULL, stflags | ST_TOPLEVEL,
+ NULL, NULL, NULL)) != 0) {
if (ret !=
DB_VERIFY_BAD)
goto err;
@@ -1435,15 +1538,14 @@ __bam_vrfy_subtree(dbp,
*/
if (F_ISSET(pip, VRFY_DUPS_UNSORTED) &&
LF_ISSET(ST_DUPSORT)) {
- EPRINT((dbp->dbenv,
- "Unsorted duplicate set at page %lu in sorted-dup database",
+ EPRINT((dbenv,
+ "Page %lu: unsorted duplicate set in sorted-dup database",
(u_long)pgno));
isbad = 1;
}
}
}
goto leaf;
- break;
case P_IBTREE:
case P_IRECNO:
/* We handle these below. */
@@ -1455,10 +1557,27 @@ __bam_vrfy_subtree(dbp,
* Note that the code at the "done" label assumes that the
* current page is a btree/recno one of some sort; this
* is not the case here, so we goto err.
+ *
+ * If the page is entirely zeroed, its pip->type will be a lie
+ * (we assumed it was a hash page, as they're allowed to be
+ * zeroed); handle this case specially.
*/
- EPRINT((dbp->dbenv,
- "Page %lu is of inappropriate type %lu",
- (u_long)pgno, (u_long)pip->type));
+ if (F_ISSET(pip, VRFY_IS_ALLZEROES))
+ ZEROPG_ERR_PRINT(dbenv, pgno, "btree or recno page");
+ else
+ EPRINT((dbenv,
+ "Page %lu: btree or recno page is of inappropriate type %lu",
+ (u_long)pgno, (u_long)pip->type));
+
+ /*
+ * We probably lost a leaf page (or more if this was an
+ * internal page) from our prev/next_pgno chain. Flag
+ * that this is expected; we don't want or need to
+ * spew error messages about erroneous prev/next_pgnos,
+ * since that's probably not the real problem.
+ */
+ F_SET(vdp, VRFY_LEAFCHAIN_BROKEN);
+
ret = DB_VERIFY_BAD;
goto err;
}
@@ -1474,7 +1593,7 @@ __bam_vrfy_subtree(dbp,
ret = __db_vrfy_ccnext(cc, &child))
if (child->type == V_RECNO) {
if (pip->type != P_IRECNO) {
- TYPE_ERR_PRINT(dbp->dbenv, "__bam_vrfy_subtree",
+ TYPE_ERR_PRINT(dbenv, "__bam_vrfy_subtree",
pgno, pip->type);
DB_ASSERT(0);
ret = EINVAL;
@@ -1499,30 +1618,64 @@ __bam_vrfy_subtree(dbp,
else if (child_relen > 0 &&
relen != child_relen) {
isbad = 1;
- EPRINT((dbp->dbenv,
- "Recno page %lu returned bad re_len",
- (u_long)child->pgno));
+ EPRINT((dbenv,
+ "Page %lu: recno page returned bad re_len %lu",
+ (u_long)child->pgno,
+ (u_long)child_relen));
}
if (relenp)
*relenp = relen;
}
if (LF_ISSET(ST_RECNUM))
nrecs += child_nrecs;
- if (level != child_level + 1) {
+ if (isbad == 0 && level != child_level + 1) {
isbad = 1;
- EPRINT((dbp->dbenv, "%s%lu%s%lu%s%lu",
- "Recno level incorrect on page ",
- (u_long)child->pgno, ": got ",
- (u_long)child_level, ", expected ",
+ EPRINT((dbenv,
+ "Page %lu: recno level incorrect: got %lu, expected %lu",
+ (u_long)child->pgno, (u_long)child_level,
(u_long)(level - 1)));
}
- } else if (child->type == V_OVERFLOW &&
- (ret = __db_vrfy_ovfl_structure(dbp, vdp,
- child->pgno, child->tlen, flags)) != 0) {
- if (ret == DB_VERIFY_BAD)
+ } else if (child->type == V_OVERFLOW) {
+ /*
+ * It is possible for one internal page to reference
+ * a single overflow page twice, if all the items
+ * in the subtree referenced by slot 0 are deleted,
+ * then a similar number of items are put back
+ * before the key that formerly had been in slot 1.
+ *
+ * (Btree doesn't look at the key in slot 0, so the
+ * fact that the key formerly at slot 1 is the "wrong"
+ * parent of the stuff in the slot 0 subtree isn't
+ * really incorrect.)
+ *
+ * __db_vrfy_ovfl_structure is designed to be
+ * efficiently called multiple times for multiple
+ * references; call it here as many times as is
+ * appropriate.
+ */
+
+ /* Otherwise, __db_vrfy_childput would be broken. */
+ DB_ASSERT(child->refcnt >= 1);
+
+ /*
+ * An overflow referenced more than twice here
+ * shouldn't happen.
+ */
+ if (child->refcnt > 2) {
+ EPRINT((dbenv,
+ "Page %lu: overflow page %lu referenced more than twice from internal page",
+ (u_long)pgno, (u_long)child->pgno));
isbad = 1;
- else
- goto done;
+ } else
+ for (j = 0; j < child->refcnt; j++)
+ if ((ret = __db_vrfy_ovfl_structure(dbp,
+ vdp, child->pgno, child->tlen,
+ flags)) != 0) {
+ if (ret == DB_VERIFY_BAD)
+ isbad = 1;
+ else
+ goto done;
+ }
}
if ((ret = __db_vrfy_ccclose(cc)) != 0)
@@ -1543,12 +1696,12 @@ __bam_vrfy_subtree(dbp,
* itself, which must sort lower than all entries on its child;
* ri will be the key to its right, which must sort greater.
*/
- if (h == NULL && (ret = memp_fget(dbp->mpf, &pgno, 0, &h)) != 0)
+ if (h == NULL && (ret = __memp_fget(mpf, &pgno, 0, &h)) != 0)
goto err;
for (i = 0; i < pip->entries; i += O_INDX) {
- li = GET_BINTERNAL(h, i);
+ li = GET_BINTERNAL(dbp, h, i);
ri = (i + O_INDX < pip->entries) ?
- GET_BINTERNAL(h, i + O_INDX) : NULL;
+ GET_BINTERNAL(dbp, h, i + O_INDX) : NULL;
/*
* The leftmost key is forcibly sorted less than all entries,
@@ -1577,19 +1730,19 @@ __bam_vrfy_subtree(dbp,
*/
if (li->nrecs != child_nrecs) {
isbad = 1;
- EPRINT((dbp->dbenv,
- "Item %lu page %lu has incorrect record count of %lu, should be %lu",
- (u_long)i, (u_long)pgno, (u_long)li->nrecs,
+ EPRINT((dbenv,
+ "Page %lu: item %lu has incorrect record count of %lu, should be %lu",
+ (u_long)pgno, (u_long)i, (u_long)li->nrecs,
(u_long)child_nrecs));
}
}
if (level != child_level + 1) {
isbad = 1;
- EPRINT((dbp->dbenv, "%s%lu%s%lu%s%lu",
- "Btree level incorrect on page ", (u_long)li->pgno,
- ": got ", (u_long)child_level, ", expected ",
- (u_long)(level - 1)));
+ EPRINT((dbenv,
+ "Page %lu: Btree level incorrect: got %lu, expected %lu",
+ (u_long)li->pgno,
+ (u_long)child_level, (u_long)(level - 1)));
}
}
@@ -1616,7 +1769,7 @@ done: if (F_ISSET(pip, VRFY_INCOMPLETE) && isbad == 0 && ret == 0) {
* isbad == 0, though, it's now safe to do so, as we've
* traversed any child overflow pages. Do it.
*/
- if (h == NULL && (ret = memp_fget(dbp->mpf, &pgno, 0, &h)) != 0)
+ if (h == NULL && (ret = __memp_fget(mpf, &pgno, 0, &h)) != 0)
goto err;
if ((ret = __bam_vrfy_itemorder(dbp,
vdp, h, pgno, 0, 1, 0, flags)) != 0)
@@ -1625,12 +1778,35 @@ done: if (F_ISSET(pip, VRFY_INCOMPLETE) && isbad == 0 && ret == 0) {
}
/*
+ * It's possible to get to this point with a page that has no
+ * items, but without having detected any sort of failure yet.
+ * Having zero items is legal if it's a leaf--it may be the
+ * root page in an empty tree, or the tree may have been
+ * modified with the DB_REVSPLITOFF flag set (there's no way
+ * to tell from what's on disk). For an internal page,
+ * though, having no items is a problem (all internal pages
+ * must have children).
+ */
+ if (isbad == 0 && ret == 0) {
+ if (h == NULL && (ret = __memp_fget(mpf, &pgno, 0, &h)) != 0)
+ goto err;
+
+ if (NUM_ENT(h) == 0 && ISINTERNAL(h)) {
+ EPRINT((dbenv,
+ "Page %lu: internal page is empty and should not be",
+ (u_long)pgno));
+ isbad = 1;
+ goto err;
+ }
+ }
+
+ /*
* Our parent has sent us BINTERNAL pointers to parent records
* so that we can verify our place with respect to them. If it's
* appropriate--we have a default sort function--verify this.
*/
if (isbad == 0 && ret == 0 && !LF_ISSET(DB_NOORDERCHK) && lp != NULL) {
- if (h == NULL && (ret = memp_fget(dbp->mpf, &pgno, 0, &h)) != 0)
+ if (h == NULL && (ret = __memp_fget(mpf, &pgno, 0, &h)) != 0)
goto err;
/*
@@ -1661,8 +1837,8 @@ done: if (F_ISSET(pip, VRFY_INCOMPLETE) && isbad == 0 && ret == 0) {
*/
if (LF_ISSET(ST_RECNUM) && nrecs != pip->rec_cnt && toplevel) {
isbad = 1;
- EPRINT((dbp->dbenv,
- "Bad record count on page %lu: got %lu, expected %lu",
+ EPRINT((dbenv,
+ "Page %lu: bad record count: has %lu records, claims %lu",
(u_long)pgno, (u_long)nrecs, (u_long)pip->rec_cnt));
}
@@ -1676,13 +1852,31 @@ done: if (F_ISSET(pip, VRFY_INCOMPLETE) && isbad == 0 && ret == 0) {
goto err;
if (p != 0) {
isbad = 1;
- EPRINT((dbp->dbenv, "Page %lu linked twice", (u_long)pgno));
+ EPRINT((dbenv, "Page %lu: linked twice", (u_long)pgno));
} else if ((ret = __db_vrfy_pgset_inc(pgset, pgno)) != 0)
goto err;
-err: if (h != NULL && (t_ret = memp_fput(dbp->mpf, h, 0)) != 0 && ret == 0)
+ if (toplevel)
+ /*
+ * The last page's next_pgno in the leaf chain should have been
+ * PGNO_INVALID.
+ */
+ if (vdp->next_pgno != PGNO_INVALID) {
+ EPRINT((dbenv, "Page %lu: unterminated leaf chain",
+ (u_long)vdp->prev_pgno));
+ isbad = 1;
+ }
+
+err: if (toplevel) {
+ /* Restore our caller's settings. */
+ vdp->next_pgno = next_pgno;
+ vdp->prev_pgno = prev_pgno;
+ vdp->leaf_type = leaf_type;
+ }
+
+ if (h != NULL && (t_ret = __memp_fput(mpf, h, 0)) != 0 && ret == 0)
ret = t_ret;
- if ((t_ret = __db_vrfy_putpageinfo(vdp, pip)) != 0 && ret == 0)
+ if ((t_ret = __db_vrfy_putpageinfo(dbenv, vdp, pip)) != 0 && ret == 0)
ret = t_ret;
if (cc != NULL && ((t_ret = __db_vrfy_ccclose(cc)) != 0) && ret == 0)
ret = t_ret;
@@ -1712,14 +1906,24 @@ __bam_vrfy_treeorder(dbp, pgno, h, lp, rp, func, flags)
u_int32_t flags;
{
BOVERFLOW *bo;
+ DB_ENV *dbenv;
DBT dbt;
db_indx_t last;
int ret, cmp;
+ dbenv = dbp->dbenv;
memset(&dbt, 0, sizeof(DBT));
F_SET(&dbt, DB_DBT_MALLOC);
ret = 0;
+ /*
+ * Empty pages are sorted correctly by definition. We check
+ * to see whether they ought to be empty elsewhere; leaf
+ * pages legally may be.
+ */
+ if (NUM_ENT(h) == 0)
+ return (0);
+
switch (TYPE(h)) {
case P_IBTREE:
case P_LDUP:
@@ -1729,8 +1933,7 @@ __bam_vrfy_treeorder(dbp, pgno, h, lp, rp, func, flags)
last = NUM_ENT(h) - P_INDX;
break;
default:
- TYPE_ERR_PRINT(dbp->dbenv,
- "__bam_vrfy_treeorder", pgno, TYPE(h));
+ TYPE_ERR_PRINT(dbenv, "__bam_vrfy_treeorder", pgno, TYPE(h));
DB_ASSERT(0);
return (EINVAL);
}
@@ -1759,26 +1962,27 @@ __bam_vrfy_treeorder(dbp, pgno, h, lp, rp, func, flags)
return (ret);
} else {
DB_ASSERT(0);
- EPRINT((dbp->dbenv,
- "Unknown type for internal record"));
+ EPRINT((dbenv,
+ "Page %lu: unknown type for internal record",
+ (u_long)PGNO(h)));
return (EINVAL);
}
/* On error, fall through, free if neeeded, and return. */
if ((ret = __bam_cmp(dbp, &dbt, h, 0, func, &cmp)) == 0) {
if (cmp > 0) {
- EPRINT((dbp->dbenv,
- "First item on page %lu sorted greater than parent entry",
+ EPRINT((dbenv,
+ "Page %lu: first item on page sorted greater than parent entry",
(u_long)PGNO(h)));
ret = DB_VERIFY_BAD;
}
} else
- EPRINT((dbp->dbenv,
- "First item on page %lu had comparison error",
+ EPRINT((dbenv,
+ "Page %lu: first item on page had comparison error",
(u_long)PGNO(h)));
if (dbt.data != lp->data)
- __os_free(dbt.data, 0);
+ __os_ufree(dbenv, dbt.data);
if (ret != 0)
return (ret);
}
@@ -1794,26 +1998,27 @@ __bam_vrfy_treeorder(dbp, pgno, h, lp, rp, func, flags)
return (ret);
} else {
DB_ASSERT(0);
- EPRINT((dbp->dbenv,
- "Unknown type for internal record"));
+ EPRINT((dbenv,
+ "Page %lu: unknown type for internal record",
+ (u_long)PGNO(h)));
return (EINVAL);
}
/* On error, fall through, free if neeeded, and return. */
if ((ret = __bam_cmp(dbp, &dbt, h, last, func, &cmp)) == 0) {
if (cmp < 0) {
- EPRINT((dbp->dbenv,
- "Last item on page %lu sorted greater than parent entry",
+ EPRINT((dbenv,
+ "Page %lu: last item on page sorted greater than parent entry",
(u_long)PGNO(h)));
ret = DB_VERIFY_BAD;
}
} else
- EPRINT((dbp->dbenv,
- "Last item on page %lu had comparison error",
+ EPRINT((dbenv,
+ "Page %lu: last item on page had comparison error",
(u_long)PGNO(h)));
if (dbt.data != rp->data)
- __os_free(dbt.data, 0);
+ __os_ufree(dbenv, dbt.data);
}
return (ret);
@@ -1841,37 +2046,41 @@ __bam_salvage(dbp, vdp, pgno, pgtype, h, handle, callback, key, flags)
u_int32_t flags;
{
DBT dbt, unkdbt;
+ DB_ENV *dbenv;
BKEYDATA *bk;
BOVERFLOW *bo;
- db_indx_t i, beg, end;
+ db_indx_t i, beg, end, *inp;
u_int32_t himark;
u_int8_t *pgmap;
void *ovflbuf;
int t_ret, ret, err_ret;
+ dbenv = dbp->dbenv;
+
/* Shut up lint. */
COMPQUIET(end, 0);
ovflbuf = pgmap = NULL;
err_ret = ret = 0;
+ inp = P_INP(dbp, h);
memset(&dbt, 0, sizeof(DBT));
dbt.flags = DB_DBT_REALLOC;
memset(&unkdbt, 0, sizeof(DBT));
- unkdbt.size = strlen("UNKNOWN") + 1;
+ unkdbt.size = (u_int32_t)(strlen("UNKNOWN") + 1);
unkdbt.data = "UNKNOWN";
/*
* Allocate a buffer for overflow items. Start at one page;
* __db_safe_goff will realloc as needed.
*/
- if ((ret = __os_malloc(dbp->dbenv, dbp->pgsize, NULL, &ovflbuf)) != 0)
+ if ((ret = __os_malloc(dbenv, dbp->pgsize, &ovflbuf)) != 0)
return (ret);
if (LF_ISSET(DB_AGGRESSIVE)) {
if ((ret =
- __os_malloc(dbp->dbenv, dbp->pgsize, NULL, &pgmap)) != 0)
+ __os_malloc(dbenv, dbp->pgsize, &pgmap)) != 0)
goto err;
memset(pgmap, 0, dbp->pgsize);
}
@@ -1914,7 +2123,7 @@ __bam_salvage(dbp, vdp, pgno, pgtype, h, handle, callback, key, flags)
* We only want to print deleted items if
* DB_AGGRESSIVE is set.
*/
- bk = GET_BKEYDATA(h, i);
+ bk = GET_BKEYDATA(dbp, h, i);
if (!LF_ISSET(DB_AGGRESSIVE) && B_DISSET(bk->type))
continue;
@@ -1927,10 +2136,10 @@ __bam_salvage(dbp, vdp, pgno, pgtype, h, handle, callback, key, flags)
if (key != NULL &&
(i != 0 || !LF_ISSET(SA_SKIPFIRSTKEY)))
if ((ret = __db_prdbt(key,
- 0, " ", handle, callback, 0, NULL)) != 0)
+ 0, " ", handle, callback, 0, vdp)) != 0)
err_ret = ret;
- beg = h->inp[i];
+ beg = inp[i];
switch (B_TYPE(bk->type)) {
case B_DUPLICATE:
end = beg + BOVERFLOW_SIZE - 1;
@@ -1958,23 +2167,24 @@ __bam_salvage(dbp, vdp, pgno, pgtype, h, handle, callback, key, flags)
(i % P_INDX == 0)) {
/* Not much to do on failure. */
if ((ret = __db_prdbt(&unkdbt, 0, " ",
- handle, callback, 0, NULL)) != 0)
+ handle, callback, 0, vdp)) != 0)
err_ret = ret;
break;
}
if ((ret = __db_salvage_duptree(dbp,
vdp, bo->pgno, &dbt, handle, callback,
- flags | SA_SKIPFIRSTKEY)) != 0)
+ flags | SA_SKIPFIRSTKEY)) != 0)
err_ret = ret;
break;
case B_KEYDATA:
- end = ALIGN(beg + bk->len, sizeof(u_int32_t)) - 1;
+ end =
+ ALIGN(beg + bk->len, sizeof(u_int32_t)) - 1;
dbt.data = bk->data;
dbt.size = bk->len;
if ((ret = __db_prdbt(&dbt,
- 0, " ", handle, callback, 0, NULL)) != 0)
+ 0, " ", handle, callback, 0, vdp)) != 0)
err_ret = ret;
break;
case B_OVERFLOW:
@@ -1985,11 +2195,11 @@ __bam_salvage(dbp, vdp, pgno, pgtype, h, handle, callback, key, flags)
err_ret = ret;
/* We care about err_ret more. */
(void)__db_prdbt(&unkdbt, 0, " ",
- handle, callback, 0, NULL);
+ handle, callback, 0, vdp);
break;
}
if ((ret = __db_prdbt(&dbt,
- 0, " ", handle, callback, 0, NULL)) != 0)
+ 0, " ", handle, callback, 0, vdp)) != 0)
err_ret = ret;
break;
default:
@@ -2020,12 +2230,12 @@ __bam_salvage(dbp, vdp, pgno, pgtype, h, handle, callback, key, flags)
* a datum; fix this imbalance by printing an "UNKNOWN".
*/
if (pgtype == P_LBTREE && (i % P_INDX == 1) && ((ret =
- __db_prdbt(&unkdbt, 0, " ", handle, callback, 0, NULL)) != 0))
+ __db_prdbt(&unkdbt, 0, " ", handle, callback, 0, vdp)) != 0))
err_ret = ret;
err: if (pgmap != NULL)
- __os_free(pgmap, 0);
- __os_free(ovflbuf, 0);
+ __os_free(dbenv, pgmap);
+ __os_free(dbenv, ovflbuf);
/* Mark this page as done. */
if ((t_ret = __db_salvage_markdone(vdp, pgno)) != 0)
@@ -2061,12 +2271,13 @@ __bam_salvage_walkdupint(dbp, vdp, h, key, handle, callback, flags)
for (i = 0; i < NUM_ENT(h); i++) {
switch (TYPE(h)) {
case P_IBTREE:
- bi = GET_BINTERNAL(h, i);
+ bi = GET_BINTERNAL(dbp, h, i);
if ((t_ret = __db_salvage_duptree(dbp,
vdp, bi->pgno, key, handle, callback, flags)) != 0)
ret = t_ret;
+ break;
case P_IRECNO:
- ri = GET_RINTERNAL(h, i);
+ ri = GET_RINTERNAL(dbp, h, i);
if ((t_ret = __db_salvage_duptree(dbp,
vdp, ri->pgno, key, handle, callback, flags)) != 0)
ret = t_ret;
@@ -2110,11 +2321,13 @@ __bam_meta2pgset(dbp, vdp, btmeta, flags, pgset)
DB *pgset;
{
BINTERNAL *bi;
+ DB_MPOOLFILE *mpf;
PAGE *h;
RINTERNAL *ri;
db_pgno_t current, p;
int err_ret, ret;
+ mpf = dbp->mpf;
h = NULL;
ret = err_ret = 0;
DB_ASSERT(pgset != NULL);
@@ -2123,7 +2336,7 @@ __bam_meta2pgset(dbp, vdp, btmeta, flags, pgset)
err_ret = DB_VERIFY_BAD;
goto err;
}
- if ((ret = memp_fget(dbp->mpf, &current, 0, &h)) != 0) {
+ if ((ret = __memp_fget(mpf, &current, 0, &h)) != 0) {
err_ret = ret;
goto err;
}
@@ -2137,10 +2350,10 @@ __bam_meta2pgset(dbp, vdp, btmeta, flags, pgset)
goto err;
}
if (TYPE(h) == P_IBTREE) {
- bi = GET_BINTERNAL(h, 0);
+ bi = GET_BINTERNAL(dbp, h, 0);
current = bi->pgno;
} else { /* P_IRECNO */
- ri = GET_RINTERNAL(h, 0);
+ ri = GET_RINTERNAL(dbp, h, 0);
current = ri->pgno;
}
break;
@@ -2152,7 +2365,7 @@ __bam_meta2pgset(dbp, vdp, btmeta, flags, pgset)
goto err;
}
- if ((ret = memp_fput(dbp->mpf, h, 0)) != 0)
+ if ((ret = __memp_fput(mpf, h, 0)) != 0)
err_ret = ret;
h = NULL;
}
@@ -2164,7 +2377,7 @@ __bam_meta2pgset(dbp, vdp, btmeta, flags, pgset)
traverse:
while (IS_VALID_PGNO(current) && current != PGNO_INVALID) {
if (h == NULL &&
- (ret = memp_fget(dbp->mpf, &current, 0, &h) != 0)) {
+ (ret = __memp_fget(mpf, &current, 0, &h)) != 0) {
err_ret = ret;
break;
}
@@ -2184,13 +2397,13 @@ traverse:
goto err;
current = NEXT_PGNO(h);
- if ((ret = memp_fput(dbp->mpf, h, 0)) != 0)
+ if ((ret = __memp_fput(mpf, h, 0)) != 0)
err_ret = ret;
h = NULL;
}
err: if (h != NULL)
- (void)memp_fput(dbp->mpf, h, 0);
+ (void)__memp_fput(mpf, h, 0);
return (ret == 0 ? err_ret : ret);
}
@@ -2218,7 +2431,7 @@ __bam_safe_getdata(dbp, h, i, ovflok, dbt, freedbtp)
memset(dbt, 0, sizeof(DBT));
*freedbtp = 0;
- bk = GET_BKEYDATA(h, i);
+ bk = GET_BKEYDATA(dbp, h, i);
if (B_TYPE(bk->type) == B_OVERFLOW) {
if (!ovflok)
return (0);