/*-------------------------------------------------------------------------
*
* 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 $
*
*-------------------------------------------------------------------------
*/
static XLogRecPtr ReadRecPtr;
static XLogRecPtr EndRecPtr;
static XLogRecord *nextRecord = NULL;
+static StartUpID lastReadSUI;
static bool InRedo = false;
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);
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;
}
total_len;
uint32 targetPageOff;
unsigned i;
+ bool nextmode = false;
if (readBuf == NULL)
{
if (RecPtr == NULL)
{
RecPtr = &tmpRecPtr;
+ nextmode = true;
/* fast case if next record is on same page */
if (nextRecord != NULL)
{
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)
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",
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
*
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;
* 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
* 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
{
/*
* 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))
/* 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.