mirror of
https://github.com/postgres/postgres.git
synced 2025-06-16 06:01:02 +03:00
Tolerate timeline switches while "pg_basebackup -X fetch" is running.
If you take a base backup from a standby server with "pg_basebackup -X fetch", and the timeline switches while the backup is being taken, the backup used to fail with an error "requested WAL segment %s has already been removed". This is because the server-side code that sends over the required WAL files would not construct the WAL filename with the correct timeline after a switch. Fix that by using readdir() to scan pg_xlog for all the WAL segments in the range, regardless of timeline. Also, include all timeline history files in the backup, if taken with "-X fetch". That fixes another related bug: If a timeline switch happened just before the backup was initiated in a standby, the WAL segment containing the initial checkpoint record contains WAL from the older timeline too. Recovery will not accept that without a timeline history file that lists the older timeline. Backpatch to 9.2. Versions prior to that were not affected as you could not take a base backup from a standby before 9.2.
This commit is contained in:
@ -2797,18 +2797,33 @@ PreallocXlogFiles(XLogRecPtr endptr)
|
||||
}
|
||||
|
||||
/*
|
||||
* Get the segno of the latest removed or recycled WAL segment.
|
||||
* Returns 0/0 if no WAL segments have been removed since startup.
|
||||
* Throws an error if the given log segment has already been removed or
|
||||
* recycled. The caller should only pass a segment that it knows to have
|
||||
* existed while the server has been running, as this function always
|
||||
* succeeds if no WAL segments have been removed since startup.
|
||||
* 'tli' is only used in the error message.
|
||||
*/
|
||||
void
|
||||
XLogGetLastRemoved(XLogSegNo *segno)
|
||||
CheckXLogRemoved(XLogSegNo segno, TimeLineID tli)
|
||||
{
|
||||
/* use volatile pointer to prevent code rearrangement */
|
||||
volatile XLogCtlData *xlogctl = XLogCtl;
|
||||
XLogSegNo lastRemovedSegNo;
|
||||
|
||||
SpinLockAcquire(&xlogctl->info_lck);
|
||||
*segno = xlogctl->lastRemovedSegNo;
|
||||
lastRemovedSegNo = xlogctl->lastRemovedSegNo;
|
||||
SpinLockRelease(&xlogctl->info_lck);
|
||||
|
||||
if (segno <= lastRemovedSegNo)
|
||||
{
|
||||
char filename[MAXFNAMELEN];
|
||||
|
||||
XLogFileName(filename, tli, segno);
|
||||
ereport(ERROR,
|
||||
(errcode_for_file_access(),
|
||||
errmsg("requested WAL segment %s has already been removed",
|
||||
filename)));
|
||||
}
|
||||
}
|
||||
|
||||
/*
|
||||
|
Reference in New Issue
Block a user