aboutsummaryrefslogtreecommitdiff
path: root/src
diff options
context:
space:
mode:
Diffstat (limited to 'src')
-rw-r--r--src/backend/access/transam/xlog.c188
-rw-r--r--src/bin/pg_controldata/pg_controldata.c7
-rw-r--r--src/bin/pg_resetxlog/pg_resetxlog.c4
-rw-r--r--src/include/catalog/catversion.h4
-rw-r--r--src/include/catalog/pg_control.h27
5 files changed, 128 insertions, 102 deletions
diff --git a/src/backend/access/transam/xlog.c b/src/backend/access/transam/xlog.c
index c045807dc35..9a13a98cbc1 100644
--- a/src/backend/access/transam/xlog.c
+++ b/src/backend/access/transam/xlog.c
@@ -7,7 +7,7 @@
* Portions Copyright (c) 1996-2010, PostgreSQL Global Development Group
* Portions Copyright (c) 1994, Regents of the University of California
*
- * $PostgreSQL: pgsql/src/backend/access/transam/xlog.c,v 1.356 2010/01/02 16:57:35 momjian Exp $
+ * $PostgreSQL: pgsql/src/backend/access/transam/xlog.c,v 1.357 2010/01/04 12:50:49 heikki Exp $
*
*-------------------------------------------------------------------------
*/
@@ -515,8 +515,7 @@ static void xlog_outrec(StringInfo buf, XLogRecord *record);
#endif
static void issue_xlog_fsync(void);
static void pg_start_backup_callback(int code, Datum arg);
-static bool read_backup_label(XLogRecPtr *checkPointLoc,
- XLogRecPtr *minRecoveryLoc);
+static bool read_backup_label(XLogRecPtr *checkPointLoc);
static void rm_redo_error_callback(void *arg);
static int get_sync_bit(int method);
@@ -5355,7 +5354,6 @@ StartupXLOG(void)
bool haveBackupLabel = false;
XLogRecPtr RecPtr,
checkPointLoc,
- backupStopLoc,
EndOfLog;
uint32 endLogId;
uint32 endLogSeg;
@@ -5454,7 +5452,7 @@ StartupXLOG(void)
recoveryTargetTLI,
ControlFile->checkPointCopy.ThisTimeLineID)));
- if (read_backup_label(&checkPointLoc, &backupStopLoc))
+ if (read_backup_label(&checkPointLoc))
{
/*
* When a backup_label file is present, we want to roll forward from
@@ -5597,11 +5595,23 @@ StartupXLOG(void)
ControlFile->prevCheckPoint = ControlFile->checkPoint;
ControlFile->checkPoint = checkPointLoc;
ControlFile->checkPointCopy = checkPoint;
- if (backupStopLoc.xlogid != 0 || backupStopLoc.xrecoff != 0)
+ if (InArchiveRecovery)
+ {
+ /* initialize minRecoveryPoint if not set yet */
+ if (XLByteLT(ControlFile->minRecoveryPoint, checkPoint.redo))
+ ControlFile->minRecoveryPoint = checkPoint.redo;
+ }
+ else
{
- if (XLByteLT(ControlFile->minRecoveryPoint, backupStopLoc))
- ControlFile->minRecoveryPoint = backupStopLoc;
+ XLogRecPtr InvalidXLogRecPtr = {0, 0};
+ ControlFile->minRecoveryPoint = InvalidXLogRecPtr;
}
+ /*
+ * set backupStartupPoint if we're starting archive recovery from a
+ * base backup
+ */
+ if (haveBackupLabel)
+ ControlFile->backupStartPoint = checkPoint.redo;
ControlFile->time = (pg_time_t) time(NULL);
/* No need to hold ControlFileLock yet, we aren't up far enough */
UpdateControlFile();
@@ -5703,15 +5713,9 @@ StartupXLOG(void)
InRedo = true;
- if (minRecoveryPoint.xlogid == 0 && minRecoveryPoint.xrecoff == 0)
- ereport(LOG,
- (errmsg("redo starts at %X/%X",
- ReadRecPtr.xlogid, ReadRecPtr.xrecoff)));
- else
- ereport(LOG,
- (errmsg("redo starts at %X/%X, consistency will be reached at %X/%X",
- ReadRecPtr.xlogid, ReadRecPtr.xrecoff,
- minRecoveryPoint.xlogid, minRecoveryPoint.xrecoff)));
+ ereport(LOG,
+ (errmsg("redo starts at %X/%X",
+ ReadRecPtr.xlogid, ReadRecPtr.xrecoff)));
/*
* Let postmaster know we've started redo now, so that it can
@@ -5771,7 +5775,8 @@ StartupXLOG(void)
* Have we passed our safe starting point?
*/
if (!reachedMinRecoveryPoint &&
- XLByteLE(minRecoveryPoint, EndRecPtr))
+ XLByteLE(minRecoveryPoint, EndRecPtr) &&
+ XLogRecPtrIsInvalid(ControlFile->backupStartPoint))
{
reachedMinRecoveryPoint = true;
ereport(LOG,
@@ -5877,7 +5882,9 @@ StartupXLOG(void)
* be further ahead --- ControlFile->minRecoveryPoint cannot have been
* advanced beyond the WAL we processed.
*/
- if (InRecovery && XLByteLT(EndOfLog, minRecoveryPoint))
+ if (InArchiveRecovery &&
+ (XLByteLT(EndOfLog, minRecoveryPoint) ||
+ !XLogRecPtrIsInvalid(ControlFile->backupStartPoint)))
{
if (reachedStopPoint) /* stopped because of stop request */
ereport(FATAL,
@@ -7312,6 +7319,32 @@ xlog_redo(XLogRecPtr lsn, XLogRecord *record)
{
/* nothing to do here */
}
+ else if (info == XLOG_BACKUP_END)
+ {
+ XLogRecPtr startpoint;
+ memcpy(&startpoint, XLogRecGetData(record), sizeof(startpoint));
+
+ if (XLByteEQ(ControlFile->backupStartPoint, startpoint))
+ {
+ /*
+ * We have reached the end of base backup, the point where
+ * pg_stop_backup() was done. The data on disk is now consistent.
+ * Reset backupStartPoint, and update minRecoveryPoint to make
+ * sure we don't allow starting up at an earlier point even if
+ * recovery is stopped and restarted soon after this.
+ */
+ elog(DEBUG1, "end of backup reached");
+
+ LWLockAcquire(ControlFileLock, LW_EXCLUSIVE);
+
+ if (XLByteLT(ControlFile->minRecoveryPoint, lsn))
+ ControlFile->minRecoveryPoint = lsn;
+ MemSet(&ControlFile->backupStartPoint, 0, sizeof(XLogRecPtr));
+ UpdateControlFile();
+
+ LWLockRelease(ControlFileLock);
+ }
+ }
}
void
@@ -7353,6 +7386,14 @@ xlog_desc(StringInfo buf, uint8 xl_info, char *rec)
{
appendStringInfo(buf, "xlog switch");
}
+ else if (info == XLOG_BACKUP_END)
+ {
+ XLogRecPtr startpoint;
+
+ memcpy(&startpoint, rec, sizeof(XLogRecPtr));
+ appendStringInfo(buf, "backup end: %X/%X",
+ startpoint.xlogid, startpoint.xrecoff);
+ }
else
appendStringInfo(buf, "UNKNOWN");
}
@@ -7688,10 +7729,14 @@ pg_start_backup_callback(int code, Datum arg)
/*
* pg_stop_backup: finish taking an on-line backup dump
*
- * We remove the backup label file created by pg_start_backup, and instead
- * create a backup history file in pg_xlog (whence it will immediately be
- * archived). The backup history file contains the same info found in
- * the label file, plus the backup-end time and WAL location.
+ * We write an end-of-backup WAL record, and remove the backup label file
+ * created by pg_start_backup, creating a backup history file in pg_xlog
+ * instead (whence it will immediately be archived). The backup history file
+ * contains the same info found in the label file, plus the backup-end time
+ * and WAL location. Before 8.5, the backup-end time was read from the backup
+ * history file at the beginning of archive recovery, but we now use the WAL
+ * record for that and the file is for informational and debug purposes only.
+ *
* Note: different from CancelBackup which just cancels online backup mode.
*/
Datum
@@ -7699,6 +7744,7 @@ pg_stop_backup(PG_FUNCTION_ARGS)
{
XLogRecPtr startpoint;
XLogRecPtr stoppoint;
+ XLogRecData rdata;
pg_time_t stamp_time;
char strfbuf[128];
char histfilepath[MAXPGPATH];
@@ -7740,22 +7786,6 @@ pg_stop_backup(PG_FUNCTION_ARGS)
LWLockRelease(WALInsertLock);
/*
- * Force a switch to a new xlog segment file, so that the backup is valid
- * as soon as archiver moves out the current segment file. We'll report
- * the end address of the XLOG SWITCH record as the backup stopping point.
- */
- stoppoint = RequestXLogSwitch();
-
- XLByteToSeg(stoppoint, _logId, _logSeg);
- XLogFileName(stopxlogfilename, ThisTimeLineID, _logId, _logSeg);
-
- /* Use the log timezone here, not the session timezone */
- stamp_time = (pg_time_t) time(NULL);
- pg_strftime(strfbuf, sizeof(strfbuf),
- "%Y-%m-%d %H:%M:%S %Z",
- pg_localtime(&stamp_time, log_timezone));
-
- /*
* Open the existing label file
*/
lfp = AllocateFile(BACKUP_LABEL_FILE, "r");
@@ -7783,6 +7813,30 @@ pg_stop_backup(PG_FUNCTION_ARGS)
errmsg("invalid data in file \"%s\"", BACKUP_LABEL_FILE)));
/*
+ * Write the backup-end xlog record
+ */
+ rdata.data = (char *) (&startpoint);
+ rdata.len = sizeof(startpoint);
+ rdata.buffer = InvalidBuffer;
+ rdata.next = NULL;
+ stoppoint = XLogInsert(RM_XLOG_ID, XLOG_BACKUP_END, &rdata);
+
+ /*
+ * Force a switch to a new xlog segment file, so that the backup is valid
+ * as soon as archiver moves out the current segment file.
+ */
+ RequestXLogSwitch();
+
+ XLByteToSeg(stoppoint, _logId, _logSeg);
+ XLogFileName(stopxlogfilename, ThisTimeLineID, _logId, _logSeg);
+
+ /* Use the log timezone here, not the session timezone */
+ stamp_time = (pg_time_t) time(NULL);
+ pg_strftime(strfbuf, sizeof(strfbuf),
+ "%Y-%m-%d %H:%M:%S %Z",
+ pg_localtime(&stamp_time, log_timezone));
+
+ /*
* Write the backup history file
*/
XLByteToSeg(startpoint, _logId, _logSeg);
@@ -8088,33 +8142,18 @@ pg_xlogfile_name(PG_FUNCTION_ARGS)
* later than the start of the dump, and so if we rely on it as the start
* point, we will fail to restore a consistent database state.
*
- * We also attempt to retrieve the corresponding backup history file.
- * If successful, set *minRecoveryLoc to constrain valid PITR stopping
- * points.
- *
* Returns TRUE if a backup_label was found (and fills the checkpoint
* location into *checkPointLoc); returns FALSE if not.
*/
static bool
-read_backup_label(XLogRecPtr *checkPointLoc, XLogRecPtr *minRecoveryLoc)
+read_backup_label(XLogRecPtr *checkPointLoc)
{
XLogRecPtr startpoint;
- XLogRecPtr stoppoint;
- char histfilename[MAXFNAMELEN];
- char histfilepath[MAXPGPATH];
char startxlogfilename[MAXFNAMELEN];
- char stopxlogfilename[MAXFNAMELEN];
TimeLineID tli;
- uint32 _logId;
- uint32 _logSeg;
FILE *lfp;
- FILE *fp;
char ch;
- /* Default is to not constrain recovery stop point */
- minRecoveryLoc->xlogid = 0;
- minRecoveryLoc->xrecoff = 0;
-
/*
* See if label file is present
*/
@@ -8152,45 +8191,6 @@ read_backup_label(XLogRecPtr *checkPointLoc, XLogRecPtr *minRecoveryLoc)
errmsg("could not read file \"%s\": %m",
BACKUP_LABEL_FILE)));
- /*
- * Try to retrieve the backup history file (no error if we can't)
- */
- XLByteToSeg(startpoint, _logId, _logSeg);
- BackupHistoryFileName(histfilename, tli, _logId, _logSeg,
- startpoint.xrecoff % XLogSegSize);
-
- if (InArchiveRecovery)
- RestoreArchivedFile(histfilepath, histfilename, "RECOVERYHISTORY", 0);
- else
- BackupHistoryFilePath(histfilepath, tli, _logId, _logSeg,
- startpoint.xrecoff % XLogSegSize);
-
- fp = AllocateFile(histfilepath, "r");
- if (fp)
- {
- /*
- * Parse history file to identify stop point.
- */
- if (fscanf(fp, "START WAL LOCATION: %X/%X (file %24s)%c",
- &startpoint.xlogid, &startpoint.xrecoff, startxlogfilename,
- &ch) != 4 || ch != '\n')
- ereport(FATAL,
- (errcode(ERRCODE_OBJECT_NOT_IN_PREREQUISITE_STATE),
- errmsg("invalid data in file \"%s\"", histfilename)));
- if (fscanf(fp, "STOP WAL LOCATION: %X/%X (file %24s)%c",
- &stoppoint.xlogid, &stoppoint.xrecoff, stopxlogfilename,
- &ch) != 4 || ch != '\n')
- ereport(FATAL,
- (errcode(ERRCODE_OBJECT_NOT_IN_PREREQUISITE_STATE),
- errmsg("invalid data in file \"%s\"", histfilename)));
- *minRecoveryLoc = stoppoint;
- if (ferror(fp) || FreeFile(fp))
- ereport(FATAL,
- (errcode_for_file_access(),
- errmsg("could not read file \"%s\": %m",
- histfilepath)));
- }
-
return true;
}
diff --git a/src/bin/pg_controldata/pg_controldata.c b/src/bin/pg_controldata/pg_controldata.c
index 9551a1d8786..2735a6611e2 100644
--- a/src/bin/pg_controldata/pg_controldata.c
+++ b/src/bin/pg_controldata/pg_controldata.c
@@ -6,7 +6,7 @@
* copyright (c) Oliver Elphick <olly@lfix.co.uk>, 2001;
* licence: BSD
*
- * $PostgreSQL: pgsql/src/bin/pg_controldata/pg_controldata.c,v 1.45 2009/12/19 01:32:38 sriggs Exp $
+ * $PostgreSQL: pgsql/src/bin/pg_controldata/pg_controldata.c,v 1.46 2010/01/04 12:50:49 heikki Exp $
*/
#include "postgres_fe.h"
@@ -196,13 +196,16 @@ main(int argc, char *argv[])
ControlFile.checkPointCopy.oldestXid);
printf(_("Latest checkpoint's oldestXID's DB: %u\n"),
ControlFile.checkPointCopy.oldestXidDB);
- printf(_("Latest checkpoint's oldestActiveXID: %u\n"),
+ printf(_("Latest checkpoint's oldestActiveXID: %u\n"),
ControlFile.checkPointCopy.oldestActiveXid);
printf(_("Time of latest checkpoint: %s\n"),
ckpttime_str);
printf(_("Minimum recovery ending location: %X/%X\n"),
ControlFile.minRecoveryPoint.xlogid,
ControlFile.minRecoveryPoint.xrecoff);
+ printf(_("Backup start location: %X/%X\n"),
+ ControlFile.backupStartPoint.xlogid,
+ ControlFile.backupStartPoint.xrecoff);
printf(_("Maximum data alignment: %u\n"),
ControlFile.maxAlign);
/* we don't print floatFormat since can't say much useful about it */
diff --git a/src/bin/pg_resetxlog/pg_resetxlog.c b/src/bin/pg_resetxlog/pg_resetxlog.c
index 8e0ba5073dd..07ea5fd13bc 100644
--- a/src/bin/pg_resetxlog/pg_resetxlog.c
+++ b/src/bin/pg_resetxlog/pg_resetxlog.c
@@ -23,7 +23,7 @@
* Portions Copyright (c) 1996-2010, PostgreSQL Global Development Group
* Portions Copyright (c) 1994, Regents of the University of California
*
- * $PostgreSQL: pgsql/src/bin/pg_resetxlog/pg_resetxlog.c,v 1.76 2010/01/02 16:57:59 momjian Exp $
+ * $PostgreSQL: pgsql/src/bin/pg_resetxlog/pg_resetxlog.c,v 1.77 2010/01/04 12:50:49 heikki Exp $
*
*-------------------------------------------------------------------------
*/
@@ -625,6 +625,8 @@ RewriteControlFile(void)
ControlFile.prevCheckPoint.xrecoff = 0;
ControlFile.minRecoveryPoint.xlogid = 0;
ControlFile.minRecoveryPoint.xrecoff = 0;
+ ControlFile.backupStartPoint.xlogid = 0;
+ ControlFile.backupStartPoint.xrecoff = 0;
/* Now we can force the recorded xlog seg size to the right thing. */
ControlFile.xlog_seg_size = XLogSegSize;
diff --git a/src/include/catalog/catversion.h b/src/include/catalog/catversion.h
index aed93501a8a..49bb9198183 100644
--- a/src/include/catalog/catversion.h
+++ b/src/include/catalog/catversion.h
@@ -37,7 +37,7 @@
* Portions Copyright (c) 1996-2010, PostgreSQL Global Development Group
* Portions Copyright (c) 1994, Regents of the University of California
*
- * $PostgreSQL: pgsql/src/include/catalog/catversion.h,v 1.565 2010/01/02 16:58:01 momjian Exp $
+ * $PostgreSQL: pgsql/src/include/catalog/catversion.h,v 1.566 2010/01/04 12:50:49 heikki Exp $
*
*-------------------------------------------------------------------------
*/
@@ -53,6 +53,6 @@
*/
/* yyyymmddN */
-#define CATALOG_VERSION_NO 201001011
+#define CATALOG_VERSION_NO 201001041
#endif
diff --git a/src/include/catalog/pg_control.h b/src/include/catalog/pg_control.h
index 454fc23a306..bac3e2a7ee9 100644
--- a/src/include/catalog/pg_control.h
+++ b/src/include/catalog/pg_control.h
@@ -8,7 +8,7 @@
* Portions Copyright (c) 1996-2010, PostgreSQL Global Development Group
* Portions Copyright (c) 1994, Regents of the University of California
*
- * $PostgreSQL: pgsql/src/include/catalog/pg_control.h,v 1.47 2010/01/02 16:58:01 momjian Exp $
+ * $PostgreSQL: pgsql/src/include/catalog/pg_control.h,v 1.48 2010/01/04 12:50:50 heikki Exp $
*
*-------------------------------------------------------------------------
*/
@@ -21,7 +21,7 @@
/* Version identifier for this pg_control format */
-#define PG_CONTROL_VERSION 852
+#define PG_CONTROL_VERSION 853
/*
* Body of CheckPoint XLOG records. This is declared here because we keep
@@ -62,6 +62,7 @@ typedef struct CheckPoint
#define XLOG_NOOP 0x20
#define XLOG_NEXTOID 0x30
#define XLOG_SWITCH 0x40
+#define XLOG_BACKUP_END 0x50
/* System status indicator */
@@ -117,7 +118,27 @@ typedef struct ControlFileData
CheckPoint checkPointCopy; /* copy of last check point record */
- XLogRecPtr minRecoveryPoint; /* must replay xlog to here */
+ /*
+ * These two values determine the minimum point we must recover up to
+ * before starting up:
+ *
+ * minRecoveryPoint is updated to the latest replayed LSN whenever we
+ * flush a data change during archive recovery. That guards against
+ * starting archive recovery, aborting it, and restarting with an earlier
+ * stop location. If we've already flushed data changes from WAL record X
+ * to disk, we mustn't start up until we reach X again. Zero when not
+ * doing archive recovery.
+ *
+ * backupStartPoint is the redo pointer of the backup start checkpoint, if
+ * we are recovering from an online backup and haven't reached the end of
+ * backup yet. It is reset to zero when the end of backup is reached, and
+ * we mustn't start up before that. A boolean would suffice otherwise, but
+ * we use the redo pointer as a cross-check when we see an end-of-backup
+ * record, to make sure the end-of-backup record corresponds the base
+ * backup we're recovering from.
+ */
+ XLogRecPtr minRecoveryPoint;
+ XLogRecPtr backupStartPoint;
/*
* This data is used to check for hardware-architecture compatibility of