* Portions Copyright (c) 1996-2010, PostgreSQL Global Development Group
* Portions Copyright (c) 1994, Regents of the University of California
*
- * $PostgreSQL: pgsql/src/backend/access/transam/xlog.c,v 1.396 2010/04/15 03:05:59 momjian Exp $
+ * $PostgreSQL: pgsql/src/backend/access/transam/xlog.c,v 1.397 2010/04/16 08:58:16 heikki Exp $
*
*-------------------------------------------------------------------------
*/
int sources);
static bool XLogPageRead(XLogRecPtr *RecPtr, int emode, bool fetching_ckpt,
bool randAccess);
-static int emode_for_corrupt_record(int emode);
+static int emode_for_corrupt_record(int emode, XLogRecPtr RecPtr);
static void XLogFileClose(void);
static bool RestoreArchivedFile(char *path, const char *xlogfname,
const char *recovername, off_t expectedSize);
memcpy(&bkpb, blk, sizeof(BkpBlock));
if (bkpb.hole_offset + bkpb.hole_length > BLCKSZ)
{
- ereport(emode,
+ ereport(emode_for_corrupt_record(emode, recptr),
(errmsg("incorrect hole size in record at %X/%X",
recptr.xlogid, recptr.xrecoff)));
return false;
/* Check that xl_tot_len agrees with our calculation */
if (blk != (char *) record + record->xl_tot_len)
{
- ereport(emode,
+ ereport(emode_for_corrupt_record(emode, recptr),
(errmsg("incorrect total length in record at %X/%X",
recptr.xlogid, recptr.xrecoff)));
return false;
if (!EQ_CRC32(record->xl_crc, crc))
{
- ereport(emode,
+ ereport(emode_for_corrupt_record(emode, recptr),
(errmsg("incorrect resource manager data checksum in record at %X/%X",
recptr.xlogid, recptr.xrecoff)));
return false;
}
else if (targetRecOff < pageHeaderSize)
{
- ereport(emode_for_corrupt_record(emode),
+ ereport(emode_for_corrupt_record(emode, *RecPtr),
(errmsg("invalid record offset at %X/%X",
RecPtr->xlogid, RecPtr->xrecoff)));
goto next_record_is_invalid;
if ((((XLogPageHeader) readBuf)->xlp_info & XLP_FIRST_IS_CONTRECORD) &&
targetRecOff == pageHeaderSize)
{
- ereport(emode_for_corrupt_record(emode),
+ ereport(emode_for_corrupt_record(emode, *RecPtr),
(errmsg("contrecord is requested by %X/%X",
RecPtr->xlogid, RecPtr->xrecoff)));
goto next_record_is_invalid;
{
if (record->xl_len != 0)
{
- ereport(emode_for_corrupt_record(emode),
+ ereport(emode_for_corrupt_record(emode, *RecPtr),
(errmsg("invalid xlog switch record at %X/%X",
RecPtr->xlogid, RecPtr->xrecoff)));
goto next_record_is_invalid;
}
else if (record->xl_len == 0)
{
- ereport(emode_for_corrupt_record(emode),
+ ereport(emode_for_corrupt_record(emode, *RecPtr),
(errmsg("record with zero length at %X/%X",
RecPtr->xlogid, RecPtr->xrecoff)));
goto next_record_is_invalid;
record->xl_tot_len > SizeOfXLogRecord + record->xl_len +
XLR_MAX_BKP_BLOCKS * (sizeof(BkpBlock) + BLCKSZ))
{
- ereport(emode_for_corrupt_record(emode),
+ ereport(emode_for_corrupt_record(emode, *RecPtr),
(errmsg("invalid record length at %X/%X",
RecPtr->xlogid, RecPtr->xrecoff)));
goto next_record_is_invalid;
}
if (record->xl_rmid > RM_MAX_ID)
{
- ereport(emode_for_corrupt_record(emode),
+ ereport(emode_for_corrupt_record(emode, *RecPtr),
(errmsg("invalid resource manager ID %u at %X/%X",
record->xl_rmid, RecPtr->xlogid, RecPtr->xrecoff)));
goto next_record_is_invalid;
*/
if (!XLByteLT(record->xl_prev, *RecPtr))
{
- ereport(emode_for_corrupt_record(emode),
+ ereport(emode_for_corrupt_record(emode, *RecPtr),
(errmsg("record with incorrect prev-link %X/%X at %X/%X",
record->xl_prev.xlogid, record->xl_prev.xrecoff,
RecPtr->xlogid, RecPtr->xrecoff)));
*/
if (!XLByteEQ(record->xl_prev, ReadRecPtr))
{
- ereport(emode_for_corrupt_record(emode),
+ ereport(emode_for_corrupt_record(emode, *RecPtr),
(errmsg("record with incorrect prev-link %X/%X at %X/%X",
record->xl_prev.xlogid, record->xl_prev.xrecoff,
RecPtr->xlogid, RecPtr->xrecoff)));
{
readRecordBufSize = 0;
/* We treat this as a "bogus data" condition */
- ereport(emode_for_corrupt_record(emode),
+ ereport(emode_for_corrupt_record(emode, *RecPtr),
(errmsg("record length %u at %X/%X too long",
total_len, RecPtr->xlogid, RecPtr->xrecoff)));
goto next_record_is_invalid;
/* Check that the continuation record looks valid */
if (!(((XLogPageHeader) readBuf)->xlp_info & XLP_FIRST_IS_CONTRECORD))
{
- ereport(emode_for_corrupt_record(emode),
+ ereport(emode_for_corrupt_record(emode, *RecPtr),
(errmsg("there is no contrecord flag in log file %u, segment %u, offset %u",
readId, readSeg, readOff)));
goto next_record_is_invalid;
if (contrecord->xl_rem_len == 0 ||
total_len != (contrecord->xl_rem_len + gotlen))
{
- ereport(emode_for_corrupt_record(emode),
+ ereport(emode_for_corrupt_record(emode, *RecPtr),
(errmsg("invalid contrecord length %u in log file %u, segment %u, offset %u",
contrecord->xl_rem_len,
readId, readSeg, readOff)));
contrecord->xl_rem_len);
break;
}
- if (!RecordIsValid(record, *RecPtr, emode_for_corrupt_record(emode)))
+ if (!RecordIsValid(record, *RecPtr, emode))
goto next_record_is_invalid;
pageHeaderSize = XLogPageHeaderSize((XLogPageHeader) readBuf);
EndRecPtr.xlogid = readId;
}
/* Record does not cross a page boundary */
- if (!RecordIsValid(record, *RecPtr, emode_for_corrupt_record(emode)))
+ if (!RecordIsValid(record, *RecPtr, emode))
goto next_record_is_invalid;
EndRecPtr.xlogid = RecPtr->xlogid;
EndRecPtr.xrecoff = RecPtr->xrecoff + MAXALIGN(total_len);
{
XLogRecPtr recaddr;
+ recaddr.xlogid = readId;
+ recaddr.xrecoff = readSeg * XLogSegSize + readOff;
+
if (hdr->xlp_magic != XLOG_PAGE_MAGIC)
{
- ereport(emode,
+ ereport(emode_for_corrupt_record(emode, recaddr),
(errmsg("invalid magic number %04X in log file %u, segment %u, offset %u",
hdr->xlp_magic, readId, readSeg, readOff)));
return false;
}
if ((hdr->xlp_info & ~XLP_ALL_FLAGS) != 0)
{
- ereport(emode,
+ ereport(emode_for_corrupt_record(emode, recaddr),
(errmsg("invalid info bits %04X in log file %u, segment %u, offset %u",
hdr->xlp_info, readId, readSeg, readOff)));
return false;
longhdr->xlp_sysid);
snprintf(sysident_str, sizeof(sysident_str), UINT64_FORMAT,
ControlFile->system_identifier);
- ereport(emode,
+ ereport(emode_for_corrupt_record(emode, recaddr),
(errmsg("WAL file is from different database system"),
errdetail("WAL file database system identifier is %s, pg_control database system identifier is %s.",
fhdrident_str, sysident_str)));
}
if (longhdr->xlp_seg_size != XLogSegSize)
{
- ereport(emode,
+ ereport(emode_for_corrupt_record(emode, recaddr),
(errmsg("WAL file is from different database system"),
errdetail("Incorrect XLOG_SEG_SIZE in page header.")));
return false;
}
if (longhdr->xlp_xlog_blcksz != XLOG_BLCKSZ)
{
- ereport(emode,
+ ereport(emode_for_corrupt_record(emode, recaddr),
(errmsg("WAL file is from different database system"),
errdetail("Incorrect XLOG_BLCKSZ in page header.")));
return false;
else if (readOff == 0)
{
/* hmm, first page of file doesn't have a long header? */
- ereport(emode,
+ ereport(emode_for_corrupt_record(emode, recaddr),
(errmsg("invalid info bits %04X in log file %u, segment %u, offset %u",
hdr->xlp_info, readId, readSeg, readOff)));
return false;
}
- recaddr.xlogid = readId;
- recaddr.xrecoff = readSeg * XLogSegSize + readOff;
if (!XLByteEQ(hdr->xlp_pageaddr, recaddr))
{
- ereport(emode,
+ ereport(emode_for_corrupt_record(emode, recaddr),
(errmsg("unexpected pageaddr %X/%X in log file %u, segment %u, offset %u",
hdr->xlp_pageaddr.xlogid, hdr->xlp_pageaddr.xrecoff,
readId, readSeg, readOff)));
*/
if (!list_member_int(expectedTLIs, (int) hdr->xlp_tli))
{
- ereport(emode,
+ ereport(emode_for_corrupt_record(emode, recaddr),
(errmsg("unexpected timeline ID %u in log file %u, segment %u, offset %u",
hdr->xlp_tli,
readId, readSeg, readOff)));
*/
if (hdr->xlp_tli < lastPageTLI)
{
- ereport(emode,
+ ereport(emode_for_corrupt_record(emode, recaddr),
(errmsg("out-of-sequence timeline ID %u (after %u) in log file %u, segment %u, offset %u",
hdr->xlp_tli, lastPageTLI,
readId, readSeg, readOff)));
readOff = 0;
if (read(readFile, readBuf, XLOG_BLCKSZ) != XLOG_BLCKSZ)
{
- ereport(emode_for_corrupt_record(emode),
+ ereport(emode_for_corrupt_record(emode, *RecPtr),
(errcode_for_file_access(),
errmsg("could not read from log file %u, segment %u, offset %u: %m",
readId, readSeg, readOff)));
goto next_record_is_invalid;
}
- if (!ValidXLOGHeader((XLogPageHeader) readBuf,
- emode_for_corrupt_record(emode)))
+ if (!ValidXLOGHeader((XLogPageHeader) readBuf, emode))
goto next_record_is_invalid;
}
readOff = targetPageOff;
if (lseek(readFile, (off_t) readOff, SEEK_SET) < 0)
{
- ereport(emode_for_corrupt_record(emode),
+ ereport(emode_for_corrupt_record(emode, *RecPtr),
(errcode_for_file_access(),
errmsg("could not seek in log file %u, segment %u to offset %u: %m",
readId, readSeg, readOff)));
}
if (read(readFile, readBuf, XLOG_BLCKSZ) != XLOG_BLCKSZ)
{
- ereport(emode_for_corrupt_record(emode),
+ ereport(emode_for_corrupt_record(emode, *RecPtr),
(errcode_for_file_access(),
errmsg("could not read from log file %u, segment %u, offset %u: %m",
readId, readSeg, readOff)));
goto next_record_is_invalid;
}
- if (!ValidXLOGHeader((XLogPageHeader) readBuf, emode_for_corrupt_record(emode)))
+ if (!ValidXLOGHeader((XLogPageHeader) readBuf, emode))
goto next_record_is_invalid;
Assert(targetId == readId);
* 'emode' is the error mode that would be used to report a file-not-found
* or legitimate end-of-WAL situation. It is upgraded to WARNING or PANIC
* if a corrupt record is not expected at this point.
+ *
+ * NOTE: This function remembers the RecPtr value it was last called with,
+ * to suppress repeated messages about the same record. Only call this when
+ * you are about to ereport(), or you might cause a later message to be
+ * erroneously suppressed.
*/
static int
-emode_for_corrupt_record(int emode)
+emode_for_corrupt_record(int emode, XLogRecPtr RecPtr)
{
+ static XLogRecPtr lastComplaint = {0, 0};
+
/*
* We don't expect any invalid records in archive or in records streamed
* from master. Files in the archive should be complete, and we should
if (emode < WARNING)
emode = WARNING;
}
+ /*
+ * If we retry reading a record in pg_xlog, only complain on the first
+ * time to keep the noise down.
+ */
+ else if (emode == LOG)
+ {
+ if (XLByteEQ(RecPtr, lastComplaint))
+ emode = DEBUG1;
+ else
+ lastComplaint = RecPtr;
+ }
return emode;
}