From b23c1d69ad86fcbb992cb21c604f587d82441001 Mon Sep 17 00:00:00 2001 From: Kyotaro Horiguchi Date: Thu, 7 Sep 2017 12:14:55 +0900 Subject: [PATCH 1/2] Allow switch WAL source midst of record. The corrent recovery machinary assumes the whole of a record is avaiable from single source. This prevents a standby from restarting under a certain condition. This patch allows source switching during reading a series of continuation records. --- src/backend/access/transam/xlog.c | 14 ++++++++++++-- src/backend/access/transam/xlogreader.c | 28 ++++++++++++++++++---------- src/include/access/xlogreader.h | 4 ++++ 3 files changed, 34 insertions(+), 12 deletions(-) diff --git a/src/backend/access/transam/xlog.c b/src/backend/access/transam/xlog.c index dd028a1..0d639ec 100644 --- a/src/backend/access/transam/xlog.c +++ b/src/backend/access/transam/xlog.c @@ -11647,6 +11647,10 @@ retry: Assert(reqLen <= readLen); *readTLI = curFileTLI; + + if (!XLogReaderValidatePageHeader(xlogreader, targetPagePtr, readBuf)) + goto next_record_is_invalid; + return readLen; next_record_is_invalid: @@ -11781,12 +11785,18 @@ WaitForWALToBecomeAvailable(XLogRecPtr RecPtr, bool randAccess, } else { - ptr = tliRecPtr; + /* + * Trying from the current RecPtr, not from the + * beginning of the current record. The record may + * be no longer available from the master. + */ + ptr = RecPtr; tli = tliOfPointInHistory(tliRecPtr, expectedTLEs); if (curFileTLI > 0 && tli < curFileTLI) elog(ERROR, "according to history file, WAL location %X/%X belongs to timeline %u, but previous recovered WAL file came from timeline %u", - (uint32) (ptr >> 32), (uint32) ptr, + (uint32) (tliRecPtr >> 32), + (uint32) tliRecPtr, tli, curFileTLI); } curFileTLI = tli; diff --git a/src/backend/access/transam/xlogreader.c b/src/backend/access/transam/xlogreader.c index b1f9b90..78a721a 100644 --- a/src/backend/access/transam/xlogreader.c +++ b/src/backend/access/transam/xlogreader.c @@ -27,8 +27,6 @@ static bool allocate_recordbuf(XLogReaderState *state, uint32 reclength); -static bool ValidXLogPageHeader(XLogReaderState *state, XLogRecPtr recptr, - XLogPageHeader hdr); static bool ValidXLogRecordHeader(XLogReaderState *state, XLogRecPtr RecPtr, XLogRecPtr PrevRecPtr, XLogRecord *record, bool randAccess); static bool ValidXLogRecord(XLogReaderState *state, XLogRecord *record, @@ -533,7 +531,6 @@ ReadPageInternal(XLogReaderState *state, XLogRecPtr pageptr, int reqLen) */ if (targetSegNo != state->readSegNo && targetPageOff != 0) { - XLogPageHeader hdr; XLogRecPtr targetSegmentPtr = pageptr - targetPageOff; readLen = state->read_page(state, targetSegmentPtr, XLOG_BLCKSZ, @@ -545,9 +542,8 @@ ReadPageInternal(XLogReaderState *state, XLogRecPtr pageptr, int reqLen) /* we can be sure to have enough WAL available, we scrolled back */ Assert(readLen == XLOG_BLCKSZ); - hdr = (XLogPageHeader) state->readBuf; - - if (!ValidXLogPageHeader(state, targetSegmentPtr, hdr)) + if (!XLogReaderValidatePageHeader(state, targetSegmentPtr, + state->readBuf)) goto err; } @@ -584,7 +580,7 @@ ReadPageInternal(XLogReaderState *state, XLogRecPtr pageptr, int reqLen) /* * Now that we know we have the full header, validate it. */ - if (!ValidXLogPageHeader(state, pageptr, hdr)) + if (!XLogReaderValidatePageHeader(state, pageptr, (char *) hdr)) goto err; /* update read state information */ @@ -710,14 +706,26 @@ ValidXLogRecord(XLogReaderState *state, XLogRecord *record, XLogRecPtr recptr) /* * Validate a page header + * + * Check if phdr is valid as the XLog page header of the XLog page of the page + * pointed by recptr. + * + * phdr is read as XLogPageHeaderData and check if it has valid magic, has no + * usused flag bits set and belongs to correct page pointed by recptr. The + * incorrect page address is detected usually when we read a page in a + * recycled segment. + * + * If it is the first page in a segment or detected rewind of state, + * additional checks are performed. */ -static bool -ValidXLogPageHeader(XLogReaderState *state, XLogRecPtr recptr, - XLogPageHeader hdr) +bool +XLogReaderValidatePageHeader(XLogReaderState *state, XLogRecPtr recptr, + char *phdr) { XLogRecPtr recaddr; XLogSegNo segno; int32 offset; + XLogPageHeader hdr = (XLogPageHeader) phdr; Assert((recptr % XLOG_BLCKSZ) == 0); diff --git a/src/include/access/xlogreader.h b/src/include/access/xlogreader.h index 3a9ebd4..758d880 100644 --- a/src/include/access/xlogreader.h +++ b/src/include/access/xlogreader.h @@ -205,6 +205,10 @@ extern void XLogReaderFree(XLogReaderState *state); extern struct XLogRecord *XLogReadRecord(XLogReaderState *state, XLogRecPtr recptr, char **errormsg); +/* Validate a page */ +extern bool XLogReaderValidatePageHeader(XLogReaderState *state, + XLogRecPtr recptr, char *phdr); + /* Invalidate read state */ extern void XLogReaderInvalReadState(XLogReaderState *state); -- 2.9.2