|
7 | 7 | * Portions Copyright (c) 1996-2010, PostgreSQL Global Development Group |
8 | 8 | * Portions Copyright (c) 1994, Regents of the University of California |
9 | 9 | * |
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 $ |
11 | 11 | * |
12 | 12 | *------------------------------------------------------------------------- |
13 | 13 | */ |
@@ -515,8 +515,7 @@ static void xlog_outrec(StringInfo buf, XLogRecord *record); |
515 | 515 | #endif |
516 | 516 | static void issue_xlog_fsync(void); |
517 | 517 | 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); |
520 | 519 | static void rm_redo_error_callback(void *arg); |
521 | 520 | static int get_sync_bit(int method); |
522 | 521 |
|
@@ -5355,7 +5354,6 @@ StartupXLOG(void) |
5355 | 5354 | bool haveBackupLabel = false; |
5356 | 5355 | XLogRecPtr RecPtr, |
5357 | 5356 | checkPointLoc, |
5358 | | - backupStopLoc, |
5359 | 5357 | EndOfLog; |
5360 | 5358 | uint32 endLogId; |
5361 | 5359 | uint32 endLogSeg; |
@@ -5454,7 +5452,7 @@ StartupXLOG(void) |
5454 | 5452 | recoveryTargetTLI, |
5455 | 5453 | ControlFile->checkPointCopy.ThisTimeLineID))); |
5456 | 5454 |
|
5457 | | - if (read_backup_label(&checkPointLoc, &backupStopLoc)) |
| 5455 | + if (read_backup_label(&checkPointLoc)) |
5458 | 5456 | { |
5459 | 5457 | /* |
5460 | 5458 | * When a backup_label file is present, we want to roll forward from |
@@ -5597,11 +5595,23 @@ StartupXLOG(void) |
5597 | 5595 | ControlFile->prevCheckPoint = ControlFile->checkPoint; |
5598 | 5596 | ControlFile->checkPoint = checkPointLoc; |
5599 | 5597 | 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 |
5601 | 5605 | { |
5602 | | - if (XLByteLT(ControlFile->minRecoveryPoint, backupStopLoc)) |
5603 | | - ControlFile->minRecoveryPoint = backupStopLoc; |
| 5606 | + XLogRecPtr InvalidXLogRecPtr = {0, 0}; |
| 5607 | + ControlFile->minRecoveryPoint = InvalidXLogRecPtr; |
5604 | 5608 | } |
| 5609 | + /* |
| 5610 | + * set backupStartupPoint if we're starting archive recovery from a |
| 5611 | + * base backup |
| 5612 | + */ |
| 5613 | + if (haveBackupLabel) |
| 5614 | + ControlFile->backupStartPoint = checkPoint.redo; |
5605 | 5615 | ControlFile->time = (pg_time_t) time(NULL); |
5606 | 5616 | /* No need to hold ControlFileLock yet, we aren't up far enough */ |
5607 | 5617 | UpdateControlFile(); |
@@ -5703,15 +5713,9 @@ StartupXLOG(void) |
5703 | 5713 |
|
5704 | 5714 | InRedo = true; |
5705 | 5715 |
|
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))); |
5715 | 5719 |
|
5716 | 5720 | /* |
5717 | 5721 | * Let postmaster know we've started redo now, so that it can |
@@ -5771,7 +5775,8 @@ StartupXLOG(void) |
5771 | 5775 | * Have we passed our safe starting point? |
5772 | 5776 | */ |
5773 | 5777 | if (!reachedMinRecoveryPoint && |
5774 | | - XLByteLE(minRecoveryPoint, EndRecPtr)) |
| 5778 | + XLByteLE(minRecoveryPoint, EndRecPtr) && |
| 5779 | + XLogRecPtrIsInvalid(ControlFile->backupStartPoint)) |
5775 | 5780 | { |
5776 | 5781 | reachedMinRecoveryPoint = true; |
5777 | 5782 | ereport(LOG, |
@@ -5877,7 +5882,9 @@ StartupXLOG(void) |
5877 | 5882 | * be further ahead --- ControlFile->minRecoveryPoint cannot have been |
5878 | 5883 | * advanced beyond the WAL we processed. |
5879 | 5884 | */ |
5880 | | - if (InRecovery && XLByteLT(EndOfLog, minRecoveryPoint)) |
| 5885 | + if (InArchiveRecovery && |
| 5886 | + (XLByteLT(EndOfLog, minRecoveryPoint) || |
| 5887 | + !XLogRecPtrIsInvalid(ControlFile->backupStartPoint))) |
5881 | 5888 | { |
5882 | 5889 | if (reachedStopPoint) /* stopped because of stop request */ |
5883 | 5890 | ereport(FATAL, |
@@ -7312,6 +7319,32 @@ xlog_redo(XLogRecPtr lsn, XLogRecord *record) |
7312 | 7319 | { |
7313 | 7320 | /* nothing to do here */ |
7314 | 7321 | } |
| 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 | + } |
7315 | 7348 | } |
7316 | 7349 |
|
7317 | 7350 | void |
@@ -7353,6 +7386,14 @@ xlog_desc(StringInfo buf, uint8 xl_info, char *rec) |
7353 | 7386 | { |
7354 | 7387 | appendStringInfo(buf, "xlog switch"); |
7355 | 7388 | } |
| 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 | + } |
7356 | 7397 | else |
7357 | 7398 | appendStringInfo(buf, "UNKNOWN"); |
7358 | 7399 | } |
@@ -7688,17 +7729,22 @@ pg_start_backup_callback(int code, Datum arg) |
7688 | 7729 | /* |
7689 | 7730 | * pg_stop_backup: finish taking an on-line backup dump |
7690 | 7731 | * |
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 | + * |
7695 | 7740 | * Note: different from CancelBackup which just cancels online backup mode. |
7696 | 7741 | */ |
7697 | 7742 | Datum |
7698 | 7743 | pg_stop_backup(PG_FUNCTION_ARGS) |
7699 | 7744 | { |
7700 | 7745 | XLogRecPtr startpoint; |
7701 | 7746 | XLogRecPtr stoppoint; |
| 7747 | + XLogRecData rdata; |
7702 | 7748 | pg_time_t stamp_time; |
7703 | 7749 | char strfbuf[128]; |
7704 | 7750 | char histfilepath[MAXPGPATH]; |
@@ -7739,22 +7785,6 @@ pg_stop_backup(PG_FUNCTION_ARGS) |
7739 | 7785 | XLogCtl->Insert.forcePageWrites = false; |
7740 | 7786 | LWLockRelease(WALInsertLock); |
7741 | 7787 |
|
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 | | - |
7758 | 7788 | /* |
7759 | 7789 | * Open the existing label file |
7760 | 7790 | */ |
@@ -7782,6 +7812,30 @@ pg_stop_backup(PG_FUNCTION_ARGS) |
7782 | 7812 | (errcode(ERRCODE_OBJECT_NOT_IN_PREREQUISITE_STATE), |
7783 | 7813 | errmsg("invalid data in file \"%s\"", BACKUP_LABEL_FILE))); |
7784 | 7814 |
|
| 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 | + |
7785 | 7839 | /* |
7786 | 7840 | * Write the backup history file |
7787 | 7841 | */ |
@@ -8088,33 +8142,18 @@ pg_xlogfile_name(PG_FUNCTION_ARGS) |
8088 | 8142 | * later than the start of the dump, and so if we rely on it as the start |
8089 | 8143 | * point, we will fail to restore a consistent database state. |
8090 | 8144 | * |
8091 | | - * We also attempt to retrieve the corresponding backup history file. |
8092 | | - * If successful, set *minRecoveryLoc to constrain valid PITR stopping |
8093 | | - * points. |
8094 | | - * |
8095 | 8145 | * Returns TRUE if a backup_label was found (and fills the checkpoint |
8096 | 8146 | * location into *checkPointLoc); returns FALSE if not. |
8097 | 8147 | */ |
8098 | 8148 | static bool |
8099 | | -read_backup_label(XLogRecPtr *checkPointLoc, XLogRecPtr *minRecoveryLoc) |
| 8149 | +read_backup_label(XLogRecPtr *checkPointLoc) |
8100 | 8150 | { |
8101 | 8151 | XLogRecPtr startpoint; |
8102 | | - XLogRecPtr stoppoint; |
8103 | | - char histfilename[MAXFNAMELEN]; |
8104 | | - char histfilepath[MAXPGPATH]; |
8105 | 8152 | char startxlogfilename[MAXFNAMELEN]; |
8106 | | - char stopxlogfilename[MAXFNAMELEN]; |
8107 | 8153 | TimeLineID tli; |
8108 | | - uint32 _logId; |
8109 | | - uint32 _logSeg; |
8110 | 8154 | FILE *lfp; |
8111 | | - FILE *fp; |
8112 | 8155 | char ch; |
8113 | 8156 |
|
8114 | | - /* Default is to not constrain recovery stop point */ |
8115 | | - minRecoveryLoc->xlogid = 0; |
8116 | | - minRecoveryLoc->xrecoff = 0; |
8117 | | - |
8118 | 8157 | /* |
8119 | 8158 | * See if label file is present |
8120 | 8159 | */ |
@@ -8152,45 +8191,6 @@ read_backup_label(XLogRecPtr *checkPointLoc, XLogRecPtr *minRecoveryLoc) |
8152 | 8191 | errmsg("could not read file \"%s\": %m", |
8153 | 8192 | BACKUP_LABEL_FILE))); |
8154 | 8193 |
|
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 | | - |
8194 | 8194 | return true; |
8195 | 8195 | } |
8196 | 8196 |
|
|
0 commit comments