Location via proxy:   [ UP ]  
[Report a bug]   [Manage cookies]                
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