Change xlog page-header format to include StartUpID. Use the SUI to
authorTom Lane <tgl@sss.pgh.pa.us>
Tue, 13 Mar 2001 20:32:37 +0000 (20:32 +0000)
committerTom Lane <tgl@sss.pgh.pa.us>
Tue, 13 Mar 2001 20:32:37 +0000 (20:32 +0000)
detect case that next page in log came from an older run than the prior
page.  This avoids the necessity to re-zero the log after recovery from
a crash, which is good because we need not risk destroying valuable log
information.
This forces another initdb since yesterday :-(.  Need to get that log
reset utility done...

src/backend/access/transam/xlog.c
src/include/access/xlog.h

index 3d6b8255e969a1f03ac7eead7459658f0fde9dbd..d30392096830096d91b436ab705c0f1b8f18906a 100644 (file)
@@ -1,12 +1,13 @@
 /*-------------------------------------------------------------------------
  *
  * xlog.c
+ *     PostgreSQL transaction log manager
  *
  *
  * Portions Copyright (c) 1996-2001, PostgreSQL Global Development Group
  * Portions Copyright (c) 1994, Regents of the University of California
  *
- * $Header: /cvsroot/pgsql/src/backend/access/transam/xlog.c,v 1.56 2001/03/13 01:17:05 tgl Exp $
+ * $Header: /cvsroot/pgsql/src/backend/access/transam/xlog.c,v 1.57 2001/03/13 20:32:37 tgl Exp $
  *
  *-------------------------------------------------------------------------
  */
@@ -344,6 +345,7 @@ static char *readBuf = NULL;
 static XLogRecPtr ReadRecPtr;
 static XLogRecPtr EndRecPtr;
 static XLogRecord *nextRecord = NULL;
+static StartUpID lastReadSUI;
 
 static bool InRedo = false;
 
@@ -355,6 +357,7 @@ static int  XLogFileOpen(uint32 log, uint32 seg, bool econt);
 static void PreallocXlogFiles(XLogRecPtr endptr);
 static void MoveOfflineLogs(uint32 log, uint32 seg);
 static XLogRecord *ReadRecord(XLogRecPtr *RecPtr, int emode, char *buffer);
+static bool ValidXLOGHeader(XLogPageHeader hdr, int emode, bool checkSUI);
 static XLogRecord *ReadCheckpointRecord(XLogRecPtr RecPtr,
                                        const char *whichChkpt,
                                        char *buffer);
@@ -891,6 +894,7 @@ AdvanceXLInsertBuffer(void)
    MemSet((char*) Insert->currpage, 0, BLCKSZ);
    Insert->currpage->xlp_magic = XLOG_PAGE_MAGIC;
    /* Insert->currpage->xlp_info = 0; */   /* done by memset */
+   Insert->currpage->xlp_sui = ThisStartUpID;
 
    return update_needed;
 }
@@ -1498,6 +1502,7 @@ ReadRecord(XLogRecPtr *RecPtr, int emode, char *buffer)
                total_len;
    uint32      targetPageOff;
    unsigned    i;
+   bool        nextmode = false;
 
    if (readBuf == NULL)
    {
@@ -1516,6 +1521,7 @@ ReadRecord(XLogRecPtr *RecPtr, int emode, char *buffer)
    if (RecPtr == NULL)
    {
        RecPtr = &tmpRecPtr;
+       nextmode = true;
        /* fast case if next record is on same page */
        if (nextRecord != NULL)
        {
@@ -1566,13 +1572,8 @@ ReadRecord(XLogRecPtr *RecPtr, int emode, char *buffer)
                 readId, readSeg, readOff);
            goto next_record_is_invalid;
        }
-       if (((XLogPageHeader) readBuf)->xlp_magic != XLOG_PAGE_MAGIC)
-       {
-           elog(emode, "ReadRecord: invalid magic number %u in logfile %u seg %u off %u",
-                ((XLogPageHeader) readBuf)->xlp_magic,
-                readId, readSeg, readOff);
+       if (!ValidXLOGHeader((XLogPageHeader) readBuf, emode, nextmode))
            goto next_record_is_invalid;
-       }
    }
    if ((((XLogPageHeader) readBuf)->xlp_info & XLP_FIRST_IS_CONTRECORD) &&
        RecPtr->xrecoff % BLCKSZ == SizeOfXLogPHD)
@@ -1651,13 +1652,8 @@ got_record:;
                     readId, readSeg, readOff);
                goto next_record_is_invalid;
            }
-           if (((XLogPageHeader) readBuf)->xlp_magic != XLOG_PAGE_MAGIC)
-           {
-               elog(emode, "ReadRecord: invalid magic number %u in logfile %u seg %u off %u",
-                    ((XLogPageHeader) readBuf)->xlp_magic,
-                    readId, readSeg, readOff);
+           if (!ValidXLOGHeader((XLogPageHeader) readBuf, emode, true))
                goto next_record_is_invalid;
-           }
            if (!(((XLogPageHeader) readBuf)->xlp_info & XLP_FIRST_IS_CONTRECORD))
            {
                elog(emode, "ReadRecord: there is no ContRecord flag in logfile %u seg %u off %u",
@@ -1719,6 +1715,50 @@ next_record_is_invalid:;
    return NULL;
 }
 
+/*
+ * Check whether the xlog header of a page just read in looks valid.
+ *
+ * This is just a convenience subroutine to avoid duplicated code in
+ * ReadRecord.  It's not intended for use from anywhere else.
+ */
+static bool
+ValidXLOGHeader(XLogPageHeader hdr, int emode, bool checkSUI)
+{
+   if (hdr->xlp_magic != XLOG_PAGE_MAGIC)
+   {
+       elog(emode, "ReadRecord: invalid magic number %04X in logfile %u seg %u off %u",
+            hdr->xlp_magic, readId, readSeg, readOff);
+       return false;
+   }
+   if ((hdr->xlp_info & ~XLP_ALL_FLAGS) != 0)
+   {
+       elog(emode, "ReadRecord: invalid info bits %04X in logfile %u seg %u off %u",
+            hdr->xlp_info, readId, readSeg, readOff);
+       return false;
+   }
+   /*
+    * We disbelieve a SUI less than the previous page's SUI, or more
+    * than a few counts greater.  In theory as many as 512 shutdown
+    * checkpoint records could appear on a 32K-sized xlog page, so
+    * that's the most differential there could legitimately be.
+    *
+    * Note this check can only be applied when we are reading the next page
+    * in sequence, so ReadRecord passes a flag indicating whether to check.
+    */
+   if (checkSUI)
+   {
+       if (hdr->xlp_sui < lastReadSUI ||
+           hdr->xlp_sui > lastReadSUI + 512)
+       {
+           elog(emode, "ReadRecord: out-of-sequence SUI %u (after %u) in logfile %u seg %u off %u",
+                hdr->xlp_sui, lastReadSUI, readId, readSeg, readOff);
+           return false;
+       }
+   }
+   lastReadSUI = hdr->xlp_sui;
+   return true;
+}
+
 /*
  * I/O routines for pg_control
  *
@@ -2023,6 +2063,7 @@ BootStrapXLOG(void)
    memset(buffer, 0, BLCKSZ);
    page->xlp_magic = XLOG_PAGE_MAGIC;
    page->xlp_info = 0;
+   page->xlp_sui = checkPoint.ThisStartUpID;
    record = (XLogRecord *) ((char *) page + SizeOfXLogPHD);
    record->xl_prev.xlogid = 0;
    record->xl_prev.xrecoff = 0;
index dd079496ed65bde9bdff40c0b156fc8c9267625e..fa51d68d39ecd861814b9a4073652e1822f940f4 100644 (file)
@@ -6,7 +6,7 @@
  * Portions Copyright (c) 1996-2001, PostgreSQL Global Development Group
  * Portions Copyright (c) 1994, Regents of the University of California
  *
- * $Id: xlog.h,v 1.19 2001/03/13 01:17:06 tgl Exp $
+ * $Id: xlog.h,v 1.20 2001/03/13 20:32:37 tgl Exp $
  */
 #ifndef XLOG_H
 #define XLOG_H
@@ -26,6 +26,9 @@
  * really:
  *
  * SizeOfXLogRecord + xl_len + n_backup_blocks * (sizeof(BkpBlock) + BLCKSZ)
+ *
+ * rounded up to a MAXALIGN boundary (so that all xlog records start on
+ * MAXALIGN boundaries).
  */
 typedef struct XLogRecord
 {
@@ -105,12 +108,13 @@ typedef struct XLogContRecord
 /*
  * Each page of XLOG file has a header like this:
  */
-#define XLOG_PAGE_MAGIC 0x17345169 /* can be used as WAL version indicator */
+#define XLOG_PAGE_MAGIC 0xD058 /* can be used as WAL version indicator */
 
 typedef struct XLogPageHeaderData
 {
-   uint32      xlp_magic;      /* magic value for correctness checks */
+   uint16      xlp_magic;      /* magic value for correctness checks */
    uint16      xlp_info;       /* flag bits, see below */
+   StartUpID   xlp_sui;        /* StartUpID of first record on page */
 } XLogPageHeaderData;
 
 #define SizeOfXLogPHD  MAXALIGN(sizeof(XLogPageHeaderData))
@@ -119,6 +123,8 @@ typedef XLogPageHeaderData *XLogPageHeader;
 
 /* When record crosses page boundary, set this flag in new page's header */
 #define XLP_FIRST_IS_CONTRECORD        0x0001
+/* All defined flag bits in xlp_info (used for validity checking of header) */
+#define XLP_ALL_FLAGS              0x0001
 
 /*
  * We break each logical log file (xlogid value) into 16Mb segments.