From 1b87e24c4abcb9bca5b2542f7dd11433fa347993 Mon Sep 17 00:00:00 2001 From: Tom Lane Date: Tue, 13 Mar 2001 20:32:37 +0000 Subject: [PATCH] Change xlog page-header format to include StartUpID. Use the SUI to 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 | 67 +++++++++++++++++++++++++------ src/include/access/xlog.h | 12 ++++-- 2 files changed, 63 insertions(+), 16 deletions(-) diff --git a/src/backend/access/transam/xlog.c b/src/backend/access/transam/xlog.c index 3d6b8255e9..d303920968 100644 --- a/src/backend/access/transam/xlog.c +++ b/src/backend/access/transam/xlog.c @@ -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; diff --git a/src/include/access/xlog.h b/src/include/access/xlog.h index dd079496ed..fa51d68d39 100644 --- a/src/include/access/xlog.h +++ b/src/include/access/xlog.h @@ -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.