Make recovery from WAL be restartable, by executing a checkpoint-like

operation every so often.  This improves the usefulness of PITR log
shipping for hot standby: formerly, if the standby server crashed, it
was necessary to restart it from the last base backup and replay all
the WAL since then.  Now it will only need to reread about the same
amount of WAL as the master server would.  The behavior might also
come in handy during a long PITR replay sequence.  Simon Riggs,
with some editorialization by Tom Lane.
This commit is contained in:
Tom Lane 2006-08-07 16:57:57 +00:00
parent 977ac90001
commit e002836913
12 changed files with 273 additions and 115 deletions

View File

@ -8,7 +8,7 @@
* Portions Copyright (c) 1994, Regents of the University of California * Portions Copyright (c) 1994, Regents of the University of California
* *
* IDENTIFICATION * IDENTIFICATION
* $PostgreSQL: pgsql/src/backend/access/gin/ginxlog.c,v 1.3 2006/07/14 14:52:16 momjian Exp $ * $PostgreSQL: pgsql/src/backend/access/gin/ginxlog.c,v 1.4 2006/08/07 16:57:56 tgl Exp $
*------------------------------------------------------------------------- *-------------------------------------------------------------------------
*/ */
#include "postgres.h" #include "postgres.h"
@ -528,7 +528,8 @@ gin_xlog_cleanup(void) {
topCtx = MemoryContextSwitchTo(opCtx); topCtx = MemoryContextSwitchTo(opCtx);
foreach(l, incomplete_splits) { foreach(l, incomplete_splits)
{
ginIncompleteSplit *split = (ginIncompleteSplit *) lfirst(l); ginIncompleteSplit *split = (ginIncompleteSplit *) lfirst(l);
ginContinueSplit( split ); ginContinueSplit( split );
MemoryContextReset( opCtx ); MemoryContextReset( opCtx );
@ -538,3 +539,10 @@ gin_xlog_cleanup(void) {
MemoryContextDelete(opCtx); MemoryContextDelete(opCtx);
} }
bool
gin_safe_restartpoint(void)
{
if (incomplete_splits)
return false;
return true;
}

View File

@ -8,7 +8,7 @@
* Portions Copyright (c) 1994, Regents of the University of California * Portions Copyright (c) 1994, Regents of the University of California
* *
* IDENTIFICATION * IDENTIFICATION
* $PostgreSQL: pgsql/src/backend/access/gist/gistxlog.c,v 1.22 2006/07/14 14:52:16 momjian Exp $ * $PostgreSQL: pgsql/src/backend/access/gist/gistxlog.c,v 1.23 2006/08/07 16:57:56 tgl Exp $
*------------------------------------------------------------------------- *-------------------------------------------------------------------------
*/ */
#include "postgres.h" #include "postgres.h"
@ -818,6 +818,14 @@ gist_xlog_cleanup(void)
MemoryContextDelete(insertCtx); MemoryContextDelete(insertCtx);
} }
bool
gist_safe_restartpoint(void)
{
if (incomplete_inserts)
return false;
return true;
}
XLogRecData * XLogRecData *
formSplitRdata(RelFileNode node, BlockNumber blkno, bool page_is_leaf, formSplitRdata(RelFileNode node, BlockNumber blkno, bool page_is_leaf,

View File

@ -8,7 +8,7 @@
* Portions Copyright (c) 1994, Regents of the University of California * Portions Copyright (c) 1994, Regents of the University of California
* *
* IDENTIFICATION * IDENTIFICATION
* $PostgreSQL: pgsql/src/backend/access/nbtree/nbtxlog.c,v 1.36 2006/07/25 19:13:00 tgl Exp $ * $PostgreSQL: pgsql/src/backend/access/nbtree/nbtxlog.c,v 1.37 2006/08/07 16:57:56 tgl Exp $
* *
*------------------------------------------------------------------------- *-------------------------------------------------------------------------
*/ */
@ -794,3 +794,11 @@ btree_xlog_cleanup(void)
} }
incomplete_splits = NIL; incomplete_splits = NIL;
} }
bool
btree_safe_restartpoint(void)
{
if (incomplete_splits)
return false;
return true;
}

View File

@ -3,7 +3,7 @@
* *
* Resource managers definition * Resource managers definition
* *
* $PostgreSQL: pgsql/src/backend/access/transam/rmgr.c,v 1.23 2006/07/11 17:26:58 momjian Exp $ * $PostgreSQL: pgsql/src/backend/access/transam/rmgr.c,v 1.24 2006/08/07 16:57:56 tgl Exp $
*/ */
#include "postgres.h" #include "postgres.h"
@ -23,20 +23,20 @@
const RmgrData RmgrTable[RM_MAX_ID + 1] = { const RmgrData RmgrTable[RM_MAX_ID + 1] = {
{"XLOG", xlog_redo, xlog_desc, NULL, NULL}, {"XLOG", xlog_redo, xlog_desc, NULL, NULL, NULL},
{"Transaction", xact_redo, xact_desc, NULL, NULL}, {"Transaction", xact_redo, xact_desc, NULL, NULL, NULL},
{"Storage", smgr_redo, smgr_desc, NULL, NULL}, {"Storage", smgr_redo, smgr_desc, NULL, NULL, NULL},
{"CLOG", clog_redo, clog_desc, NULL, NULL}, {"CLOG", clog_redo, clog_desc, NULL, NULL, NULL},
{"Database", dbase_redo, dbase_desc, NULL, NULL}, {"Database", dbase_redo, dbase_desc, NULL, NULL, NULL},
{"Tablespace", tblspc_redo, tblspc_desc, NULL, NULL}, {"Tablespace", tblspc_redo, tblspc_desc, NULL, NULL, NULL},
{"MultiXact", multixact_redo, multixact_desc, NULL, NULL}, {"MultiXact", multixact_redo, multixact_desc, NULL, NULL, NULL},
{"Reserved 7", NULL, NULL, NULL, NULL}, {"Reserved 7", NULL, NULL, NULL, NULL, NULL},
{"Reserved 8", NULL, NULL, NULL, NULL}, {"Reserved 8", NULL, NULL, NULL, NULL, NULL},
{"Reserved 9", NULL, NULL, NULL, NULL}, {"Reserved 9", NULL, NULL, NULL, NULL, NULL},
{"Heap", heap_redo, heap_desc, NULL, NULL}, {"Heap", heap_redo, heap_desc, NULL, NULL, NULL},
{"Btree", btree_redo, btree_desc, btree_xlog_startup, btree_xlog_cleanup}, {"Btree", btree_redo, btree_desc, btree_xlog_startup, btree_xlog_cleanup, btree_safe_restartpoint},
{"Hash", hash_redo, hash_desc, NULL, NULL}, {"Hash", hash_redo, hash_desc, NULL, NULL, NULL},
{"Gin", gin_redo, gin_desc, gin_xlog_startup, gin_xlog_cleanup}, {"Gin", gin_redo, gin_desc, gin_xlog_startup, gin_xlog_cleanup, gin_safe_restartpoint},
{"Gist", gist_redo, gist_desc, gist_xlog_startup, gist_xlog_cleanup}, {"Gist", gist_redo, gist_desc, gist_xlog_startup, gist_xlog_cleanup, gist_safe_restartpoint},
{"Sequence", seq_redo, seq_desc, NULL, NULL} {"Sequence", seq_redo, seq_desc, NULL, NULL, NULL}
}; };

View File

@ -7,7 +7,7 @@
* Portions Copyright (c) 1996-2006, PostgreSQL Global Development Group * Portions Copyright (c) 1996-2006, PostgreSQL Global Development Group
* Portions Copyright (c) 1994, Regents of the University of California * Portions Copyright (c) 1994, Regents of the University of California
* *
* $PostgreSQL: pgsql/src/backend/access/transam/xlog.c,v 1.246 2006/08/06 03:53:44 tgl Exp $ * $PostgreSQL: pgsql/src/backend/access/transam/xlog.c,v 1.247 2006/08/07 16:57:56 tgl Exp $
* *
*------------------------------------------------------------------------- *-------------------------------------------------------------------------
*/ */
@ -120,6 +120,7 @@
/* File path names (all relative to $PGDATA) */ /* File path names (all relative to $PGDATA) */
#define BACKUP_LABEL_FILE "backup_label" #define BACKUP_LABEL_FILE "backup_label"
#define BACKUP_LABEL_OLD "backup_label.old"
#define RECOVERY_COMMAND_FILE "recovery.conf" #define RECOVERY_COMMAND_FILE "recovery.conf"
#define RECOVERY_COMMAND_DONE "recovery.done" #define RECOVERY_COMMAND_DONE "recovery.done"
@ -185,9 +186,6 @@ static TransactionId recoveryStopXid;
static time_t recoveryStopTime; static time_t recoveryStopTime;
static bool recoveryStopAfter; static bool recoveryStopAfter;
/* constraint set by read_backup_label */
static XLogRecPtr recoveryMinXlogOffset = {0, 0};
/* /*
* During normal operation, the only timeline we care about is ThisTimeLineID. * During normal operation, the only timeline we care about is ThisTimeLineID.
* During recovery, however, things are more complicated. To simplify life * During recovery, however, things are more complicated. To simplify life
@ -463,6 +461,7 @@ static void readRecoveryCommandFile(void);
static void exitArchiveRecovery(TimeLineID endTLI, static void exitArchiveRecovery(TimeLineID endTLI,
uint32 endLogId, uint32 endLogSeg); uint32 endLogId, uint32 endLogSeg);
static bool recoveryStopsHere(XLogRecord *record, bool *includeThis); static bool recoveryStopsHere(XLogRecord *record, bool *includeThis);
static void CheckPointGuts(XLogRecPtr checkPointRedo);
static bool XLogCheckBuffer(XLogRecData *rdata, bool doPageWrites, static bool XLogCheckBuffer(XLogRecData *rdata, bool doPageWrites,
XLogRecPtr *lsn, BkpBlock *bkpb); XLogRecPtr *lsn, BkpBlock *bkpb);
@ -499,8 +498,8 @@ static void issue_xlog_fsync(void);
#ifdef WAL_DEBUG #ifdef WAL_DEBUG
static void xlog_outrec(StringInfo buf, XLogRecord *record); static void xlog_outrec(StringInfo buf, XLogRecord *record);
#endif #endif
static bool read_backup_label(XLogRecPtr *checkPointLoc); static bool read_backup_label(XLogRecPtr *checkPointLoc,
static void remove_backup_label(void); XLogRecPtr *minRecoveryLoc);
static void rm_redo_error_callback(void *arg); static void rm_redo_error_callback(void *arg);
@ -4594,9 +4593,11 @@ StartupXLOG(void)
CheckPoint checkPoint; CheckPoint checkPoint;
bool wasShutdown; bool wasShutdown;
bool needNewTimeLine = false; bool needNewTimeLine = false;
bool haveBackupLabel = false;
XLogRecPtr RecPtr, XLogRecPtr RecPtr,
LastRec, LastRec,
checkPointLoc, checkPointLoc,
minRecoveryLoc,
EndOfLog; EndOfLog;
uint32 endLogId; uint32 endLogId;
uint32 endLogSeg; uint32 endLogSeg;
@ -4629,12 +4630,18 @@ StartupXLOG(void)
ereport(LOG, ereport(LOG,
(errmsg("database system shutdown was interrupted at %s", (errmsg("database system shutdown was interrupted at %s",
str_time(ControlFile->time)))); str_time(ControlFile->time))));
else if (ControlFile->state == DB_IN_RECOVERY) else if (ControlFile->state == DB_IN_CRASH_RECOVERY)
ereport(LOG, ereport(LOG,
(errmsg("database system was interrupted while in recovery at %s", (errmsg("database system was interrupted while in recovery at %s",
str_time(ControlFile->time)), str_time(ControlFile->time)),
errhint("This probably means that some data is corrupted and" errhint("This probably means that some data is corrupted and"
" you will have to use the last backup for recovery."))); " you will have to use the last backup for recovery.")));
else if (ControlFile->state == DB_IN_ARCHIVE_RECOVERY)
ereport(LOG,
(errmsg("database system was interrupted while in recovery at log time %s",
str_time(ControlFile->checkPointCopy.time)),
errhint("If this has occurred more than once some data may be corrupted"
" and you may need to choose an earlier recovery target.")));
else if (ControlFile->state == DB_IN_PRODUCTION) else if (ControlFile->state == DB_IN_PRODUCTION)
ereport(LOG, ereport(LOG,
(errmsg("database system was interrupted at %s", (errmsg("database system was interrupted at %s",
@ -4673,7 +4680,7 @@ StartupXLOG(void)
recoveryTargetTLI, recoveryTargetTLI,
ControlFile->checkPointCopy.ThisTimeLineID))); ControlFile->checkPointCopy.ThisTimeLineID)));
if (read_backup_label(&checkPointLoc)) if (read_backup_label(&checkPointLoc, &minRecoveryLoc))
{ {
/* /*
* When a backup_label file is present, we want to roll forward from * When a backup_label file is present, we want to roll forward from
@ -4693,6 +4700,8 @@ StartupXLOG(void)
(errmsg("could not locate required checkpoint record"), (errmsg("could not locate required checkpoint record"),
errhint("If you are not restoring from a backup, try removing the file \"%s/backup_label\".", DataDir))); errhint("If you are not restoring from a backup, try removing the file \"%s/backup_label\".", DataDir)));
} }
/* set flag to delete it later */
haveBackupLabel = true;
} }
else else
{ {
@ -4790,17 +4799,51 @@ StartupXLOG(void)
{ {
int rmid; int rmid;
/*
* Update pg_control to show that we are recovering and to show
* the selected checkpoint as the place we are starting from.
* We also mark pg_control with any minimum recovery stop point
* obtained from a backup history file.
*/
if (InArchiveRecovery) if (InArchiveRecovery)
{
ereport(LOG, ereport(LOG,
(errmsg("automatic recovery in progress"))); (errmsg("automatic recovery in progress")));
ControlFile->state = DB_IN_ARCHIVE_RECOVERY;
}
else else
{
ereport(LOG, ereport(LOG,
(errmsg("database system was not properly shut down; " (errmsg("database system was not properly shut down; "
"automatic recovery in progress"))); "automatic recovery in progress")));
ControlFile->state = DB_IN_RECOVERY; ControlFile->state = DB_IN_CRASH_RECOVERY;
}
ControlFile->prevCheckPoint = ControlFile->checkPoint;
ControlFile->checkPoint = checkPointLoc;
ControlFile->checkPointCopy = checkPoint;
if (minRecoveryLoc.xlogid != 0 || minRecoveryLoc.xrecoff != 0)
ControlFile->minRecoveryPoint = minRecoveryLoc;
ControlFile->time = time(NULL); ControlFile->time = time(NULL);
UpdateControlFile(); UpdateControlFile();
/*
* If there was a backup label file, it's done its job and the
* info has now been propagated into pg_control. We must get rid of
* the label file so that if we crash during recovery, we'll pick up
* at the latest recovery restartpoint instead of going all the way
* back to the backup start point. It seems prudent though to just
* rename the file out of the way rather than delete it completely.
*/
if (haveBackupLabel)
{
unlink(BACKUP_LABEL_OLD);
if (rename(BACKUP_LABEL_FILE, BACKUP_LABEL_OLD) != 0)
ereport(FATAL,
(errcode_for_file_access(),
errmsg("could not rename file \"%s\" to \"%s\": %m",
BACKUP_LABEL_FILE, BACKUP_LABEL_OLD)));
}
/* Start up the recovery environment */ /* Start up the recovery environment */
XLogInitRelationCache(); XLogInitRelationCache();
@ -4927,7 +4970,7 @@ StartupXLOG(void)
* Complain if we did not roll forward far enough to render the backup * Complain if we did not roll forward far enough to render the backup
* dump consistent. * dump consistent.
*/ */
if (XLByteLT(EndOfLog, recoveryMinXlogOffset)) if (XLByteLT(EndOfLog, ControlFile->minRecoveryPoint))
{ {
if (needNewTimeLine) /* stopped because of stop request */ if (needNewTimeLine) /* stopped because of stop request */
ereport(FATAL, ereport(FATAL,
@ -5051,34 +5094,20 @@ StartupXLOG(void)
pgstat_reset_all(); pgstat_reset_all();
/* /*
* Perform a new checkpoint to update our recovery activity to disk. * Perform a checkpoint to update all our recovery activity to disk.
* *
* Note that we write a shutdown checkpoint rather than an on-line * Note that we write a shutdown checkpoint rather than an on-line
* one. This is not particularly critical, but since we may be * one. This is not particularly critical, but since we may be
* assigning a new TLI, using a shutdown checkpoint allows us to have * assigning a new TLI, using a shutdown checkpoint allows us to have
* the rule that TLI only changes in shutdown checkpoints, which * the rule that TLI only changes in shutdown checkpoints, which
* allows some extra error checking in xlog_redo. * allows some extra error checking in xlog_redo.
*
* In case we had to use the secondary checkpoint, make sure that it
* will still be shown as the secondary checkpoint after this
* CreateCheckPoint operation; we don't want the broken primary
* checkpoint to become prevCheckPoint...
*/ */
if (XLByteEQ(checkPointLoc, ControlFile->prevCheckPoint))
ControlFile->checkPoint = checkPointLoc;
CreateCheckPoint(true, true); CreateCheckPoint(true, true);
/* /*
* Close down recovery environment * Close down recovery environment
*/ */
XLogCloseRelationCache(); XLogCloseRelationCache();
/*
* Now that we've checkpointed the recovery, it's safe to flush old
* backup_label, if present.
*/
remove_backup_label();
} }
/* /*
@ -5464,6 +5493,10 @@ CreateCheckPoint(bool shutdown, bool force)
LWLockRelease(CheckpointStartLock); LWLockRelease(CheckpointStartLock);
if (!shutdown)
ereport(DEBUG2,
(errmsg("checkpoint starting")));
/* /*
* Get the other info we need for the checkpoint record. * Get the other info we need for the checkpoint record.
*/ */
@ -5494,16 +5527,7 @@ CreateCheckPoint(bool shutdown, bool force)
*/ */
END_CRIT_SECTION(); END_CRIT_SECTION();
if (!shutdown) CheckPointGuts(checkPoint.redo);
ereport(DEBUG2,
(errmsg("checkpoint starting")));
CheckPointCLOG();
CheckPointSUBTRANS();
CheckPointMultiXact();
FlushBufferPool();
/* We deliberately delay 2PC checkpointing as long as possible */
CheckPointTwoPhase(checkPoint.redo);
START_CRIT_SECTION(); START_CRIT_SECTION();
@ -5591,6 +5615,85 @@ CreateCheckPoint(bool shutdown, bool force)
LWLockRelease(CheckpointLock); LWLockRelease(CheckpointLock);
} }
/*
* Flush all data in shared memory to disk, and fsync
*
* This is the common code shared between regular checkpoints and
* recovery restartpoints.
*/
static void
CheckPointGuts(XLogRecPtr checkPointRedo)
{
CheckPointCLOG();
CheckPointSUBTRANS();
CheckPointMultiXact();
FlushBufferPool(); /* performs all required fsyncs */
/* We deliberately delay 2PC checkpointing as long as possible */
CheckPointTwoPhase(checkPointRedo);
}
/*
* Set a recovery restart point if appropriate
*
* This is similar to CreateCheckpoint, but is used during WAL recovery
* to establish a point from which recovery can roll forward without
* replaying the entire recovery log. This function is called each time
* a checkpoint record is read from XLOG; it must determine whether a
* restartpoint is needed or not.
*/
static void
RecoveryRestartPoint(const CheckPoint *checkPoint)
{
int elapsed_secs;
int rmid;
/*
* Do nothing if the elapsed time since the last restartpoint is less
* than half of checkpoint_timeout. (We use a value less than
* checkpoint_timeout so that variations in the timing of checkpoints on
* the master, or speed of transmission of WAL segments to a slave, won't
* make the slave skip a restartpoint once it's synced with the master.)
* Checking true elapsed time keeps us from doing restartpoints too often
* while rapidly scanning large amounts of WAL.
*/
elapsed_secs = time(NULL) - ControlFile->time;
if (elapsed_secs < CheckPointTimeout / 2)
return;
/*
* Is it safe to checkpoint? We must ask each of the resource managers
* whether they have any partial state information that might prevent a
* correct restart from this point. If so, we skip this opportunity, but
* return at the next checkpoint record for another try.
*/
for (rmid = 0; rmid <= RM_MAX_ID; rmid++)
{
if (RmgrTable[rmid].rm_safe_restartpoint != NULL)
if (!(RmgrTable[rmid].rm_safe_restartpoint()))
return;
}
/*
* OK, force data out to disk
*/
CheckPointGuts(checkPoint->redo);
/*
* Update pg_control so that any subsequent crash will restart from
* this checkpoint. Note: ReadRecPtr gives the XLOG address of the
* checkpoint record itself.
*/
ControlFile->prevCheckPoint = ControlFile->checkPoint;
ControlFile->checkPoint = ReadRecPtr;
ControlFile->checkPointCopy = *checkPoint;
ControlFile->time = time(NULL);
UpdateControlFile();
ereport(DEBUG2,
(errmsg("recovery restart point at %X/%X",
checkPoint->redo.xlogid, checkPoint->redo.xrecoff)));
}
/* /*
* Write a NEXTOID log record * Write a NEXTOID log record
*/ */
@ -5687,6 +5790,8 @@ xlog_redo(XLogRecPtr lsn, XLogRecord *record)
/* Following WAL records should be run with new TLI */ /* Following WAL records should be run with new TLI */
ThisTimeLineID = checkPoint.ThisTimeLineID; ThisTimeLineID = checkPoint.ThisTimeLineID;
} }
RecoveryRestartPoint(&checkPoint);
} }
else if (info == XLOG_CHECKPOINT_ONLINE) else if (info == XLOG_CHECKPOINT_ONLINE)
{ {
@ -5709,6 +5814,8 @@ xlog_redo(XLogRecPtr lsn, XLogRecord *record)
ereport(PANIC, ereport(PANIC,
(errmsg("unexpected timeline ID %u (should be %u) in checkpoint record", (errmsg("unexpected timeline ID %u (should be %u) in checkpoint record",
checkPoint.ThisTimeLineID, ThisTimeLineID))); checkPoint.ThisTimeLineID, ThisTimeLineID)));
RecoveryRestartPoint(&checkPoint);
} }
else if (info == XLOG_SWITCH) else if (info == XLOG_SWITCH)
{ {
@ -6349,14 +6456,14 @@ pg_xlogfile_name(PG_FUNCTION_ARGS)
* point, we will fail to restore a consistent database state. * point, we will fail to restore a consistent database state.
* *
* We also attempt to retrieve the corresponding backup history file. * We also attempt to retrieve the corresponding backup history file.
* If successful, set recoveryMinXlogOffset to constrain valid PITR stopping * If successful, set *minRecoveryLoc to constrain valid PITR stopping
* points. * points.
* *
* Returns TRUE if a backup_label was found (and fills the checkpoint * Returns TRUE if a backup_label was found (and fills the checkpoint
* location into *checkPointLoc); returns FALSE if not. * location into *checkPointLoc); returns FALSE if not.
*/ */
static bool static bool
read_backup_label(XLogRecPtr *checkPointLoc) read_backup_label(XLogRecPtr *checkPointLoc, XLogRecPtr *minRecoveryLoc)
{ {
XLogRecPtr startpoint; XLogRecPtr startpoint;
XLogRecPtr stoppoint; XLogRecPtr stoppoint;
@ -6371,6 +6478,10 @@ read_backup_label(XLogRecPtr *checkPointLoc)
FILE *fp; FILE *fp;
char ch; char ch;
/* Default is to not constrain recovery stop point */
minRecoveryLoc->xlogid = 0;
minRecoveryLoc->xrecoff = 0;
/* /*
* See if label file is present * See if label file is present
*/ */
@ -6439,7 +6550,7 @@ read_backup_label(XLogRecPtr *checkPointLoc)
ereport(FATAL, ereport(FATAL,
(errcode(ERRCODE_OBJECT_NOT_IN_PREREQUISITE_STATE), (errcode(ERRCODE_OBJECT_NOT_IN_PREREQUISITE_STATE),
errmsg("invalid data in file \"%s\"", histfilename))); errmsg("invalid data in file \"%s\"", histfilename)));
recoveryMinXlogOffset = stoppoint; *minRecoveryLoc = stoppoint;
if (ferror(fp) || FreeFile(fp)) if (ferror(fp) || FreeFile(fp))
ereport(FATAL, ereport(FATAL,
(errcode_for_file_access(), (errcode_for_file_access(),
@ -6450,24 +6561,6 @@ read_backup_label(XLogRecPtr *checkPointLoc)
return true; return true;
} }
/*
* remove_backup_label: remove any extant backup_label after successful
* recovery. Once we have completed the end-of-recovery checkpoint there
* is no reason to have to replay from the start point indicated by the
* label (and indeed we'll probably have removed/recycled the needed WAL
* segments), so remove the label to prevent trouble in later crash recoveries.
*/
static void
remove_backup_label(void)
{
if (unlink(BACKUP_LABEL_FILE) != 0)
if (errno != ENOENT)
ereport(FATAL,
(errcode_for_file_access(),
errmsg("could not remove file \"%s\": %m",
BACKUP_LABEL_FILE)));
}
/* /*
* Error context callback for errors occurring during rm_redo(). * Error context callback for errors occurring during rm_redo().
*/ */

View File

@ -6,7 +6,7 @@
* copyright (c) Oliver Elphick <olly@lfix.co.uk>, 2001; * copyright (c) Oliver Elphick <olly@lfix.co.uk>, 2001;
* licence: BSD * licence: BSD
* *
* $PostgreSQL: pgsql/src/bin/pg_controldata/pg_controldata.c,v 1.29 2006/06/07 22:24:44 momjian Exp $ * $PostgreSQL: pgsql/src/bin/pg_controldata/pg_controldata.c,v 1.30 2006/08/07 16:57:56 tgl Exp $
*/ */
#include "postgres.h" #include "postgres.h"
@ -50,8 +50,10 @@ dbState(DBState state)
return _("shut down"); return _("shut down");
case DB_SHUTDOWNING: case DB_SHUTDOWNING:
return _("shutting down"); return _("shutting down");
case DB_IN_RECOVERY: case DB_IN_CRASH_RECOVERY:
return _("in recovery"); return _("in crash recovery");
case DB_IN_ARCHIVE_RECOVERY:
return _("in archive recovery");
case DB_IN_PRODUCTION: case DB_IN_PRODUCTION:
return _("in production"); return _("in production");
} }
@ -147,40 +149,70 @@ main(int argc, char *argv[])
snprintf(sysident_str, sizeof(sysident_str), UINT64_FORMAT, snprintf(sysident_str, sizeof(sysident_str), UINT64_FORMAT,
ControlFile.system_identifier); ControlFile.system_identifier);
printf(_("pg_control version number: %u\n"), ControlFile.pg_control_version); printf(_("pg_control version number: %u\n"),
printf(_("Catalog version number: %u\n"), ControlFile.catalog_version_no); ControlFile.pg_control_version);
printf(_("Database system identifier: %s\n"), sysident_str); printf(_("Catalog version number: %u\n"),
printf(_("Database cluster state: %s\n"), dbState(ControlFile.state)); ControlFile.catalog_version_no);
printf(_("pg_control last modified: %s\n"), pgctime_str); printf(_("Database system identifier: %s\n"),
printf(_("Current log file ID: %u\n"), ControlFile.logId); sysident_str);
printf(_("Next log file segment: %u\n"), ControlFile.logSeg); printf(_("Database cluster state: %s\n"),
dbState(ControlFile.state));
printf(_("pg_control last modified: %s\n"),
pgctime_str);
printf(_("Current log file ID: %u\n"),
ControlFile.logId);
printf(_("Next log file segment: %u\n"),
ControlFile.logSeg);
printf(_("Latest checkpoint location: %X/%X\n"), printf(_("Latest checkpoint location: %X/%X\n"),
ControlFile.checkPoint.xlogid, ControlFile.checkPoint.xrecoff); ControlFile.checkPoint.xlogid,
ControlFile.checkPoint.xrecoff);
printf(_("Prior checkpoint location: %X/%X\n"), printf(_("Prior checkpoint location: %X/%X\n"),
ControlFile.prevCheckPoint.xlogid, ControlFile.prevCheckPoint.xrecoff); ControlFile.prevCheckPoint.xlogid,
ControlFile.prevCheckPoint.xrecoff);
printf(_("Latest checkpoint's REDO location: %X/%X\n"), printf(_("Latest checkpoint's REDO location: %X/%X\n"),
ControlFile.checkPointCopy.redo.xlogid, ControlFile.checkPointCopy.redo.xrecoff); ControlFile.checkPointCopy.redo.xlogid,
ControlFile.checkPointCopy.redo.xrecoff);
printf(_("Latest checkpoint's UNDO location: %X/%X\n"), printf(_("Latest checkpoint's UNDO location: %X/%X\n"),
ControlFile.checkPointCopy.undo.xlogid, ControlFile.checkPointCopy.undo.xrecoff); ControlFile.checkPointCopy.undo.xlogid,
printf(_("Latest checkpoint's TimeLineID: %u\n"), ControlFile.checkPointCopy.ThisTimeLineID); ControlFile.checkPointCopy.undo.xrecoff);
printf(_("Latest checkpoint's NextXID: %u\n"), ControlFile.checkPointCopy.nextXid); printf(_("Latest checkpoint's TimeLineID: %u\n"),
printf(_("Latest checkpoint's NextOID: %u\n"), ControlFile.checkPointCopy.nextOid); ControlFile.checkPointCopy.ThisTimeLineID);
printf(_("Latest checkpoint's NextMultiXactId: %u\n"), ControlFile.checkPointCopy.nextMulti); printf(_("Latest checkpoint's NextXID: %u\n"),
printf(_("Latest checkpoint's NextMultiOffset: %u\n"), ControlFile.checkPointCopy.nextMultiOffset); ControlFile.checkPointCopy.nextXid);
printf(_("Time of latest checkpoint: %s\n"), ckpttime_str); printf(_("Latest checkpoint's NextOID: %u\n"),
printf(_("Maximum data alignment: %u\n"), ControlFile.maxAlign); ControlFile.checkPointCopy.nextOid);
printf(_("Latest checkpoint's NextMultiXactId: %u\n"),
ControlFile.checkPointCopy.nextMulti);
printf(_("Latest checkpoint's NextMultiOffset: %u\n"),
ControlFile.checkPointCopy.nextMultiOffset);
printf(_("Time of latest checkpoint: %s\n"),
ckpttime_str);
printf(_("Minimum recovery ending location: %X/%X\n"),
ControlFile.minRecoveryPoint.xlogid,
ControlFile.minRecoveryPoint.xrecoff);
printf(_("Maximum data alignment: %u\n"),
ControlFile.maxAlign);
/* we don't print floatFormat since can't say much useful about it */ /* we don't print floatFormat since can't say much useful about it */
printf(_("Database block size: %u\n"), ControlFile.blcksz); printf(_("Database block size: %u\n"),
printf(_("Blocks per segment of large relation: %u\n"), ControlFile.relseg_size); ControlFile.blcksz);
printf(_("WAL block size: %u\n"), ControlFile.xlog_blcksz); printf(_("Blocks per segment of large relation: %u\n"),
printf(_("Bytes per WAL segment: %u\n"), ControlFile.xlog_seg_size); ControlFile.relseg_size);
printf(_("Maximum length of identifiers: %u\n"), ControlFile.nameDataLen); printf(_("WAL block size: %u\n"),
printf(_("Maximum columns in an index: %u\n"), ControlFile.indexMaxKeys); ControlFile.xlog_blcksz);
printf(_("Bytes per WAL segment: %u\n"),
ControlFile.xlog_seg_size);
printf(_("Maximum length of identifiers: %u\n"),
ControlFile.nameDataLen);
printf(_("Maximum columns in an index: %u\n"),
ControlFile.indexMaxKeys);
printf(_("Date/time type storage: %s\n"), printf(_("Date/time type storage: %s\n"),
(ControlFile.enableIntTimes ? _("64-bit integers") : _("floating-point numbers"))); (ControlFile.enableIntTimes ? _("64-bit integers") : _("floating-point numbers")));
printf(_("Maximum length of locale name: %u\n"), ControlFile.localeBuflen); printf(_("Maximum length of locale name: %u\n"),
printf(_("LC_COLLATE: %s\n"), ControlFile.lc_collate); ControlFile.localeBuflen);
printf(_("LC_CTYPE: %s\n"), ControlFile.lc_ctype); printf(_("LC_COLLATE: %s\n"),
ControlFile.lc_collate);
printf(_("LC_CTYPE: %s\n"),
ControlFile.lc_ctype);
return 0; return 0;
} }

View File

@ -23,7 +23,7 @@
* Portions Copyright (c) 1996-2006, PostgreSQL Global Development Group * Portions Copyright (c) 1996-2006, PostgreSQL Global Development Group
* Portions Copyright (c) 1994, Regents of the University of California * Portions Copyright (c) 1994, Regents of the University of California
* *
* $PostgreSQL: pgsql/src/bin/pg_resetxlog/pg_resetxlog.c,v 1.50 2006/07/14 14:52:26 momjian Exp $ * $PostgreSQL: pgsql/src/bin/pg_resetxlog/pg_resetxlog.c,v 1.51 2006/08/07 16:57:56 tgl Exp $
* *
*------------------------------------------------------------------------- *-------------------------------------------------------------------------
*/ */
@ -578,6 +578,8 @@ RewriteControlFile(void)
ControlFile.checkPoint = ControlFile.checkPointCopy.redo; ControlFile.checkPoint = ControlFile.checkPointCopy.redo;
ControlFile.prevCheckPoint.xlogid = 0; ControlFile.prevCheckPoint.xlogid = 0;
ControlFile.prevCheckPoint.xrecoff = 0; ControlFile.prevCheckPoint.xrecoff = 0;
ControlFile.minRecoveryPoint.xlogid = 0;
ControlFile.minRecoveryPoint.xrecoff = 0;
/* Contents are protected with a CRC */ /* Contents are protected with a CRC */
INIT_CRC32(ControlFile.crc); INIT_CRC32(ControlFile.crc);

View File

@ -3,7 +3,7 @@
* header file for postgres inverted index access method implementation. * header file for postgres inverted index access method implementation.
* *
* Copyright (c) 2006, PostgreSQL Global Development Group * Copyright (c) 2006, PostgreSQL Global Development Group
* $PostgreSQL: pgsql/src/include/access/gin.h,v 1.5 2006/07/11 16:55:34 teodor Exp $ * $PostgreSQL: pgsql/src/include/access/gin.h,v 1.6 2006/08/07 16:57:57 tgl Exp $
*-------------------------------------------------------------------------- *--------------------------------------------------------------------------
*/ */
@ -234,6 +234,7 @@ extern void gin_redo(XLogRecPtr lsn, XLogRecord *record);
extern void gin_desc(StringInfo buf, uint8 xl_info, char *rec); extern void gin_desc(StringInfo buf, uint8 xl_info, char *rec);
extern void gin_xlog_startup(void); extern void gin_xlog_startup(void);
extern void gin_xlog_cleanup(void); extern void gin_xlog_cleanup(void);
extern bool gin_safe_restartpoint(void);
/* ginbtree.c */ /* ginbtree.c */

View File

@ -7,7 +7,7 @@
* Portions Copyright (c) 1996-2006, PostgreSQL Global Development Group * Portions Copyright (c) 1996-2006, PostgreSQL Global Development Group
* Portions Copyright (c) 1994, Regents of the University of California * Portions Copyright (c) 1994, Regents of the University of California
* *
* $PostgreSQL: pgsql/src/include/access/gist_private.h,v 1.22 2006/07/11 21:05:57 tgl Exp $ * $PostgreSQL: pgsql/src/include/access/gist_private.h,v 1.23 2006/08/07 16:57:57 tgl Exp $
* *
*------------------------------------------------------------------------- *-------------------------------------------------------------------------
*/ */
@ -251,6 +251,7 @@ extern void gist_redo(XLogRecPtr lsn, XLogRecord *record);
extern void gist_desc(StringInfo buf, uint8 xl_info, char *rec); extern void gist_desc(StringInfo buf, uint8 xl_info, char *rec);
extern void gist_xlog_startup(void); extern void gist_xlog_startup(void);
extern void gist_xlog_cleanup(void); extern void gist_xlog_cleanup(void);
extern bool gist_safe_restartpoint(void);
extern IndexTuple gist_form_invalid_tuple(BlockNumber blkno); extern IndexTuple gist_form_invalid_tuple(BlockNumber blkno);
extern XLogRecData *formUpdateRdata(RelFileNode node, Buffer buffer, extern XLogRecData *formUpdateRdata(RelFileNode node, Buffer buffer,

View File

@ -7,7 +7,7 @@
* Portions Copyright (c) 1996-2006, PostgreSQL Global Development Group * Portions Copyright (c) 1996-2006, PostgreSQL Global Development Group
* Portions Copyright (c) 1994, Regents of the University of California * Portions Copyright (c) 1994, Regents of the University of California
* *
* $PostgreSQL: pgsql/src/include/access/nbtree.h,v 1.102 2006/07/25 19:13:00 tgl Exp $ * $PostgreSQL: pgsql/src/include/access/nbtree.h,v 1.103 2006/08/07 16:57:57 tgl Exp $
* *
*------------------------------------------------------------------------- *-------------------------------------------------------------------------
*/ */
@ -545,5 +545,6 @@ extern void btree_redo(XLogRecPtr lsn, XLogRecord *record);
extern void btree_desc(StringInfo buf, uint8 xl_info, char *rec); extern void btree_desc(StringInfo buf, uint8 xl_info, char *rec);
extern void btree_xlog_startup(void); extern void btree_xlog_startup(void);
extern void btree_xlog_cleanup(void); extern void btree_xlog_cleanup(void);
extern bool btree_safe_restartpoint(void);
#endif /* NBTREE_H */ #endif /* NBTREE_H */

View File

@ -11,7 +11,7 @@
* Portions Copyright (c) 1996-2006, PostgreSQL Global Development Group * Portions Copyright (c) 1996-2006, PostgreSQL Global Development Group
* Portions Copyright (c) 1994, Regents of the University of California * Portions Copyright (c) 1994, Regents of the University of California
* *
* $PostgreSQL: pgsql/src/include/access/xlog_internal.h,v 1.14 2006/08/06 03:53:44 tgl Exp $ * $PostgreSQL: pgsql/src/include/access/xlog_internal.h,v 1.15 2006/08/07 16:57:57 tgl Exp $
*/ */
#ifndef XLOG_INTERNAL_H #ifndef XLOG_INTERNAL_H
#define XLOG_INTERNAL_H #define XLOG_INTERNAL_H
@ -232,6 +232,7 @@ typedef struct RmgrData
void (*rm_desc) (StringInfo buf, uint8 xl_info, char *rec); void (*rm_desc) (StringInfo buf, uint8 xl_info, char *rec);
void (*rm_startup) (void); void (*rm_startup) (void);
void (*rm_cleanup) (void); void (*rm_cleanup) (void);
bool (*rm_safe_restartpoint) (void);
} RmgrData; } RmgrData;
extern const RmgrData RmgrTable[]; extern const RmgrData RmgrTable[];

View File

@ -8,7 +8,7 @@
* Portions Copyright (c) 1996-2006, PostgreSQL Global Development Group * Portions Copyright (c) 1996-2006, PostgreSQL Global Development Group
* Portions Copyright (c) 1994, Regents of the University of California * Portions Copyright (c) 1994, Regents of the University of California
* *
* $PostgreSQL: pgsql/src/include/catalog/pg_control.h,v 1.30 2006/08/06 03:53:44 tgl Exp $ * $PostgreSQL: pgsql/src/include/catalog/pg_control.h,v 1.31 2006/08/07 16:57:57 tgl Exp $
* *
*------------------------------------------------------------------------- *-------------------------------------------------------------------------
*/ */
@ -22,7 +22,7 @@
/* Version identifier for this pg_control format */ /* Version identifier for this pg_control format */
#define PG_CONTROL_VERSION 820 #define PG_CONTROL_VERSION 821
/* /*
* Body of CheckPoint XLOG records. This is declared here because we keep * Body of CheckPoint XLOG records. This is declared here because we keep
@ -56,7 +56,8 @@ typedef enum DBState
DB_STARTUP = 0, DB_STARTUP = 0,
DB_SHUTDOWNED, DB_SHUTDOWNED,
DB_SHUTDOWNING, DB_SHUTDOWNING,
DB_IN_RECOVERY, DB_IN_CRASH_RECOVERY,
DB_IN_ARCHIVE_RECOVERY,
DB_IN_PRODUCTION DB_IN_PRODUCTION
} DBState; } DBState;
@ -107,6 +108,8 @@ typedef struct ControlFileData
CheckPoint checkPointCopy; /* copy of last check point record */ CheckPoint checkPointCopy; /* copy of last check point record */
XLogRecPtr minRecoveryPoint; /* must replay xlog to here */
/* /*
* This data is used to check for hardware-architecture compatibility of * This data is used to check for hardware-architecture compatibility of
* the database and the backend executable. We need not check endianness * the database and the backend executable. We need not check endianness