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.