|
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 | staticvoidissue_xlog_fsync(void); |
517 | 517 | staticvoidpg_start_backup_callback(intcode,Datumarg); |
518 | | -staticboolread_backup_label(XLogRecPtr*checkPointLoc, |
519 | | -XLogRecPtr*minRecoveryLoc); |
| 518 | +staticboolread_backup_label(XLogRecPtr*checkPointLoc); |
520 | 519 | staticvoidrm_redo_error_callback(void*arg); |
521 | 520 | staticintget_sync_bit(intmethod); |
522 | 521 |
|
@@ -5355,7 +5354,6 @@ StartupXLOG(void) |
5355 | 5354 | boolhaveBackupLabel= false; |
5356 | 5355 | XLogRecPtrRecPtr, |
5357 | 5356 | checkPointLoc, |
5358 | | -backupStopLoc, |
5359 | 5357 | EndOfLog; |
5360 | 5358 | uint32endLogId; |
5361 | 5359 | uint32endLogSeg; |
@@ -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 | +XLogRecPtrInvalidXLogRecPtr= {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 | +elseif (info==XLOG_BACKUP_END) |
| 7323 | +{ |
| 7324 | +XLogRecPtrstartpoint; |
| 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 | +elseif (info==XLOG_BACKUP_END) |
| 7390 | +{ |
| 7391 | +XLogRecPtrstartpoint; |
| 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 | XLogRecPtrstartpoint; |
7701 | 7746 | XLogRecPtrstoppoint; |
| 7747 | +XLogRecDatardata; |
7702 | 7748 | pg_time_tstamp_time; |
7703 | 7749 | charstrfbuf[128]; |
7704 | 7750 | charhistfilepath[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 | staticbool |
8099 | | -read_backup_label(XLogRecPtr*checkPointLoc,XLogRecPtr*minRecoveryLoc) |
| 8149 | +read_backup_label(XLogRecPtr*checkPointLoc) |
8100 | 8150 | { |
8101 | 8151 | XLogRecPtrstartpoint; |
8102 | | -XLogRecPtrstoppoint; |
8103 | | -charhistfilename[MAXFNAMELEN]; |
8104 | | -charhistfilepath[MAXPGPATH]; |
8105 | 8152 | charstartxlogfilename[MAXFNAMELEN]; |
8106 | | -charstopxlogfilename[MAXFNAMELEN]; |
8107 | 8153 | TimeLineIDtli; |
8108 | | -uint32_logId; |
8109 | | -uint32_logSeg; |
8110 | 8154 | FILE*lfp; |
8111 | | -FILE*fp; |
8112 | 8155 | charch; |
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 |
|
|