From 44bdb5b92b651c524e6f901be4eaa0184714f04d Mon Sep 17 00:00:00 2001 From: Kyotaro Horiguchi Date: Fri, 26 Oct 2018 10:07:05 +0900 Subject: [PATCH 6/6] Check removal of in-reading segment file. Checkpoint can remove or recycle a segment file while it is being read by ReadRecord during logical decoding. This patch checks for the case and error out immedaitely. Reading recycled file is basically safe and inconsistency caused by overwrites as new segment will be caught by page/record validation. So this is only for keeping consistency with the wal_status shown in pg_replication_slots. --- src/backend/access/transam/xlogreader.c | 20 +++++++++++++++++++- 1 file changed, 19 insertions(+), 1 deletion(-) diff --git a/src/backend/access/transam/xlogreader.c b/src/backend/access/transam/xlogreader.c index c5e019bf77..117710c55b 100644 --- a/src/backend/access/transam/xlogreader.c +++ b/src/backend/access/transam/xlogreader.c @@ -26,6 +26,7 @@ #include "replication/origin.h" #ifndef FRONTEND +#include "access/xlog.h" #include "utils/memutils.h" #endif @@ -224,7 +225,9 @@ XLogReadRecord(XLogReaderState *state, XLogRecPtr RecPtr, char **errormsg) uint32 pageHeaderSize; bool gotheader; int readOff; - +#ifndef FRONTEND + XLogSegNo targetSegNo; +#endif /* * randAccess indicates whether to verify the previous-record pointer of * the record we're reading. We only do this if we're reading @@ -270,6 +273,21 @@ XLogReadRecord(XLogReaderState *state, XLogRecPtr RecPtr, char **errormsg) targetPagePtr = RecPtr - (RecPtr % XLOG_BLCKSZ); targetRecOff = RecPtr % XLOG_BLCKSZ; +#ifndef FRONTEND + /* + * checkpoint can remove the segment currently looking for. make sure the + * current segment still exists. we check this once per page. This cannot + * happen on frontend. + */ + XLByteToSeg(targetPagePtr, targetSegNo, state->wal_segment_size); + if (targetSegNo <= XLogGetLastRemovedSegno()) + { + report_invalid_record(state, + "WAL segment for LSN %X/%X has been removed", + (uint32)(RecPtr >> 32), (uint32) RecPtr); + goto err; + } +#endif /* * Read the page containing the record into state->readBuf. Request enough * byte to cover the whole record header, or at least the part of it that -- 2.16.3