Bootstrap WAL to begin at segment logid=0 logseg=1 (000000010000000000000001)
authorHeikki Linnakangas <[email protected]>
Tue, 2 Nov 2010 09:23:43 +0000 (11:23 +0200)
committerHeikki Linnakangas <[email protected]>
Tue, 2 Nov 2010 09:36:32 +0000 (11:36 +0200)
rather than 0/0, so that we can safely use 0/0 as an invalid value. This is a
more future-proof fix for the corner-case bug in streaming replication that
was fixed yesterday. We had a similar corner-case bug with log/seg 0/0 back in
February as well. Avoiding 0/0 as a valid value should prevent bugs like that
in the future. Per Tom Lane's idea.

Back-patch to 9.0. Since this only affects bootstrapping, it makes no
difference to existing installations. We don't need to worry about the
bug in existing installations, because if you've managed to get past the
initial base backup already, you won't hit the bug in the future either.

src/backend/access/transam/xlog.c
src/backend/replication/walsender.c

index a55c2ffbcfe3abb1d9bad346254818b4c59e0071..1b90f9ae72e4423cd902e49c0b72db03eafb44d3 100644 (file)
@@ -363,7 +363,7 @@ typedef struct XLogCtlData
        uint32          ckptXidEpoch;   /* nextXID & epoch of latest checkpoint */
        TransactionId ckptXid;
        XLogRecPtr      asyncXactLSN; /* LSN of newest async commit/abort */
-       uint32          lastRemovedLog; /* latest removed/recycled XLOG segment + 1 */
+       uint32          lastRemovedLog; /* latest removed/recycled XLOG segment */
        uint32          lastRemovedSeg;
 
        /* Protected by WALWriteLock: */
@@ -3210,9 +3210,7 @@ PreallocXlogFiles(XLogRecPtr endptr)
 }
 
 /*
- * Get the log/seg of the first WAL segment that has not been removed or
- * recycled. In other words, the log/seg of the last removed/recycled WAL
- * segment + 1.
+ * Get the log/seg of the latest removed or recycled WAL segment.
  * Returns 0/0 if no WAL segments have been removed since startup.
  */
 void
@@ -3241,7 +3239,6 @@ UpdateLastRemovedPtr(char *filename)
                                seg;
 
        XLogFromFileName(filename, &tli, &log, &seg);
-       NextLogSeg(log, seg);
 
        SpinLockAcquire(&xlogctl->info_lck);
        if (log > xlogctl->lastRemovedLog ||
@@ -4894,9 +4891,15 @@ BootStrapXLOG(void)
        page = (XLogPageHeader) TYPEALIGN(ALIGNOF_XLOG_BUFFER, buffer);
        memset(page, 0, XLOG_BLCKSZ);
 
-       /* Set up information for the initial checkpoint record */
+       /*
+        * Set up information for the initial checkpoint record
+        *
+        * The initial checkpoint record is written to the beginning of the
+        * WAL segment with logid=0 logseg=1. The very first WAL segment, 0/0, is
+        * not used, so that we can use 0/0 to mean "before any valid WAL segment".
+        */
        checkPoint.redo.xlogid = 0;
-       checkPoint.redo.xrecoff = SizeOfXLogLongPHD;
+       checkPoint.redo.xrecoff = XLogSegSize + SizeOfXLogLongPHD;
        checkPoint.ThisTimeLineID = ThisTimeLineID;
        checkPoint.nextXidEpoch = 0;
        checkPoint.nextXid = FirstNormalTransactionId;
@@ -4919,7 +4922,7 @@ BootStrapXLOG(void)
        page->xlp_info = XLP_LONG_HEADER;
        page->xlp_tli = ThisTimeLineID;
        page->xlp_pageaddr.xlogid = 0;
-       page->xlp_pageaddr.xrecoff = 0;
+       page->xlp_pageaddr.xrecoff = XLogSegSize;
        longpage = (XLogLongPageHeader) page;
        longpage->xlp_sysid = sysidentifier;
        longpage->xlp_seg_size = XLogSegSize;
@@ -4945,7 +4948,7 @@ BootStrapXLOG(void)
 
        /* Create first XLOG segment file */
        use_existent = false;
-       openLogFile = XLogFileInit(0, 0, &use_existent, false);
+       openLogFile = XLogFileInit(0, 1, &use_existent, false);
 
        /* Write the first page with the initial record */
        errno = 0;
index f3775ac72da9e2bea5969ef899c93e1fc5c77b70..2a16888b0ff8821d7eeac442ddadbf11192f25f2 100644 (file)
@@ -630,7 +630,7 @@ XLogRead(char *buf, XLogRecPtr recptr, Size nbytes)
        XLogGetLastRemoved(&lastRemovedLog, &lastRemovedSeg);
        XLByteToSeg(startRecPtr, log, seg);
        if (log < lastRemovedLog ||
-               (log == lastRemovedLog && seg < lastRemovedSeg))
+               (log == lastRemovedLog && seg <= lastRemovedSeg))
        {
                char            filename[MAXFNAMELEN];