aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorTom Lane <tgl@sss.pgh.pa.us>2003-04-04 00:32:57 +0000
committerTom Lane <tgl@sss.pgh.pa.us>2003-04-04 00:32:57 +0000
commit8fe728b0094e8364e82b4a58c92265c00f4a2d1b (patch)
treef9257ea3c0961f7ea7e4589c309f30a0012db020
parenta880697f097b26c196d3e0cd079a03821deac95b (diff)
downloadpostgresql-8fe728b0094e8364e82b4a58c92265c00f4a2d1b.tar.gz
postgresql-8fe728b0094e8364e82b4a58c92265c00f4a2d1b.zip
Back-patch changes to validate page header fields immediately after
reading in any page. Also back-port the zero_damaged_pages boolean that determines what to do about it.
-rw-r--r--doc/src/sgml/runtime.sgml28
-rw-r--r--src/backend/storage/buffer/bufmgr.c21
-rw-r--r--src/backend/storage/page/bufpage.c49
-rw-r--r--src/backend/utils/misc/guc.c6
-rw-r--r--src/include/storage/bufmgr.h5
-rw-r--r--src/include/storage/bufpage.h3
6 files changed, 101 insertions, 11 deletions
diff --git a/doc/src/sgml/runtime.sgml b/doc/src/sgml/runtime.sgml
index 10507b81ff0..f77ee8e035a 100644
--- a/doc/src/sgml/runtime.sgml
+++ b/doc/src/sgml/runtime.sgml
@@ -1,5 +1,5 @@
<!--
-$Header: /cvsroot/pgsql/doc/src/sgml/runtime.sgml,v 1.147.2.6 2003/01/11 05:04:26 momjian Exp $
+$Header: /cvsroot/pgsql/doc/src/sgml/runtime.sgml,v 1.147.2.7 2003/04/04 00:32:57 tgl Exp $
-->
<Chapter Id="runtime">
@@ -1525,10 +1525,10 @@ dynamic_library_path = '/usr/local/lib/postgresql:/home/my_project/lib:$libdir'
</para>
<para>
- It should be noted that the performance penalty of doing
- <function>fsync</>s is considerably less in
+ It should be noted that the performance penalty of having
+ <function>fsync</> on is considerably less in
<productname>PostgreSQL</> version 7.1 and later. If you
- previously suppressed <function>fsync</>s for performance
+ previously suppressed <function>fsync</> for performance
reasons, you may wish to reconsider your choice.
</para>
@@ -2057,6 +2057,26 @@ dynamic_library_path = '/usr/local/lib/postgresql:/home/my_project/lib:$libdir'
</listitem>
</varlistentry>
+ <varlistentry>
+ <term><varname>ZERO_DAMAGED_PAGES</varname> (<type>boolean</type>)</term>
+ <listitem>
+ <para>
+ Detection of a damaged page header normally causes
+ <productname>PostgreSQL</> to report an error, aborting the current
+ transaction. Setting <varname>zero_damaged_pages</> to true causes
+ the system to instead report a warning, zero out the damaged page,
+ and continue processing. This behavior <emphasis>will destroy data</>,
+ namely all the rows on the damaged page. But it allows you to get
+ past the error and retrieve rows from any undamaged pages that may
+ be present in the table. So it is useful for recovering data if
+ corruption has occurred due to hardware or software error. You should
+ generally not set this true until you have given up hope of recovering
+ data from the damaged page(s) of a table. The
+ default setting is off, and it can only be changed by a superuser.
+ </para>
+ </listitem>
+ </varlistentry>
+
</variablelist>
</para>
</sect2>
diff --git a/src/backend/storage/buffer/bufmgr.c b/src/backend/storage/buffer/bufmgr.c
index 6d1e52d5220..35b1db79e84 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.133 2002/09/14 19:59:20 tgl Exp $
+ * $Header: /cvsroot/pgsql/src/backend/storage/buffer/bufmgr.c,v 1.133.2.1 2003/04/04 00:32:57 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 83e0c337228..c57ebf2fbdc 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.50 2002/09/04 20:31:26 momjian Exp $
+ * $Header: /cvsroot/pgsql/src/backend/storage/page/bufpage.c,v 1.50.2.1 2003/04/04 00:32:57 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 edb5e353644..b49b36565e6 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.99.2.4 2003/01/28 18:04:13 tgl Exp $
+ * $Header: /cvsroot/pgsql/src/backend/utils/misc/guc.c,v 1.99.2.5 2003/04/04 00:32:57 tgl Exp $
*
* Copyright 2000 by PostgreSQL Global Development Group
* Written by Peter Eisentraut <peter_e@gmx.net>.
@@ -353,6 +353,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/include/storage/bufmgr.h b/src/include/storage/bufmgr.h
index 5fcc354849d..c2f970c0b6c 100644
--- a/src/include/storage/bufmgr.h
+++ b/src/include/storage/bufmgr.h
@@ -7,7 +7,7 @@
* Portions Copyright (c) 1996-2002, PostgreSQL Global Development Group
* Portions Copyright (c) 1994, Regents of the University of California
*
- * $Id: bufmgr.h,v 1.66 2002/10/22 20:00:48 petere Exp $
+ * $Id: bufmgr.h,v 1.66.2.1 2003/04/04 00:32:57 tgl Exp $
*
*-------------------------------------------------------------------------
*/
@@ -25,6 +25,9 @@ typedef void *Block;
/* in globals.c ... this duplicates miscadmin.h */
extern DLLIMPORT int NBuffers;
+/* in bufmgr.c */
+extern bool zero_damaged_pages;
+
/* in buf_init.c */
extern DLLIMPORT Block *BufferBlockPointers;
extern long *PrivateRefCount;
diff --git a/src/include/storage/bufpage.h b/src/include/storage/bufpage.h
index 159a82a0228..fc589c18f9d 100644
--- a/src/include/storage/bufpage.h
+++ b/src/include/storage/bufpage.h
@@ -7,7 +7,7 @@
* Portions Copyright (c) 1996-2002, PostgreSQL Global Development Group
* Portions Copyright (c) 1994, Regents of the University of California
*
- * $Id: bufpage.h,v 1.53 2002/09/04 20:31:45 momjian Exp $
+ * $Id: bufpage.h,v 1.53.2.1 2003/04/04 00:32:57 tgl Exp $
*
*-------------------------------------------------------------------------
*/
@@ -339,6 +339,7 @@ typedef PageHeaderData *PageHeader;
*/
extern void PageInit(Page page, Size pageSize, Size specialSize);
+extern bool PageHeaderIsValid(PageHeader page);
extern OffsetNumber PageAddItem(Page page, Item item, Size size,
OffsetNumber offsetNumber, ItemIdFlags flags);
extern Page PageGetTempPage(Page page, Size specialSize);