diff options
| author | Tom Lane | 2003-03-28 20:17:13 +0000 |
|---|---|---|
| committer | Tom Lane | 2003-03-28 20:17:13 +0000 |
| commit | fd42262836be6c3fdf77cc0c774964f04acdc913 (patch) | |
| tree | f45034cde07c773e6cf56621ba0f8b7933c40bfb /src/backend | |
| parent | bb3c00ee28721258d5d74c7827663a828b9387ae (diff) | |
Add code to apply some simple sanity checks to the header fields of a
page when it's read in, per pghackers discussion around 17-Feb. Add a
GUC variable zero_damaged_pages that causes the response to be a WARNING
followed by zeroing the page, rather than the normal ERROR; this is per
Hiroshi's suggestion that there needs to be a way to get at the data
in the rest of the table.
Diffstat (limited to 'src/backend')
| -rw-r--r-- | src/backend/storage/buffer/bufmgr.c | 21 | ||||
| -rw-r--r-- | src/backend/storage/page/bufpage.c | 49 | ||||
| -rw-r--r-- | src/backend/utils/misc/guc.c | 6 | ||||
| -rw-r--r-- | src/backend/utils/misc/postgresql.conf.sample | 2 |
4 files changed, 72 insertions, 6 deletions
diff --git a/src/backend/storage/buffer/bufmgr.c b/src/backend/storage/buffer/bufmgr.c index a1abaf22c1..119cfe92b0 100644 --- a/src/backend/storage/buffer/bufmgr.c +++ b/src/backend/storage/buffer/bufmgr.c @@ -8,7 +8,7 @@ * * * IDENTIFICATION - * $Header: /cvsroot/pgsql/src/backend/storage/buffer/bufmgr.c,v 1.134 2003/02/13 05:35:11 momjian Exp $ + * $Header: /cvsroot/pgsql/src/backend/storage/buffer/bufmgr.c,v 1.135 2003/03/28 20:17:13 tgl Exp $ * *------------------------------------------------------------------------- */ @@ -49,6 +49,7 @@ #include "miscadmin.h" #include "storage/buf_internals.h" #include "storage/bufmgr.h" +#include "storage/bufpage.h" #include "storage/proc.h" #include "storage/smgr.h" #include "utils/relcache.h" @@ -59,6 +60,10 @@ (*((XLogRecPtr*) MAKE_PTR((bufHdr)->data))) +/* GUC variable */ +bool zero_damaged_pages = false; + + static void WaitIO(BufferDesc *buf); static void StartBufferIO(BufferDesc *buf, bool forInput); static void TerminateBufferIO(BufferDesc *buf); @@ -217,6 +222,20 @@ ReadBufferInternal(Relation reln, BlockNumber blockNum, { status = smgrread(DEFAULT_SMGR, reln, blockNum, (char *) MAKE_PTR(bufHdr->data)); + /* check for garbage data */ + if (status == SM_SUCCESS && + !PageHeaderIsValid((PageHeader) MAKE_PTR(bufHdr->data))) + { + if (zero_damaged_pages) + { + elog(WARNING, "Invalid page header in block %u of %s; zeroing out page", + blockNum, RelationGetRelationName(reln)); + MemSet((char *) MAKE_PTR(bufHdr->data), 0, BLCKSZ); + } + else + elog(ERROR, "Invalid page header in block %u of %s", + blockNum, RelationGetRelationName(reln)); + } } if (isLocalBuf) diff --git a/src/backend/storage/page/bufpage.c b/src/backend/storage/page/bufpage.c index fd10c2aa91..be024eb6a8 100644 --- a/src/backend/storage/page/bufpage.c +++ b/src/backend/storage/page/bufpage.c @@ -8,14 +8,12 @@ * * * IDENTIFICATION - * $Header: /cvsroot/pgsql/src/backend/storage/page/bufpage.c,v 1.51 2003/01/11 05:01:03 momjian Exp $ + * $Header: /cvsroot/pgsql/src/backend/storage/page/bufpage.c,v 1.52 2003/03/28 20:17:13 tgl Exp $ * *------------------------------------------------------------------------- */ #include "postgres.h" -#include <sys/file.h> - #include "storage/bufpage.h" @@ -48,6 +46,51 @@ PageInit(Page page, Size pageSize, Size specialSize) } +/* + * PageHeaderIsValid + * Check that the header fields of a page appear valid. + * + * This is called when a page has just been read in from disk. The idea is + * to cheaply detect trashed pages before we go nuts following bogus item + * pointers, testing invalid transaction identifiers, etc. + * + * It turns out to be necessary to allow zeroed pages here too. Even though + * this routine is *not* called when deliberately adding a page to a relation, + * there are scenarios in which a zeroed page might be found in a table. + * (Example: a backend extends a relation, then crashes before it can write + * any WAL entry about the new page. The kernel will already have the + * zeroed page in the file, and it will stay that way after restart.) So we + * allow zeroed pages here, and are careful that the page access macros + * treat such a page as empty and without free space. Eventually, VACUUM + * will clean up such a page and make it usable. + */ +bool +PageHeaderIsValid(PageHeader page) +{ + char *pagebytes; + int i; + + /* Check normal case */ + if (PageGetPageSize(page) == BLCKSZ && + PageGetPageLayoutVersion(page) == PG_PAGE_LAYOUT_VERSION && + page->pd_lower >= SizeOfPageHeaderData && + page->pd_lower <= page->pd_upper && + page->pd_upper <= page->pd_special && + page->pd_special <= BLCKSZ && + page->pd_special == MAXALIGN(page->pd_special)) + return true; + + /* Check all-zeroes case */ + pagebytes = (char *) page; + for (i = 0; i < BLCKSZ; i++) + { + if (pagebytes[i] != 0) + return false; + } + return true; +} + + /* ---------------- * PageAddItem * diff --git a/src/backend/utils/misc/guc.c b/src/backend/utils/misc/guc.c index 7c5d6d1884..89b6252779 100644 --- a/src/backend/utils/misc/guc.c +++ b/src/backend/utils/misc/guc.c @@ -5,7 +5,7 @@ * command, configuration file, and command line options. * See src/backend/utils/misc/README for more information. * - * $Header: /cvsroot/pgsql/src/backend/utils/misc/guc.c,v 1.117 2003/03/20 04:51:44 momjian Exp $ + * $Header: /cvsroot/pgsql/src/backend/utils/misc/guc.c,v 1.118 2003/03/28 20:17:13 tgl Exp $ * * Copyright 2000 by PostgreSQL Global Development Group * Written by Peter Eisentraut <peter_e@gmx.net>. @@ -358,6 +358,10 @@ static struct config_bool true, NULL, NULL }, { + {"zero_damaged_pages", PGC_SUSET}, &zero_damaged_pages, + false, NULL, NULL + }, + { {"silent_mode", PGC_POSTMASTER}, &SilentMode, false, NULL, NULL }, diff --git a/src/backend/utils/misc/postgresql.conf.sample b/src/backend/utils/misc/postgresql.conf.sample index d14e9c78db..ebf99187c6 100644 --- a/src/backend/utils/misc/postgresql.conf.sample +++ b/src/backend/utils/misc/postgresql.conf.sample @@ -213,6 +213,6 @@ #sql_inheritance = true #transform_null_equals = false #statement_timeout = 0 # 0 is disabled, in milliseconds +#zero_damaged_pages = false # set this true only for disaster recovery #db_user_namespace = false #preload_libraries = '' - |
