Location via proxy:   [ UP ]  
[Report a bug]   [Manage cookies]                
Skip to content

Commit 06f82b2

Browse files
committed
Write an end-of-backup WAL record at pg_stop_backup(), and wait for it at
recovery instead of reading the backup history file. This is more robust, as it stops you from prematurely starting up an inconsisten cluster if the backup history file is lost for some reason, or if the base backup was never finished with pg_stop_backup(). This also paves the way for a simpler streaming replication patch, which doesn't need to care about backup history files anymore. The backup history file is still created and archived as before, but it's not used by the system anymore. It's just for informational purposes now. Bump PG_CONTROL_VERSION as the location of the backup startpoint is now written to a new field in pg_control, and catversion because initdb is required Original patch by Fujii Masao per Simon's idea, with further fixes by me.
1 parent 40608e7 commit 06f82b2

File tree

5 files changed

+128
-102
lines changed

5 files changed

+128
-102
lines changed

src/backend/access/transam/xlog.c

Lines changed: 94 additions & 94 deletions
Original file line numberDiff line numberDiff line change
@@ -7,7 +7,7 @@
77
* Portions Copyright (c) 1996-2010, PostgreSQL Global Development Group
88
* Portions Copyright (c) 1994, Regents of the University of California
99
*
10-
* $PostgreSQL: pgsql/src/backend/access/transam/xlog.c,v 1.356 2010/01/02 16:57:35 momjian Exp $
10+
* $PostgreSQL: pgsql/src/backend/access/transam/xlog.c,v 1.357 2010/01/04 12:50:49 heikki Exp $
1111
*
1212
*-------------------------------------------------------------------------
1313
*/
@@ -515,8 +515,7 @@ static void xlog_outrec(StringInfo buf, XLogRecord *record);
515515
#endif
516516
static void issue_xlog_fsync(void);
517517
static void pg_start_backup_callback(int code, Datum arg);
518-
static bool read_backup_label(XLogRecPtr *checkPointLoc,
519-
XLogRecPtr *minRecoveryLoc);
518+
static bool read_backup_label(XLogRecPtr *checkPointLoc);
520519
static void rm_redo_error_callback(void *arg);
521520
static int get_sync_bit(int method);
522521

@@ -5355,7 +5354,6 @@ StartupXLOG(void)
53555354
bool haveBackupLabel = false;
53565355
XLogRecPtr RecPtr,
53575356
checkPointLoc,
5358-
backupStopLoc,
53595357
EndOfLog;
53605358
uint32 endLogId;
53615359
uint32 endLogSeg;
@@ -5454,7 +5452,7 @@ StartupXLOG(void)
54545452
recoveryTargetTLI,
54555453
ControlFile->checkPointCopy.ThisTimeLineID)));
54565454

5457-
if (read_backup_label(&checkPointLoc, &backupStopLoc))
5455+
if (read_backup_label(&checkPointLoc))
54585456
{
54595457
/*
54605458
* When a backup_label file is present, we want to roll forward from
@@ -5597,11 +5595,23 @@ StartupXLOG(void)
55975595
ControlFile->prevCheckPoint = ControlFile->checkPoint;
55985596
ControlFile->checkPoint = checkPointLoc;
55995597
ControlFile->checkPointCopy = checkPoint;
5600-
if (backupStopLoc.xlogid != 0 || backupStopLoc.xrecoff != 0)
5598+
if (InArchiveRecovery)
5599+
{
5600+
/* initialize minRecoveryPoint if not set yet */
5601+
if (XLByteLT(ControlFile->minRecoveryPoint, checkPoint.redo))
5602+
ControlFile->minRecoveryPoint = checkPoint.redo;
5603+
}
5604+
else
56015605
{
5602-
if (XLByteLT(ControlFile->minRecoveryPoint, backupStopLoc))
5603-
ControlFile->minRecoveryPoint = backupStopLoc;
5606+
XLogRecPtr InvalidXLogRecPtr = {0, 0};
5607+
ControlFile->minRecoveryPoint = InvalidXLogRecPtr;
56045608
}
5609+
/*
5610+
* set backupStartupPoint if we're starting archive recovery from a
5611+
* base backup
5612+
*/
5613+
if (haveBackupLabel)
5614+
ControlFile->backupStartPoint = checkPoint.redo;
56055615
ControlFile->time = (pg_time_t) time(NULL);
56065616
/* No need to hold ControlFileLock yet, we aren't up far enough */
56075617
UpdateControlFile();
@@ -5703,15 +5713,9 @@ StartupXLOG(void)
57035713

57045714
InRedo = true;
57055715

5706-
if (minRecoveryPoint.xlogid == 0 && minRecoveryPoint.xrecoff == 0)
5707-
ereport(LOG,
5708-
(errmsg("redo starts at %X/%X",
5709-
ReadRecPtr.xlogid, ReadRecPtr.xrecoff)));
5710-
else
5711-
ereport(LOG,
5712-
(errmsg("redo starts at %X/%X, consistency will be reached at %X/%X",
5713-
ReadRecPtr.xlogid, ReadRecPtr.xrecoff,
5714-
minRecoveryPoint.xlogid, minRecoveryPoint.xrecoff)));
5716+
ereport(LOG,
5717+
(errmsg("redo starts at %X/%X",
5718+
ReadRecPtr.xlogid, ReadRecPtr.xrecoff)));
57155719

57165720
/*
57175721
* Let postmaster know we've started redo now, so that it can
@@ -5771,7 +5775,8 @@ StartupXLOG(void)
57715775
* Have we passed our safe starting point?
57725776
*/
57735777
if (!reachedMinRecoveryPoint &&
5774-
XLByteLE(minRecoveryPoint, EndRecPtr))
5778+
XLByteLE(minRecoveryPoint, EndRecPtr) &&
5779+
XLogRecPtrIsInvalid(ControlFile->backupStartPoint))
57755780
{
57765781
reachedMinRecoveryPoint = true;
57775782
ereport(LOG,
@@ -5877,7 +5882,9 @@ StartupXLOG(void)
58775882
* be further ahead --- ControlFile->minRecoveryPoint cannot have been
58785883
* advanced beyond the WAL we processed.
58795884
*/
5880-
if (InRecovery && XLByteLT(EndOfLog, minRecoveryPoint))
5885+
if (InArchiveRecovery &&
5886+
(XLByteLT(EndOfLog, minRecoveryPoint) ||
5887+
!XLogRecPtrIsInvalid(ControlFile->backupStartPoint)))
58815888
{
58825889
if (reachedStopPoint) /* stopped because of stop request */
58835890
ereport(FATAL,
@@ -7312,6 +7319,32 @@ xlog_redo(XLogRecPtr lsn, XLogRecord *record)
73127319
{
73137320
/* nothing to do here */
73147321
}
7322+
else if (info == XLOG_BACKUP_END)
7323+
{
7324+
XLogRecPtr startpoint;
7325+
memcpy(&startpoint, XLogRecGetData(record), sizeof(startpoint));
7326+
7327+
if (XLByteEQ(ControlFile->backupStartPoint, startpoint))
7328+
{
7329+
/*
7330+
* We have reached the end of base backup, the point where
7331+
* pg_stop_backup() was done. The data on disk is now consistent.
7332+
* Reset backupStartPoint, and update minRecoveryPoint to make
7333+
* sure we don't allow starting up at an earlier point even if
7334+
* recovery is stopped and restarted soon after this.
7335+
*/
7336+
elog(DEBUG1, "end of backup reached");
7337+
7338+
LWLockAcquire(ControlFileLock, LW_EXCLUSIVE);
7339+
7340+
if (XLByteLT(ControlFile->minRecoveryPoint, lsn))
7341+
ControlFile->minRecoveryPoint = lsn;
7342+
MemSet(&ControlFile->backupStartPoint, 0, sizeof(XLogRecPtr));
7343+
UpdateControlFile();
7344+
7345+
LWLockRelease(ControlFileLock);
7346+
}
7347+
}
73157348
}
73167349

73177350
void
@@ -7353,6 +7386,14 @@ xlog_desc(StringInfo buf, uint8 xl_info, char *rec)
73537386
{
73547387
appendStringInfo(buf, "xlog switch");
73557388
}
7389+
else if (info == XLOG_BACKUP_END)
7390+
{
7391+
XLogRecPtr startpoint;
7392+
7393+
memcpy(&startpoint, rec, sizeof(XLogRecPtr));
7394+
appendStringInfo(buf, "backup end: %X/%X",
7395+
startpoint.xlogid, startpoint.xrecoff);
7396+
}
73567397
else
73577398
appendStringInfo(buf, "UNKNOWN");
73587399
}
@@ -7688,17 +7729,22 @@ pg_start_backup_callback(int code, Datum arg)
76887729
/*
76897730
* pg_stop_backup: finish taking an on-line backup dump
76907731
*
7691-
* We remove the backup label file created by pg_start_backup, and instead
7692-
* create a backup history file in pg_xlog (whence it will immediately be
7693-
* archived). The backup history file contains the same info found in
7694-
* the label file, plus the backup-end time and WAL location.
7732+
* We write an end-of-backup WAL record, and remove the backup label file
7733+
* created by pg_start_backup, creating a backup history file in pg_xlog
7734+
* instead (whence it will immediately be archived). The backup history file
7735+
* contains the same info found in the label file, plus the backup-end time
7736+
* and WAL location. Before 8.5, the backup-end time was read from the backup
7737+
* history file at the beginning of archive recovery, but we now use the WAL
7738+
* record for that and the file is for informational and debug purposes only.
7739+
*
76957740
* Note: different from CancelBackup which just cancels online backup mode.
76967741
*/
76977742
Datum
76987743
pg_stop_backup(PG_FUNCTION_ARGS)
76997744
{
77007745
XLogRecPtr startpoint;
77017746
XLogRecPtr stoppoint;
7747+
XLogRecData rdata;
77027748
pg_time_t stamp_time;
77037749
char strfbuf[128];
77047750
char histfilepath[MAXPGPATH];
@@ -7739,22 +7785,6 @@ pg_stop_backup(PG_FUNCTION_ARGS)
77397785
XLogCtl->Insert.forcePageWrites = false;
77407786
LWLockRelease(WALInsertLock);
77417787

7742-
/*
7743-
* Force a switch to a new xlog segment file, so that the backup is valid
7744-
* as soon as archiver moves out the current segment file. We'll report
7745-
* the end address of the XLOG SWITCH record as the backup stopping point.
7746-
*/
7747-
stoppoint = RequestXLogSwitch();
7748-
7749-
XLByteToSeg(stoppoint, _logId, _logSeg);
7750-
XLogFileName(stopxlogfilename, ThisTimeLineID, _logId, _logSeg);
7751-
7752-
/* Use the log timezone here, not the session timezone */
7753-
stamp_time = (pg_time_t) time(NULL);
7754-
pg_strftime(strfbuf, sizeof(strfbuf),
7755-
"%Y-%m-%d %H:%M:%S %Z",
7756-
pg_localtime(&stamp_time, log_timezone));
7757-
77587788
/*
77597789
* Open the existing label file
77607790
*/
@@ -7782,6 +7812,30 @@ pg_stop_backup(PG_FUNCTION_ARGS)
77827812
(errcode(ERRCODE_OBJECT_NOT_IN_PREREQUISITE_STATE),
77837813
errmsg("invalid data in file \"%s\"", BACKUP_LABEL_FILE)));
77847814

7815+
/*
7816+
* Write the backup-end xlog record
7817+
*/
7818+
rdata.data = (char *) (&startpoint);
7819+
rdata.len = sizeof(startpoint);
7820+
rdata.buffer = InvalidBuffer;
7821+
rdata.next = NULL;
7822+
stoppoint = XLogInsert(RM_XLOG_ID, XLOG_BACKUP_END, &rdata);
7823+
7824+
/*
7825+
* Force a switch to a new xlog segment file, so that the backup is valid
7826+
* as soon as archiver moves out the current segment file.
7827+
*/
7828+
RequestXLogSwitch();
7829+
7830+
XLByteToSeg(stoppoint, _logId, _logSeg);
7831+
XLogFileName(stopxlogfilename, ThisTimeLineID, _logId, _logSeg);
7832+
7833+
/* Use the log timezone here, not the session timezone */
7834+
stamp_time = (pg_time_t) time(NULL);
7835+
pg_strftime(strfbuf, sizeof(strfbuf),
7836+
"%Y-%m-%d %H:%M:%S %Z",
7837+
pg_localtime(&stamp_time, log_timezone));
7838+
77857839
/*
77867840
* Write the backup history file
77877841
*/
@@ -8088,33 +8142,18 @@ pg_xlogfile_name(PG_FUNCTION_ARGS)
80888142
* later than the start of the dump, and so if we rely on it as the start
80898143
* point, we will fail to restore a consistent database state.
80908144
*
8091-
* We also attempt to retrieve the corresponding backup history file.
8092-
* If successful, set *minRecoveryLoc to constrain valid PITR stopping
8093-
* points.
8094-
*
80958145
* Returns TRUE if a backup_label was found (and fills the checkpoint
80968146
* location into *checkPointLoc); returns FALSE if not.
80978147
*/
80988148
static bool
8099-
read_backup_label(XLogRecPtr *checkPointLoc, XLogRecPtr *minRecoveryLoc)
8149+
read_backup_label(XLogRecPtr *checkPointLoc)
81008150
{
81018151
XLogRecPtr startpoint;
8102-
XLogRecPtr stoppoint;
8103-
char histfilename[MAXFNAMELEN];
8104-
char histfilepath[MAXPGPATH];
81058152
char startxlogfilename[MAXFNAMELEN];
8106-
char stopxlogfilename[MAXFNAMELEN];
81078153
TimeLineID tli;
8108-
uint32 _logId;
8109-
uint32 _logSeg;
81108154
FILE *lfp;
8111-
FILE *fp;
81128155
char ch;
81138156

8114-
/* Default is to not constrain recovery stop point */
8115-
minRecoveryLoc->xlogid = 0;
8116-
minRecoveryLoc->xrecoff = 0;
8117-
81188157
/*
81198158
* See if label file is present
81208159
*/
@@ -8152,45 +8191,6 @@ read_backup_label(XLogRecPtr *checkPointLoc, XLogRecPtr *minRecoveryLoc)
81528191
errmsg("could not read file \"%s\": %m",
81538192
BACKUP_LABEL_FILE)));
81548193

8155-
/*
8156-
* Try to retrieve the backup history file (no error if we can't)
8157-
*/
8158-
XLByteToSeg(startpoint, _logId, _logSeg);
8159-
BackupHistoryFileName(histfilename, tli, _logId, _logSeg,
8160-
startpoint.xrecoff % XLogSegSize);
8161-
8162-
if (InArchiveRecovery)
8163-
RestoreArchivedFile(histfilepath, histfilename, "RECOVERYHISTORY", 0);
8164-
else
8165-
BackupHistoryFilePath(histfilepath, tli, _logId, _logSeg,
8166-
startpoint.xrecoff % XLogSegSize);
8167-
8168-
fp = AllocateFile(histfilepath, "r");
8169-
if (fp)
8170-
{
8171-
/*
8172-
* Parse history file to identify stop point.
8173-
*/
8174-
if (fscanf(fp, "START WAL LOCATION: %X/%X (file %24s)%c",
8175-
&startpoint.xlogid, &startpoint.xrecoff, startxlogfilename,
8176-
&ch) != 4 || ch != '\n')
8177-
ereport(FATAL,
8178-
(errcode(ERRCODE_OBJECT_NOT_IN_PREREQUISITE_STATE),
8179-
errmsg("invalid data in file \"%s\"", histfilename)));
8180-
if (fscanf(fp, "STOP WAL LOCATION: %X/%X (file %24s)%c",
8181-
&stoppoint.xlogid, &stoppoint.xrecoff, stopxlogfilename,
8182-
&ch) != 4 || ch != '\n')
8183-
ereport(FATAL,
8184-
(errcode(ERRCODE_OBJECT_NOT_IN_PREREQUISITE_STATE),
8185-
errmsg("invalid data in file \"%s\"", histfilename)));
8186-
*minRecoveryLoc = stoppoint;
8187-
if (ferror(fp) || FreeFile(fp))
8188-
ereport(FATAL,
8189-
(errcode_for_file_access(),
8190-
errmsg("could not read file \"%s\": %m",
8191-
histfilepath)));
8192-
}
8193-
81948194
return true;
81958195
}
81968196

src/bin/pg_controldata/pg_controldata.c

Lines changed: 5 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -6,7 +6,7 @@
66
* copyright (c) Oliver Elphick <olly@lfix.co.uk>, 2001;
77
* licence: BSD
88
*
9-
* $PostgreSQL: pgsql/src/bin/pg_controldata/pg_controldata.c,v 1.45 2009/12/19 01:32:38 sriggs Exp $
9+
* $PostgreSQL: pgsql/src/bin/pg_controldata/pg_controldata.c,v 1.46 2010/01/04 12:50:49 heikki Exp $
1010
*/
1111
#include "postgres_fe.h"
1212

@@ -196,13 +196,16 @@ main(int argc, char *argv[])
196196
ControlFile.checkPointCopy.oldestXid);
197197
printf(_("Latest checkpoint's oldestXID's DB: %u\n"),
198198
ControlFile.checkPointCopy.oldestXidDB);
199-
printf(_("Latest checkpoint's oldestActiveXID: %u\n"),
199+
printf(_("Latest checkpoint's oldestActiveXID: %u\n"),
200200
ControlFile.checkPointCopy.oldestActiveXid);
201201
printf(_("Time of latest checkpoint: %s\n"),
202202
ckpttime_str);
203203
printf(_("Minimum recovery ending location: %X/%X\n"),
204204
ControlFile.minRecoveryPoint.xlogid,
205205
ControlFile.minRecoveryPoint.xrecoff);
206+
printf(_("Backup start location: %X/%X\n"),
207+
ControlFile.backupStartPoint.xlogid,
208+
ControlFile.backupStartPoint.xrecoff);
206209
printf(_("Maximum data alignment: %u\n"),
207210
ControlFile.maxAlign);
208211
/* we don't print floatFormat since can't say much useful about it */

src/bin/pg_resetxlog/pg_resetxlog.c

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -23,7 +23,7 @@
2323
* Portions Copyright (c) 1996-2010, PostgreSQL Global Development Group
2424
* Portions Copyright (c) 1994, Regents of the University of California
2525
*
26-
* $PostgreSQL: pgsql/src/bin/pg_resetxlog/pg_resetxlog.c,v 1.76 2010/01/02 16:57:59 momjian Exp $
26+
* $PostgreSQL: pgsql/src/bin/pg_resetxlog/pg_resetxlog.c,v 1.77 2010/01/04 12:50:49 heikki Exp $
2727
*
2828
*-------------------------------------------------------------------------
2929
*/
@@ -625,6 +625,8 @@ RewriteControlFile(void)
625625
ControlFile.prevCheckPoint.xrecoff = 0;
626626
ControlFile.minRecoveryPoint.xlogid = 0;
627627
ControlFile.minRecoveryPoint.xrecoff = 0;
628+
ControlFile.backupStartPoint.xlogid = 0;
629+
ControlFile.backupStartPoint.xrecoff = 0;
628630

629631
/* Now we can force the recorded xlog seg size to the right thing. */
630632
ControlFile.xlog_seg_size = XLogSegSize;

src/include/catalog/catversion.h

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -37,7 +37,7 @@
3737
* Portions Copyright (c) 1996-2010, PostgreSQL Global Development Group
3838
* Portions Copyright (c) 1994, Regents of the University of California
3939
*
40-
* $PostgreSQL: pgsql/src/include/catalog/catversion.h,v 1.565 2010/01/02 16:58:01 momjian Exp $
40+
* $PostgreSQL: pgsql/src/include/catalog/catversion.h,v 1.566 2010/01/04 12:50:49 heikki Exp $
4141
*
4242
*-------------------------------------------------------------------------
4343
*/
@@ -53,6 +53,6 @@
5353
*/
5454

5555
/* yyyymmddN */
56-
#define CATALOG_VERSION_NO 201001011
56+
#define CATALOG_VERSION_NO 201001041
5757

5858
#endif

0 commit comments

Comments
 (0)