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

Reply via email to