aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--src/backend/access/transam/xlog.c82
1 files changed, 61 insertions, 21 deletions
diff --git a/src/backend/access/transam/xlog.c b/src/backend/access/transam/xlog.c
index aaa8ef423c5..53044eb4f68 100644
--- a/src/backend/access/transam/xlog.c
+++ b/src/backend/access/transam/xlog.c
@@ -2904,12 +2904,15 @@ XLogFileInit(XLogSegNo logsegno, bool *use_existent, bool use_lock)
* srcTLI, srclog, srcseg: identify segment to be copied (could be from
* a different timeline)
*
+ * upto: how much of the source file to copy? (the rest is filled with zeros)
+ *
* Currently this is only used during recovery, and so there are no locking
* considerations. But we should be just as tense as XLogFileInit to avoid
* emplacing a bogus file.
*/
static void
-XLogFileCopy(XLogSegNo destsegno, TimeLineID srcTLI, XLogSegNo srcsegno)
+XLogFileCopy(XLogSegNo destsegno, TimeLineID srcTLI, XLogSegNo srcsegno,
+ int upto)
{
char path[MAXPGPATH];
char tmppath[MAXPGPATH];
@@ -2948,16 +2951,31 @@ XLogFileCopy(XLogSegNo destsegno, TimeLineID srcTLI, XLogSegNo srcsegno)
*/
for (nbytes = 0; nbytes < XLogSegSize; nbytes += sizeof(buffer))
{
- errno = 0;
- if ((int) read(srcfd, buffer, sizeof(buffer)) != (int) sizeof(buffer))
+ int nread;
+
+ nread = upto - nbytes;
+
+ /*
+ * The part that is not read from the source file is filled with zeros.
+ */
+ if (nread < sizeof(buffer))
+ memset(buffer, 0, sizeof(buffer));
+
+ if (nread > 0)
{
- if (errno != 0)
- ereport(ERROR,
- (errcode_for_file_access(),
- errmsg("could not read file \"%s\": %m", path)));
- else
- ereport(ERROR,
- (errmsg("not enough data in file \"%s\"", path)));
+ if (nread > sizeof(buffer))
+ nread = sizeof(buffer);
+ errno = 0;
+ if (read(srcfd, buffer, nread) != nread)
+ {
+ if (errno != 0)
+ ereport(ERROR,
+ (errcode_for_file_access(),
+ errmsg("could not read file \"%s\": %m", path)));
+ else
+ ereport(ERROR,
+ (errmsg("not enough data in file \"%s\"", path)));
+ }
}
errno = 0;
if ((int) write(fd, buffer, sizeof(buffer)) != (int) sizeof(buffer))
@@ -4960,10 +4978,15 @@ readRecoveryCommandFile(void)
* Exit archive-recovery state
*/
static void
-exitArchiveRecovery(TimeLineID endTLI, XLogSegNo endLogSegNo)
+exitArchiveRecovery(TimeLineID endTLI, XLogRecPtr endOfLog)
{
char recoveryPath[MAXPGPATH];
char xlogfname[MAXFNAMELEN];
+ XLogSegNo endLogSegNo;
+ XLogSegNo startLogSegNo;
+
+ /* we always switch to a new timeline after archive recovery */
+ Assert(endTLI != ThisTimeLineID);
/*
* We are no longer in archive recovery state.
@@ -4986,18 +5009,29 @@ exitArchiveRecovery(TimeLineID endTLI, XLogSegNo endLogSegNo)
}
/*
- * If we are establishing a new timeline, we have to copy data from the
- * last WAL segment of the old timeline to create a starting WAL segment
- * for the new timeline.
+ * Calculate the last segment on the old timeline, and the first segment
+ * on the new timeline. If the switch happens in the middle of a segment,
+ * they are the same, but if the switch happens exactly at a segment
+ * boundary, startLogSegNo will be endLogSegNo + 1.
+ */
+ XLByteToPrevSeg(endOfLog, endLogSegNo);
+ XLByteToSeg(endOfLog, startLogSegNo);
+
+ /*
+ * Initialize the starting WAL segment for the new timeline. If the switch
+ * happens in the middle of a segment, copy data from the last WAL segment
+ * of the old timeline up to the switch point, to the starting WAL segment
+ * on the new timeline.
*
* Notify the archiver that the last WAL segment of the old timeline is
* ready to copy to archival storage if its .done file doesn't exist
* (e.g., if it's the restored WAL file, it's expected to have .done file).
* Otherwise, it is not archived for a while.
*/
- if (endTLI != ThisTimeLineID)
+ if (endLogSegNo == startLogSegNo)
{
- XLogFileCopy(endLogSegNo, endTLI, endLogSegNo);
+ XLogFileCopy(startLogSegNo, endTLI, endLogSegNo,
+ endOfLog % XLOG_SEG_SIZE);
/* Create .ready file only when neither .ready nor .done files exist */
if (XLogArchivingActive())
@@ -5006,12 +5040,18 @@ exitArchiveRecovery(TimeLineID endTLI, XLogSegNo endLogSegNo)
XLogArchiveCheckDone(xlogfname);
}
}
+ else
+ {
+ bool use_existent = true;
+
+ XLogFileInit(startLogSegNo, &use_existent, true);
+ }
/*
* Let's just make real sure there are not .ready or .done flags posted
* for the new segment.
*/
- XLogFileName(xlogfname, ThisTimeLineID, endLogSegNo);
+ XLogFileName(xlogfname, ThisTimeLineID, startLogSegNo);
XLogArchiveCleanup(xlogfname);
/*
@@ -5599,7 +5639,7 @@ StartupXLOG(void)
XLogRecPtr RecPtr,
checkPointLoc,
EndOfLog;
- XLogSegNo endLogSegNo;
+ XLogSegNo startLogSegNo;
TimeLineID PrevTimeLineID;
XLogRecord *record;
TransactionId oldestActiveXID;
@@ -6586,7 +6626,7 @@ StartupXLOG(void)
*/
record = ReadRecord(xlogreader, LastRec, PANIC, false);
EndOfLog = EndRecPtr;
- XLByteToPrevSeg(EndOfLog, endLogSegNo);
+ XLByteToSeg(EndOfLog, startLogSegNo);
/*
* Complain if we did not roll forward far enough to render the backup
@@ -6687,14 +6727,14 @@ StartupXLOG(void)
* we will use that below.)
*/
if (ArchiveRecoveryRequested)
- exitArchiveRecovery(xlogreader->readPageTLI, endLogSegNo);
+ exitArchiveRecovery(xlogreader->readPageTLI, EndOfLog);
/*
* Prepare to write WAL starting at EndOfLog position, and init xlog
* buffer cache using the block containing the last record from the
* previous incarnation.
*/
- openLogSegNo = endLogSegNo;
+ openLogSegNo = startLogSegNo;
openLogFile = XLogFileOpen(openLogSegNo);
openLogOff = 0;
Insert = &XLogCtl->Insert;