From ff4220ead2c833fb36e9709ab2568c6ac43e9d3b Mon Sep 17 00:00:00 2001 From: Amit Kapila Date: Thu, 13 Sep 2018 15:38:15 +0530 Subject: [PATCH] Attach FPI to the first record after full_page_writes is turned on. XLogInsert fails to attach a required FPI to the first record after full_page_writes is turned on by the last checkpoint. This bug got introduced in 9.5 due to code rearrangement in commits 2c03216d83 and 2076db2aea. Fix it by ensuring that XLogInsertRecord performs a recomputation when the given record is generated with FPW as off but found that the flag has been turned on while actually inserting the record. Reported-by: Kyotaro Horiguchi Author: Kyotaro Horiguchi Reviewed-by: Amit Kapila Backpatch-through: 9.5 where this problem was introduced Discussion: https://postgr.es/m/20180420.151043.74298611.horiguchi.kyotaro@lab.ntt.co.jp --- src/backend/access/transam/xlog.c | 19 +++++++++++++------ 1 file changed, 13 insertions(+), 6 deletions(-) diff --git a/src/backend/access/transam/xlog.c b/src/backend/access/transam/xlog.c index 32bbe11da3..879d80e187 100644 --- a/src/backend/access/transam/xlog.c +++ b/src/backend/access/transam/xlog.c @@ -943,7 +943,7 @@ static void WALInsertLockUpdateInsertingAt(XLogRecPtr insertingAt); * * If 'fpw_lsn' is valid, it is the oldest LSN among the pages that this * WAL record applies to, that were not included in the record as full page - * images. If fpw_lsn >= RedoRecPtr, the function does not perform the + * images. If fpw_lsn <= RedoRecPtr, the function does not perform the * insertion and returns InvalidXLogRecPtr. The caller can then recalculate * which pages need a full-page image, and retry. If fpw_lsn is invalid, the * record is always inserted. @@ -976,6 +976,7 @@ XLogInsertRecord(XLogRecData *rdata, info == XLOG_SWITCH); XLogRecPtr StartPos; XLogRecPtr EndPos; + bool prevDoPageWrites = doPageWrites; /* we assume that all of the record header is in the first chunk */ Assert(rdata->len >= SizeOfXLogRecord); @@ -1023,10 +1024,14 @@ XLogInsertRecord(XLogRecData *rdata, WALInsertLockAcquire(); /* - * Check to see if my copy of RedoRecPtr or doPageWrites is out of date. - * If so, may have to go back and have the caller recompute everything. - * This can only happen just after a checkpoint, so it's better to be slow - * in this case and fast otherwise. + * Check to see if my copy of RedoRecPtr is out of date. If so, may have + * to go back and have the caller recompute everything. This can only + * happen just after a checkpoint, so it's better to be slow in this case + * and fast otherwise. + * + * Also check to see if fullPageWrites or forcePageWrites was just turned + * on; if we weren't already doing full-page writes then go back and + * recompute. * * If we aren't doing full-page writes then RedoRecPtr doesn't actually * affect the contents of the XLOG record, so we'll update our local copy @@ -1041,7 +1046,9 @@ XLogInsertRecord(XLogRecData *rdata, } doPageWrites = (Insert->fullPageWrites || Insert->forcePageWrites); - if (fpw_lsn != InvalidXLogRecPtr && fpw_lsn <= RedoRecPtr && doPageWrites) + if (doPageWrites && + (!prevDoPageWrites || + (fpw_lsn != InvalidXLogRecPtr && fpw_lsn <= RedoRecPtr))) { /* * Oops, some buffer now needs to be backed up that the caller didn't