On Thu, Dec 24, 2009 at 1:39 PM, Fujii Masao <[email protected]> wrote:
> On Wed, Dec 23, 2009 at 7:50 PM, Heikki Linnakangas
> <[email protected]> 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 ([email protected])
To make changes to your subscription:
http://www.postgresql.org/mailpref/pgsql-hackers