]> granicus.if.org Git - postgresql/commitdiff
Attach FPI to the first record after full_page_writes is turned on.
authorAmit Kapila <akapila@postgresql.org>
Thu, 13 Sep 2018 10:00:26 +0000 (15:30 +0530)
committerAmit Kapila <akapila@postgresql.org>
Thu, 13 Sep 2018 10:02:50 +0000 (15:32 +0530)
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

index 85a7b285ec393033e0191cedcf10b69d6cd91c51..3025d0badb89a90feabffa3b5298eaf1dd098225 100644 (file)
@@ -944,7 +944,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.
@@ -977,6 +977,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);
@@ -1024,10 +1025,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
@@ -1042,7 +1047,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