mirror of
https://github.com/postgres/postgres.git
synced 2025-08-11 04:22:52 +03:00
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.
This commit is contained in:
@@ -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">
|
<Chapter Id="runtime">
|
||||||
@@ -1525,10 +1525,10 @@ dynamic_library_path = '/usr/local/lib/postgresql:/home/my_project/lib:$libdir'
|
|||||||
</para>
|
</para>
|
||||||
|
|
||||||
<para>
|
<para>
|
||||||
It should be noted that the performance penalty of doing
|
It should be noted that the performance penalty of having
|
||||||
<function>fsync</>s is considerably less in
|
<function>fsync</> on is considerably less in
|
||||||
<productname>PostgreSQL</> version 7.1 and later. If you
|
<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.
|
reasons, you may wish to reconsider your choice.
|
||||||
</para>
|
</para>
|
||||||
|
|
||||||
@@ -2057,6 +2057,26 @@ dynamic_library_path = '/usr/local/lib/postgresql:/home/my_project/lib:$libdir'
|
|||||||
</listitem>
|
</listitem>
|
||||||
</varlistentry>
|
</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>
|
</variablelist>
|
||||||
</para>
|
</para>
|
||||||
</sect2>
|
</sect2>
|
||||||
|
@@ -8,7 +8,7 @@
|
|||||||
*
|
*
|
||||||
*
|
*
|
||||||
* IDENTIFICATION
|
* 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 "miscadmin.h"
|
||||||
#include "storage/buf_internals.h"
|
#include "storage/buf_internals.h"
|
||||||
#include "storage/bufmgr.h"
|
#include "storage/bufmgr.h"
|
||||||
|
#include "storage/bufpage.h"
|
||||||
#include "storage/proc.h"
|
#include "storage/proc.h"
|
||||||
#include "storage/smgr.h"
|
#include "storage/smgr.h"
|
||||||
#include "utils/relcache.h"
|
#include "utils/relcache.h"
|
||||||
@@ -59,6 +60,10 @@
|
|||||||
(*((XLogRecPtr*) MAKE_PTR((bufHdr)->data)))
|
(*((XLogRecPtr*) MAKE_PTR((bufHdr)->data)))
|
||||||
|
|
||||||
|
|
||||||
|
/* GUC variable */
|
||||||
|
bool zero_damaged_pages = false;
|
||||||
|
|
||||||
|
|
||||||
static void WaitIO(BufferDesc *buf);
|
static void WaitIO(BufferDesc *buf);
|
||||||
static void StartBufferIO(BufferDesc *buf, bool forInput);
|
static void StartBufferIO(BufferDesc *buf, bool forInput);
|
||||||
static void TerminateBufferIO(BufferDesc *buf);
|
static void TerminateBufferIO(BufferDesc *buf);
|
||||||
@@ -217,6 +222,20 @@ ReadBufferInternal(Relation reln, BlockNumber blockNum,
|
|||||||
{
|
{
|
||||||
status = smgrread(DEFAULT_SMGR, reln, blockNum,
|
status = smgrread(DEFAULT_SMGR, reln, blockNum,
|
||||||
(char *) MAKE_PTR(bufHdr->data));
|
(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)
|
if (isLocalBuf)
|
||||||
|
@@ -8,14 +8,12 @@
|
|||||||
*
|
*
|
||||||
*
|
*
|
||||||
* IDENTIFICATION
|
* 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 "postgres.h"
|
||||||
|
|
||||||
#include <sys/file.h>
|
|
||||||
|
|
||||||
#include "storage/bufpage.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
|
* PageAddItem
|
||||||
*
|
*
|
||||||
|
@@ -5,7 +5,7 @@
|
|||||||
* command, configuration file, and command line options.
|
* command, configuration file, and command line options.
|
||||||
* See src/backend/utils/misc/README for more information.
|
* 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
|
* Copyright 2000 by PostgreSQL Global Development Group
|
||||||
* Written by Peter Eisentraut <peter_e@gmx.net>.
|
* Written by Peter Eisentraut <peter_e@gmx.net>.
|
||||||
@@ -352,6 +352,10 @@ static struct config_bool
|
|||||||
{"fsync", PGC_SIGHUP}, &enableFsync,
|
{"fsync", PGC_SIGHUP}, &enableFsync,
|
||||||
true, NULL, NULL
|
true, NULL, NULL
|
||||||
},
|
},
|
||||||
|
{
|
||||||
|
{"zero_damaged_pages", PGC_SUSET}, &zero_damaged_pages,
|
||||||
|
false, NULL, NULL
|
||||||
|
},
|
||||||
{
|
{
|
||||||
{"silent_mode", PGC_POSTMASTER}, &SilentMode,
|
{"silent_mode", PGC_POSTMASTER}, &SilentMode,
|
||||||
false, NULL, NULL
|
false, NULL, NULL
|
||||||
|
@@ -7,7 +7,7 @@
|
|||||||
* Portions Copyright (c) 1996-2002, PostgreSQL Global Development Group
|
* Portions Copyright (c) 1996-2002, PostgreSQL Global Development Group
|
||||||
* Portions Copyright (c) 1994, Regents of the University of California
|
* 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 */
|
/* in globals.c ... this duplicates miscadmin.h */
|
||||||
extern DLLIMPORT int NBuffers;
|
extern DLLIMPORT int NBuffers;
|
||||||
|
|
||||||
|
/* in bufmgr.c */
|
||||||
|
extern bool zero_damaged_pages;
|
||||||
|
|
||||||
/* in buf_init.c */
|
/* in buf_init.c */
|
||||||
extern DLLIMPORT Block *BufferBlockPointers;
|
extern DLLIMPORT Block *BufferBlockPointers;
|
||||||
extern long *PrivateRefCount;
|
extern long *PrivateRefCount;
|
||||||
|
@@ -7,7 +7,7 @@
|
|||||||
* Portions Copyright (c) 1996-2002, PostgreSQL Global Development Group
|
* Portions Copyright (c) 1996-2002, PostgreSQL Global Development Group
|
||||||
* Portions Copyright (c) 1994, Regents of the University of California
|
* 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 void PageInit(Page page, Size pageSize, Size specialSize);
|
||||||
|
extern bool PageHeaderIsValid(PageHeader page);
|
||||||
extern OffsetNumber PageAddItem(Page page, Item item, Size size,
|
extern OffsetNumber PageAddItem(Page page, Item item, Size size,
|
||||||
OffsetNumber offsetNumber, ItemIdFlags flags);
|
OffsetNumber offsetNumber, ItemIdFlags flags);
|
||||||
extern Page PageGetTempPage(Page page, Size specialSize);
|
extern Page PageGetTempPage(Page page, Size specialSize);
|
||||||
|
Reference in New Issue
Block a user