mirror of
https://github.com/postgres/postgres.git
synced 2025-07-30 11:03:19 +03:00
Make pg_receivexlog and pg_basebackup -X stream work across timeline switches.
This mirrors the changes done earlier to the server in standby mode. When receivelog reaches the end of a timeline, as reported by the server, it fetches the timeline history file of the next timeline, and restarts streaming from the new timeline by issuing a new START_STREAMING command. When pg_receivexlog crosses a timeline, it leaves the .partial suffix on the last segment on the old timeline. This helps you to tell apart a partial segment left in the directory because of a timeline switch, and a completed segment. If you just follow a single server, it won't make a difference, but it can be significant in more complicated scenarios where new WAL is still generated on the old timeline. This includes two small changes to the streaming replication protocol: First, when you reach the end of timeline while streaming, the server now sends the TLI of the next timeline in the server's history to the client. pg_receivexlog uses that as the next timeline, so that it doesn't need to parse the timeline history file like a standby server does. Second, when BASE_BACKUP command sends the begin and end WAL positions, it now also sends the timeline IDs corresponding the positions.
This commit is contained in:
@ -4930,7 +4930,7 @@ StartupXLOG(void)
|
||||
* tliSwitchPoint will throw an error if the checkpoint's timeline
|
||||
* is not in expectedTLEs at all.
|
||||
*/
|
||||
switchpoint = tliSwitchPoint(ControlFile->checkPointCopy.ThisTimeLineID, expectedTLEs);
|
||||
switchpoint = tliSwitchPoint(ControlFile->checkPointCopy.ThisTimeLineID, expectedTLEs, NULL);
|
||||
ereport(FATAL,
|
||||
(errmsg("requested timeline %u is not a child of this server's history",
|
||||
recoveryTargetTLI),
|
||||
@ -7870,16 +7870,21 @@ XLogFileNameP(TimeLineID tli, XLogSegNo segno)
|
||||
* non-exclusive backups active at the same time, and they don't conflict
|
||||
* with an exclusive backup either.
|
||||
*
|
||||
* Returns the minimum WAL position that must be present to restore from this
|
||||
* backup, and the corresponding timeline ID in *starttli_p.
|
||||
*
|
||||
* Every successfully started non-exclusive backup must be stopped by calling
|
||||
* do_pg_stop_backup() or do_pg_abort_backup().
|
||||
*/
|
||||
XLogRecPtr
|
||||
do_pg_start_backup(const char *backupidstr, bool fast, char **labelfile)
|
||||
do_pg_start_backup(const char *backupidstr, bool fast, TimeLineID *starttli_p,
|
||||
char **labelfile)
|
||||
{
|
||||
bool exclusive = (labelfile == NULL);
|
||||
bool backup_started_in_recovery = false;
|
||||
XLogRecPtr checkpointloc;
|
||||
XLogRecPtr startpoint;
|
||||
TimeLineID starttli;
|
||||
pg_time_t stamp_time;
|
||||
char strfbuf[128];
|
||||
char xlogfilename[MAXFNAMELEN];
|
||||
@ -8021,6 +8026,7 @@ do_pg_start_backup(const char *backupidstr, bool fast, char **labelfile)
|
||||
LWLockAcquire(ControlFileLock, LW_SHARED);
|
||||
checkpointloc = ControlFile->checkPoint;
|
||||
startpoint = ControlFile->checkPointCopy.redo;
|
||||
starttli = ControlFile->checkPointCopy.ThisTimeLineID;
|
||||
checkpointfpw = ControlFile->checkPointCopy.fullPageWrites;
|
||||
LWLockRelease(ControlFileLock);
|
||||
|
||||
@ -8154,6 +8160,8 @@ do_pg_start_backup(const char *backupidstr, bool fast, char **labelfile)
|
||||
/*
|
||||
* We're done. As a convenience, return the starting WAL location.
|
||||
*/
|
||||
if (starttli_p)
|
||||
*starttli_p = starttli;
|
||||
return startpoint;
|
||||
}
|
||||
|
||||
@ -8190,14 +8198,18 @@ pg_start_backup_callback(int code, Datum arg)
|
||||
|
||||
* If labelfile is NULL, this stops an exclusive backup. Otherwise this stops
|
||||
* the non-exclusive backup specified by 'labelfile'.
|
||||
*
|
||||
* Returns the last WAL position that must be present to restore from this
|
||||
* backup, and the corresponding timeline ID in *stoptli_p.
|
||||
*/
|
||||
XLogRecPtr
|
||||
do_pg_stop_backup(char *labelfile, bool waitforarchive)
|
||||
do_pg_stop_backup(char *labelfile, bool waitforarchive, TimeLineID *stoptli_p)
|
||||
{
|
||||
bool exclusive = (labelfile == NULL);
|
||||
bool backup_started_in_recovery = false;
|
||||
XLogRecPtr startpoint;
|
||||
XLogRecPtr stoppoint;
|
||||
TimeLineID stoptli;
|
||||
XLogRecData rdata;
|
||||
pg_time_t stamp_time;
|
||||
char strfbuf[128];
|
||||
@ -8401,8 +8413,11 @@ do_pg_stop_backup(char *labelfile, bool waitforarchive)
|
||||
|
||||
LWLockAcquire(ControlFileLock, LW_SHARED);
|
||||
stoppoint = ControlFile->minRecoveryPoint;
|
||||
stoptli = ControlFile->minRecoveryPointTLI;
|
||||
LWLockRelease(ControlFileLock);
|
||||
|
||||
if (stoptli_p)
|
||||
*stoptli_p = stoptli;
|
||||
return stoppoint;
|
||||
}
|
||||
|
||||
@ -8414,6 +8429,7 @@ do_pg_stop_backup(char *labelfile, bool waitforarchive)
|
||||
rdata.buffer = InvalidBuffer;
|
||||
rdata.next = NULL;
|
||||
stoppoint = XLogInsert(RM_XLOG_ID, XLOG_BACKUP_END, &rdata);
|
||||
stoptli = ThisTimeLineID;
|
||||
|
||||
/*
|
||||
* Force a switch to a new xlog segment file, so that the backup is valid
|
||||
@ -8529,6 +8545,8 @@ do_pg_stop_backup(char *labelfile, bool waitforarchive)
|
||||
/*
|
||||
* We're done. As a convenience, return the ending WAL location.
|
||||
*/
|
||||
if (stoptli_p)
|
||||
*stoptli_p = stoptli;
|
||||
return stoppoint;
|
||||
}
|
||||
|
||||
|
Reference in New Issue
Block a user