On Thu, Dec 24, 2009 at 1:39 PM, Fujii Masao <masao.fu...@gmail.com> wrote: > On Wed, Dec 23, 2009 at 7:50 PM, Heikki Linnakangas > <heikki.linnakan...@enterprisedb.com> wrote: >> Ok. How about writing the history file in pg_stop_backup() for >> informational purposes only. Ie. never read it, but rely on the WAL >> records instead. > > Sounds good. I'll make such change as a self-contained patch.
Done. Please see the attached patch. Design: * pg_stop_backup writes the backup-end xlog record which contains the backup starting point. * In archive recovery, the startup process doesn't mark the database as consistent until it has read the backup-end record. * A backup history file is still created as in the past, but is never used. Regards, -- Fujii Masao NIPPON TELEGRAPH AND TELEPHONE CORPORATION NTT Open Source Software Center
*** a/src/backend/access/transam/xlog.c --- b/src/backend/access/transam/xlog.c *************** *** 448,453 **** static TimeLineID lastPageTLI = 0; --- 448,454 ---- static XLogRecPtr minRecoveryPoint; /* local copy of * ControlFile->minRecoveryPoint */ static bool updateMinRecoveryPoint = true; + static bool reachedBackupEnd = false; static bool InRedo = false; *************** *** 515,522 **** 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 void rm_redo_error_callback(void *arg); static int get_sync_bit(int method); --- 516,522 ---- #endif static void issue_xlog_fsync(void); static void pg_start_backup_callback(int code, Datum arg); ! static bool read_backup_label(XLogRecPtr *checkPointLoc); static void rm_redo_error_callback(void *arg); static int get_sync_bit(int method); *************** *** 5355,5361 **** StartupXLOG(void) bool haveBackupLabel = false; XLogRecPtr RecPtr, checkPointLoc, - backupStopLoc, EndOfLog; uint32 endLogId; uint32 endLogSeg; --- 5355,5360 ---- *************** *** 5454,5460 **** StartupXLOG(void) recoveryTargetTLI, ControlFile->checkPointCopy.ThisTimeLineID))); ! if (read_backup_label(&checkPointLoc, &backupStopLoc)) { /* * When a backup_label file is present, we want to roll forward from --- 5453,5459 ---- recoveryTargetTLI, ControlFile->checkPointCopy.ThisTimeLineID))); ! if (read_backup_label(&checkPointLoc)) { /* * When a backup_label file is present, we want to roll forward from *************** *** 5597,5606 **** StartupXLOG(void) ControlFile->prevCheckPoint = ControlFile->checkPoint; ControlFile->checkPoint = checkPointLoc; ControlFile->checkPointCopy = checkPoint; ! if (backupStopLoc.xlogid != 0 || backupStopLoc.xrecoff != 0) { ! if (XLByteLT(ControlFile->minRecoveryPoint, backupStopLoc)) ! ControlFile->minRecoveryPoint = backupStopLoc; } ControlFile->time = (pg_time_t) time(NULL); /* No need to hold ControlFileLock yet, we aren't up far enough */ --- 5596,5610 ---- ControlFile->prevCheckPoint = ControlFile->checkPoint; ControlFile->checkPoint = checkPointLoc; ControlFile->checkPointCopy = checkPoint; ! if (InArchiveRecovery) ! { ! if (XLByteLT(ControlFile->minRecoveryPoint, checkPoint.redo)) ! ControlFile->minRecoveryPoint = checkPoint.redo; ! } ! else { ! XLogRecPtr InvalidXLogRecPtr = {0, 0}; ! ControlFile->minRecoveryPoint = InvalidXLogRecPtr; } ControlFile->time = (pg_time_t) time(NULL); /* No need to hold ControlFileLock yet, we aren't up far enough */ *************** *** 5703,5717 **** 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))); /* * Let postmaster know we've started redo now, so that it can --- 5707,5715 ---- InRedo = true; ! 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,5777 **** StartupXLOG(void) * Have we passed our safe starting point? */ if (!reachedMinRecoveryPoint && ! XLByteLE(minRecoveryPoint, EndRecPtr)) { reachedMinRecoveryPoint = true; ereport(LOG, --- 5769,5776 ---- * Have we passed our safe starting point? */ if (!reachedMinRecoveryPoint && ! XLByteLE(minRecoveryPoint, EndRecPtr) && ! reachedBackupEnd) { reachedMinRecoveryPoint = true; ereport(LOG, *************** *** 5877,5883 **** StartupXLOG(void) * be further ahead --- ControlFile->minRecoveryPoint cannot have been * advanced beyond the WAL we processed. */ ! if (InRecovery && XLByteLT(EndOfLog, minRecoveryPoint)) { if (reachedStopPoint) /* stopped because of stop request */ ereport(FATAL, --- 5876,5882 ---- * be further ahead --- ControlFile->minRecoveryPoint cannot have been * advanced beyond the WAL we processed. */ ! if (InArchiveRecovery && (XLByteLT(EndOfLog, minRecoveryPoint) || !reachedBackupEnd)) { if (reachedStopPoint) /* stopped because of stop request */ ereport(FATAL, *************** *** 7310,7315 **** xlog_redo(XLogRecPtr lsn, XLogRecord *record) --- 7309,7322 ---- { /* nothing to do here */ } + else if (info == XLOG_BACKUP_END) + { + XLogRecPtr startpoint; + + memcpy(&startpoint, XLogRecGetData(record), sizeof(startpoint)); + if (XLByteEQ(RedoRecPtr, startpoint)) + reachedBackupEnd = true; + } } void *************** *** 7351,7356 **** xlog_desc(StringInfo buf, uint8 xl_info, char *rec) --- 7358,7367 ---- { appendStringInfo(buf, "xlog switch"); } + else if (info == XLOG_BACKUP_END) + { + appendStringInfo(buf, "xlog backup end"); + } else appendStringInfo(buf, "UNKNOWN"); } *************** *** 7686,7695 **** 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. * Note: different from CancelBackup which just cancels online backup mode. */ Datum --- 7697,7706 ---- /* * pg_stop_backup: finish taking an on-line backup dump * ! * We remove the backup label file created by pg_start_backup, instead write ! * the backup-end xlog record and 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. * Note: different from CancelBackup which just cancels online backup mode. */ Datum *************** *** 7697,7702 **** pg_stop_backup(PG_FUNCTION_ARGS) --- 7708,7714 ---- { XLogRecPtr startpoint; XLogRecPtr stoppoint; + XLogRecData rdata; pg_time_t stamp_time; char strfbuf[128]; char histfilepath[MAXPGPATH]; *************** *** 7738,7759 **** 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"); --- 7750,7755 ---- *************** *** 7781,7786 **** pg_stop_backup(PG_FUNCTION_ARGS) --- 7777,7807 ---- 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; + 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. 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)); + + /* * Write the backup history file */ XLByteToSeg(startpoint, _logId, _logSeg); *************** *** 8086,8118 **** 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) { 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 */ --- 8107,8124 ---- * 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. * * 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 startpoint; char startxlogfilename[MAXFNAMELEN]; TimeLineID tli; FILE *lfp; char ch; /* * See if label file is present */ *************** *** 8150,8194 **** 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; } --- 8156,8161 ---- *** a/src/include/catalog/pg_control.h --- b/src/include/catalog/pg_control.h *************** *** 62,67 **** typedef struct CheckPoint --- 62,68 ---- #define XLOG_NOOP 0x20 #define XLOG_NEXTOID 0x30 #define XLOG_SWITCH 0x40 + #define XLOG_BACKUP_END 0x50 /* System status indicator */
-- Sent via pgsql-hackers mailing list (pgsql-hackers@postgresql.org) To make changes to your subscription: http://www.postgresql.org/mailpref/pgsql-hackers