diff options
author | Heikki Linnakangas <heikki.linnakangas@iki.fi> | 2013-01-03 19:51:00 +0200 |
---|---|---|
committer | Heikki Linnakangas <heikki.linnakangas@iki.fi> | 2013-01-03 19:51:00 +0200 |
commit | b0daba57bb50ca8bfb9d3ec886c5f86f7b3c006b (patch) | |
tree | c9725863f375620cd682650ad62ee75e66f23046 /src/backend/access/transam/xlog.c | |
parent | ee994272ca50f70b53074f0febaec97e28f83c4e (diff) | |
download | postgresql-b0daba57bb50ca8bfb9d3ec886c5f86f7b3c006b.tar.gz postgresql-b0daba57bb50ca8bfb9d3ec886c5f86f7b3c006b.zip |
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.
Diffstat (limited to 'src/backend/access/transam/xlog.c')
-rw-r--r-- | src/backend/access/transam/xlog.c | 23 |
1 files changed, 19 insertions, 4 deletions
diff --git a/src/backend/access/transam/xlog.c b/src/backend/access/transam/xlog.c index 58e139dcf5c..51a515a5552 100644 --- a/src/backend/access/transam/xlog.c +++ b/src/backend/access/transam/xlog.c @@ -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))); + } } /* |