Skip to content

Commit ba94518

Browse files
committed
Change how first WAL segment on new timeline after promotion is created.
Two changes: 1. When copying a WAL segment from old timeline to create the first segment on the new timeline, only copy up to the point where the timeline switch happens, and zero-fill the rest. This avoids corner cases where we might think that the copied WAL from the previous timeline belong to the new timeline. 2. If the timeline switch happens at a segment boundary, don't copy the whole old segment to the new timeline. It's pointless, because it's 100% identical to the old segment.
1 parent 38628db commit ba94518

File tree

1 file changed

+61
-21
lines changed
  • src/backend/access/transam

1 file changed

+61
-21
lines changed

src/backend/access/transam/xlog.c

+61-21
Original file line numberDiff line numberDiff line change
@@ -2904,12 +2904,15 @@ XLogFileInit(XLogSegNo logsegno, bool *use_existent, bool use_lock)
29042904
* srcTLI, srclog, srcseg: identify segment to be copied (could be from
29052905
* a different timeline)
29062906
*
2907+
* upto: how much of the source file to copy? (the rest is filled with zeros)
2908+
*
29072909
* Currently this is only used during recovery, and so there are no locking
29082910
* considerations. But we should be just as tense as XLogFileInit to avoid
29092911
* emplacing a bogus file.
29102912
*/
29112913
static void
2912-
XLogFileCopy(XLogSegNo destsegno, TimeLineID srcTLI, XLogSegNo srcsegno)
2914+
XLogFileCopy(XLogSegNo destsegno, TimeLineID srcTLI, XLogSegNo srcsegno,
2915+
int upto)
29132916
{
29142917
char path[MAXPGPATH];
29152918
char tmppath[MAXPGPATH];
@@ -2948,16 +2951,31 @@ XLogFileCopy(XLogSegNo destsegno, TimeLineID srcTLI, XLogSegNo srcsegno)
29482951
*/
29492952
for (nbytes = 0; nbytes < XLogSegSize; nbytes += sizeof(buffer))
29502953
{
2951-
errno = 0;
2952-
if ((int) read(srcfd, buffer, sizeof(buffer)) != (int) sizeof(buffer))
2954+
int nread;
2955+
2956+
nread = upto - nbytes;
2957+
2958+
/*
2959+
* The part that is not read from the source file is filled with zeros.
2960+
*/
2961+
if (nread < sizeof(buffer))
2962+
memset(buffer, 0, sizeof(buffer));
2963+
2964+
if (nread > 0)
29532965
{
2954-
if (errno != 0)
2955-
ereport(ERROR,
2956-
(errcode_for_file_access(),
2957-
errmsg("could not read file \"%s\": %m", path)));
2958-
else
2959-
ereport(ERROR,
2960-
(errmsg("not enough data in file \"%s\"", path)));
2966+
if (nread > sizeof(buffer))
2967+
nread = sizeof(buffer);
2968+
errno = 0;
2969+
if (read(srcfd, buffer, nread) != nread)
2970+
{
2971+
if (errno != 0)
2972+
ereport(ERROR,
2973+
(errcode_for_file_access(),
2974+
errmsg("could not read file \"%s\": %m", path)));
2975+
else
2976+
ereport(ERROR,
2977+
(errmsg("not enough data in file \"%s\"", path)));
2978+
}
29612979
}
29622980
errno = 0;
29632981
if ((int) write(fd, buffer, sizeof(buffer)) != (int) sizeof(buffer))
@@ -4960,10 +4978,15 @@ readRecoveryCommandFile(void)
49604978
* Exit archive-recovery state
49614979
*/
49624980
static void
4963-
exitArchiveRecovery(TimeLineID endTLI, XLogSegNo endLogSegNo)
4981+
exitArchiveRecovery(TimeLineID endTLI, XLogRecPtr endOfLog)
49644982
{
49654983
char recoveryPath[MAXPGPATH];
49664984
char xlogfname[MAXFNAMELEN];
4985+
XLogSegNo endLogSegNo;
4986+
XLogSegNo startLogSegNo;
4987+
4988+
/* we always switch to a new timeline after archive recovery */
4989+
Assert(endTLI != ThisTimeLineID);
49674990

49684991
/*
49694992
* We are no longer in archive recovery state.
@@ -4986,18 +5009,29 @@ exitArchiveRecovery(TimeLineID endTLI, XLogSegNo endLogSegNo)
49865009
}
49875010

49885011
/*
4989-
* If we are establishing a new timeline, we have to copy data from the
4990-
* last WAL segment of the old timeline to create a starting WAL segment
4991-
* for the new timeline.
5012+
* Calculate the last segment on the old timeline, and the first segment
5013+
* on the new timeline. If the switch happens in the middle of a segment,
5014+
* they are the same, but if the switch happens exactly at a segment
5015+
* boundary, startLogSegNo will be endLogSegNo + 1.
5016+
*/
5017+
XLByteToPrevSeg(endOfLog, endLogSegNo);
5018+
XLByteToSeg(endOfLog, startLogSegNo);
5019+
5020+
/*
5021+
* Initialize the starting WAL segment for the new timeline. If the switch
5022+
* happens in the middle of a segment, copy data from the last WAL segment
5023+
* of the old timeline up to the switch point, to the starting WAL segment
5024+
* on the new timeline.
49925025
*
49935026
* Notify the archiver that the last WAL segment of the old timeline is
49945027
* ready to copy to archival storage if its .done file doesn't exist
49955028
* (e.g., if it's the restored WAL file, it's expected to have .done file).
49965029
* Otherwise, it is not archived for a while.
49975030
*/
4998-
if (endTLI != ThisTimeLineID)
5031+
if (endLogSegNo == startLogSegNo)
49995032
{
5000-
XLogFileCopy(endLogSegNo, endTLI, endLogSegNo);
5033+
XLogFileCopy(startLogSegNo, endTLI, endLogSegNo,
5034+
endOfLog % XLOG_SEG_SIZE);
50015035

50025036
/* Create .ready file only when neither .ready nor .done files exist */
50035037
if (XLogArchivingActive())
@@ -5006,12 +5040,18 @@ exitArchiveRecovery(TimeLineID endTLI, XLogSegNo endLogSegNo)
50065040
XLogArchiveCheckDone(xlogfname);
50075041
}
50085042
}
5043+
else
5044+
{
5045+
bool use_existent = true;
5046+
5047+
XLogFileInit(startLogSegNo, &use_existent, true);
5048+
}
50095049

50105050
/*
50115051
* Let's just make real sure there are not .ready or .done flags posted
50125052
* for the new segment.
50135053
*/
5014-
XLogFileName(xlogfname, ThisTimeLineID, endLogSegNo);
5054+
XLogFileName(xlogfname, ThisTimeLineID, startLogSegNo);
50155055
XLogArchiveCleanup(xlogfname);
50165056

50175057
/*
@@ -5599,7 +5639,7 @@ StartupXLOG(void)
55995639
XLogRecPtr RecPtr,
56005640
checkPointLoc,
56015641
EndOfLog;
5602-
XLogSegNo endLogSegNo;
5642+
XLogSegNo startLogSegNo;
56035643
TimeLineID PrevTimeLineID;
56045644
XLogRecord *record;
56055645
TransactionId oldestActiveXID;
@@ -6586,7 +6626,7 @@ StartupXLOG(void)
65866626
*/
65876627
record = ReadRecord(xlogreader, LastRec, PANIC, false);
65886628
EndOfLog = EndRecPtr;
6589-
XLByteToPrevSeg(EndOfLog, endLogSegNo);
6629+
XLByteToSeg(EndOfLog, startLogSegNo);
65906630

65916631
/*
65926632
* Complain if we did not roll forward far enough to render the backup
@@ -6687,14 +6727,14 @@ StartupXLOG(void)
66876727
* we will use that below.)
66886728
*/
66896729
if (ArchiveRecoveryRequested)
6690-
exitArchiveRecovery(xlogreader->readPageTLI, endLogSegNo);
6730+
exitArchiveRecovery(xlogreader->readPageTLI, EndOfLog);
66916731

66926732
/*
66936733
* Prepare to write WAL starting at EndOfLog position, and init xlog
66946734
* buffer cache using the block containing the last record from the
66956735
* previous incarnation.
66966736
*/
6697-
openLogSegNo = endLogSegNo;
6737+
openLogSegNo = startLogSegNo;
66986738
openLogFile = XLogFileOpen(openLogSegNo);
66996739
openLogOff = 0;
67006740
Insert = &XLogCtl->Insert;

0 commit comments

Comments
 (0)