77 * Portions Copyright (c) 1996-2010, PostgreSQL Global Development Group
88 * Portions Copyright (c) 1994, Regents of the University of California
99 *
10- * $PostgreSQL: pgsql/src/backend/access/transam/xlog.c,v 1.396 2010/04/15 03:05:59 momjian Exp $
10+ * $PostgreSQL: pgsql/src/backend/access/transam/xlog.c,v 1.397 2010/04/16 08:58:16 heikki Exp $
1111 *
1212 *-------------------------------------------------------------------------
1313 */
@@ -539,7 +539,7 @@ static int XLogFileReadAnyTLI(uint32 log, uint32 seg, int emode,
539539int sources );
540540static bool XLogPageRead (XLogRecPtr * RecPtr ,int emode ,bool fetching_ckpt ,
541541bool randAccess );
542- static int emode_for_corrupt_record (int emode );
542+ static int emode_for_corrupt_record (int emode , XLogRecPtr RecPtr );
543543static void XLogFileClose (void );
544544static bool RestoreArchivedFile (char * path ,const char * xlogfname ,
545545const char * recovername ,off_t expectedSize );
@@ -3543,7 +3543,7 @@ RecordIsValid(XLogRecord *record, XLogRecPtr recptr, int emode)
35433543memcpy (& bkpb ,blk ,sizeof (BkpBlock ));
35443544if (bkpb .hole_offset + bkpb .hole_length > BLCKSZ )
35453545{
3546- ereport (emode ,
3546+ ereport (emode_for_corrupt_record ( emode , recptr ) ,
35473547(errmsg ("incorrect hole size in record at %X/%X" ,
35483548recptr .xlogid ,recptr .xrecoff )));
35493549return false;
@@ -3556,7 +3556,7 @@ RecordIsValid(XLogRecord *record, XLogRecPtr recptr, int emode)
35563556/* Check that xl_tot_len agrees with our calculation */
35573557if (blk != (char * )record + record -> xl_tot_len )
35583558{
3559- ereport (emode ,
3559+ ereport (emode_for_corrupt_record ( emode , recptr ) ,
35603560(errmsg ("incorrect total length in record at %X/%X" ,
35613561recptr .xlogid ,recptr .xrecoff )));
35623562return false;
@@ -3569,7 +3569,7 @@ RecordIsValid(XLogRecord *record, XLogRecPtr recptr, int emode)
35693569
35703570if (!EQ_CRC32 (record -> xl_crc ,crc ))
35713571{
3572- ereport (emode ,
3572+ ereport (emode_for_corrupt_record ( emode , recptr ) ,
35733573(errmsg ("incorrect resource manager data checksum in record at %X/%X" ,
35743574recptr .xlogid ,recptr .xrecoff )));
35753575return false;
@@ -3674,15 +3674,15 @@ ReadRecord(XLogRecPtr *RecPtr, int emode, bool fetching_ckpt)
36743674}
36753675else if (targetRecOff < pageHeaderSize )
36763676{
3677- ereport (emode_for_corrupt_record (emode ),
3677+ ereport (emode_for_corrupt_record (emode , * RecPtr ),
36783678(errmsg ("invalid record offset at %X/%X" ,
36793679RecPtr -> xlogid ,RecPtr -> xrecoff )));
36803680gotonext_record_is_invalid ;
36813681}
36823682if ((((XLogPageHeader )readBuf )-> xlp_info & XLP_FIRST_IS_CONTRECORD )&&
36833683targetRecOff == pageHeaderSize )
36843684{
3685- ereport (emode_for_corrupt_record (emode ),
3685+ ereport (emode_for_corrupt_record (emode , * RecPtr ),
36863686(errmsg ("contrecord is requested by %X/%X" ,
36873687RecPtr -> xlogid ,RecPtr -> xrecoff )));
36883688gotonext_record_is_invalid ;
@@ -3697,15 +3697,15 @@ ReadRecord(XLogRecPtr *RecPtr, int emode, bool fetching_ckpt)
36973697{
36983698if (record -> xl_len != 0 )
36993699{
3700- ereport (emode_for_corrupt_record (emode ),
3700+ ereport (emode_for_corrupt_record (emode , * RecPtr ),
37013701(errmsg ("invalid xlog switch record at %X/%X" ,
37023702RecPtr -> xlogid ,RecPtr -> xrecoff )));
37033703gotonext_record_is_invalid ;
37043704}
37053705}
37063706else if (record -> xl_len == 0 )
37073707{
3708- ereport (emode_for_corrupt_record (emode ),
3708+ ereport (emode_for_corrupt_record (emode , * RecPtr ),
37093709(errmsg ("record with zero length at %X/%X" ,
37103710RecPtr -> xlogid ,RecPtr -> xrecoff )));
37113711gotonext_record_is_invalid ;
@@ -3714,14 +3714,14 @@ ReadRecord(XLogRecPtr *RecPtr, int emode, bool fetching_ckpt)
37143714record -> xl_tot_len > SizeOfXLogRecord + record -> xl_len +
37153715XLR_MAX_BKP_BLOCKS * (sizeof (BkpBlock )+ BLCKSZ ))
37163716{
3717- ereport (emode_for_corrupt_record (emode ),
3717+ ereport (emode_for_corrupt_record (emode , * RecPtr ),
37183718(errmsg ("invalid record length at %X/%X" ,
37193719RecPtr -> xlogid ,RecPtr -> xrecoff )));
37203720gotonext_record_is_invalid ;
37213721}
37223722if (record -> xl_rmid > RM_MAX_ID )
37233723{
3724- ereport (emode_for_corrupt_record (emode ),
3724+ ereport (emode_for_corrupt_record (emode , * RecPtr ),
37253725(errmsg ("invalid resource manager ID %u at %X/%X" ,
37263726record -> xl_rmid ,RecPtr -> xlogid ,RecPtr -> xrecoff )));
37273727gotonext_record_is_invalid ;
@@ -3734,7 +3734,7 @@ ReadRecord(XLogRecPtr *RecPtr, int emode, bool fetching_ckpt)
37343734 */
37353735if (!XLByteLT (record -> xl_prev ,* RecPtr ))
37363736{
3737- ereport (emode_for_corrupt_record (emode ),
3737+ ereport (emode_for_corrupt_record (emode , * RecPtr ),
37383738(errmsg ("record with incorrect prev-link %X/%X at %X/%X" ,
37393739record -> xl_prev .xlogid ,record -> xl_prev .xrecoff ,
37403740RecPtr -> xlogid ,RecPtr -> xrecoff )));
@@ -3750,7 +3750,7 @@ ReadRecord(XLogRecPtr *RecPtr, int emode, bool fetching_ckpt)
37503750 */
37513751if (!XLByteEQ (record -> xl_prev ,ReadRecPtr ))
37523752{
3753- ereport (emode_for_corrupt_record (emode ),
3753+ ereport (emode_for_corrupt_record (emode , * RecPtr ),
37543754(errmsg ("record with incorrect prev-link %X/%X at %X/%X" ,
37553755record -> xl_prev .xlogid ,record -> xl_prev .xrecoff ,
37563756RecPtr -> xlogid ,RecPtr -> xrecoff )));
@@ -3779,7 +3779,7 @@ ReadRecord(XLogRecPtr *RecPtr, int emode, bool fetching_ckpt)
37793779{
37803780readRecordBufSize = 0 ;
37813781/* We treat this as a "bogus data" condition */
3782- ereport (emode_for_corrupt_record (emode ),
3782+ ereport (emode_for_corrupt_record (emode , * RecPtr ),
37833783(errmsg ("record length %u at %X/%X too long" ,
37843784total_len ,RecPtr -> xlogid ,RecPtr -> xrecoff )));
37853785gotonext_record_is_invalid ;
@@ -3819,7 +3819,7 @@ ReadRecord(XLogRecPtr *RecPtr, int emode, bool fetching_ckpt)
38193819/* Check that the continuation record looks valid */
38203820if (!(((XLogPageHeader )readBuf )-> xlp_info & XLP_FIRST_IS_CONTRECORD ))
38213821{
3822- ereport (emode_for_corrupt_record (emode ),
3822+ ereport (emode_for_corrupt_record (emode , * RecPtr ),
38233823(errmsg ("there is no contrecord flag in log file %u, segment %u, offset %u" ,
38243824readId ,readSeg ,readOff )));
38253825gotonext_record_is_invalid ;
@@ -3829,7 +3829,7 @@ ReadRecord(XLogRecPtr *RecPtr, int emode, bool fetching_ckpt)
38293829if (contrecord -> xl_rem_len == 0 ||
38303830total_len != (contrecord -> xl_rem_len + gotlen ))
38313831{
3832- ereport (emode_for_corrupt_record (emode ),
3832+ ereport (emode_for_corrupt_record (emode , * RecPtr ),
38333833(errmsg ("invalid contrecord length %u in log file %u, segment %u, offset %u" ,
38343834contrecord -> xl_rem_len ,
38353835readId ,readSeg ,readOff )));
@@ -3847,7 +3847,7 @@ ReadRecord(XLogRecPtr *RecPtr, int emode, bool fetching_ckpt)
38473847contrecord -> xl_rem_len );
38483848break ;
38493849}
3850- if (!RecordIsValid (record ,* RecPtr ,emode_for_corrupt_record ( emode ) ))
3850+ if (!RecordIsValid (record ,* RecPtr ,emode ))
38513851gotonext_record_is_invalid ;
38523852pageHeaderSize = XLogPageHeaderSize ((XLogPageHeader )readBuf );
38533853EndRecPtr .xlogid = readId ;
@@ -3861,7 +3861,7 @@ ReadRecord(XLogRecPtr *RecPtr, int emode, bool fetching_ckpt)
38613861}
38623862
38633863/* Record does not cross a page boundary */
3864- if (!RecordIsValid (record ,* RecPtr ,emode_for_corrupt_record ( emode ) ))
3864+ if (!RecordIsValid (record ,* RecPtr ,emode ))
38653865gotonext_record_is_invalid ;
38663866EndRecPtr .xlogid = RecPtr -> xlogid ;
38673867EndRecPtr .xrecoff = RecPtr -> xrecoff + MAXALIGN (total_len );
@@ -3914,16 +3914,19 @@ ValidXLOGHeader(XLogPageHeader hdr, int emode)
39143914{
39153915XLogRecPtr recaddr ;
39163916
3917+ recaddr .xlogid = readId ;
3918+ recaddr .xrecoff = readSeg * XLogSegSize + readOff ;
3919+
39173920if (hdr -> xlp_magic != XLOG_PAGE_MAGIC )
39183921{
3919- ereport (emode ,
3922+ ereport (emode_for_corrupt_record ( emode , recaddr ) ,
39203923(errmsg ("invalid magic number %04X in log file %u, segment %u, offset %u" ,
39213924hdr -> xlp_magic ,readId ,readSeg ,readOff )));
39223925return false;
39233926}
39243927if ((hdr -> xlp_info & ~XLP_ALL_FLAGS )!= 0 )
39253928{
3926- ereport (emode ,
3929+ ereport (emode_for_corrupt_record ( emode , recaddr ) ,
39273930(errmsg ("invalid info bits %04X in log file %u, segment %u, offset %u" ,
39283931hdr -> xlp_info ,readId ,readSeg ,readOff )));
39293932return false;
@@ -3945,22 +3948,22 @@ ValidXLOGHeader(XLogPageHeader hdr, int emode)
39453948longhdr -> xlp_sysid );
39463949snprintf (sysident_str ,sizeof (sysident_str ),UINT64_FORMAT ,
39473950ControlFile -> system_identifier );
3948- ereport (emode ,
3951+ ereport (emode_for_corrupt_record ( emode , recaddr ) ,
39493952(errmsg ("WAL file is from different database system" ),
39503953errdetail ("WAL file database system identifier is %s, pg_control database system identifier is %s." ,
39513954fhdrident_str ,sysident_str )));
39523955return false;
39533956}
39543957if (longhdr -> xlp_seg_size != XLogSegSize )
39553958{
3956- ereport (emode ,
3959+ ereport (emode_for_corrupt_record ( emode , recaddr ) ,
39573960(errmsg ("WAL file is from different database system" ),
39583961errdetail ("Incorrect XLOG_SEG_SIZE in page header." )));
39593962return false;
39603963}
39613964if (longhdr -> xlp_xlog_blcksz != XLOG_BLCKSZ )
39623965{
3963- ereport (emode ,
3966+ ereport (emode_for_corrupt_record ( emode , recaddr ) ,
39643967(errmsg ("WAL file is from different database system" ),
39653968errdetail ("Incorrect XLOG_BLCKSZ in page header." )));
39663969return false;
@@ -3969,17 +3972,15 @@ ValidXLOGHeader(XLogPageHeader hdr, int emode)
39693972else if (readOff == 0 )
39703973{
39713974/* hmm, first page of file doesn't have a long header? */
3972- ereport (emode ,
3975+ ereport (emode_for_corrupt_record ( emode , recaddr ) ,
39733976(errmsg ("invalid info bits %04X in log file %u, segment %u, offset %u" ,
39743977hdr -> xlp_info ,readId ,readSeg ,readOff )));
39753978return false;
39763979}
39773980
3978- recaddr .xlogid = readId ;
3979- recaddr .xrecoff = readSeg * XLogSegSize + readOff ;
39803981if (!XLByteEQ (hdr -> xlp_pageaddr ,recaddr ))
39813982{
3982- ereport (emode ,
3983+ ereport (emode_for_corrupt_record ( emode , recaddr ) ,
39833984(errmsg ("unexpected pageaddr %X/%X in log file %u, segment %u, offset %u" ,
39843985hdr -> xlp_pageaddr .xlogid ,hdr -> xlp_pageaddr .xrecoff ,
39853986readId ,readSeg ,readOff )));
@@ -3991,7 +3992,7 @@ ValidXLOGHeader(XLogPageHeader hdr, int emode)
39913992 */
39923993if (!list_member_int (expectedTLIs , (int )hdr -> xlp_tli ))
39933994{
3994- ereport (emode ,
3995+ ereport (emode_for_corrupt_record ( emode , recaddr ) ,
39953996(errmsg ("unexpected timeline ID %u in log file %u, segment %u, offset %u" ,
39963997hdr -> xlp_tli ,
39973998readId ,readSeg ,readOff )));
@@ -4009,7 +4010,7 @@ ValidXLOGHeader(XLogPageHeader hdr, int emode)
40094010 */
40104011if (hdr -> xlp_tli < lastPageTLI )
40114012{
4012- ereport (emode ,
4013+ ereport (emode_for_corrupt_record ( emode , recaddr ) ,
40134014(errmsg ("out-of-sequence timeline ID %u (after %u) in log file %u, segment %u, offset %u" ,
40144015hdr -> xlp_tli ,lastPageTLI ,
40154016readId ,readSeg ,readOff )));
@@ -9245,36 +9246,35 @@ XLogPageRead(XLogRecPtr *RecPtr, int emode, bool fetching_ckpt,
92459246readOff = 0 ;
92469247if (read (readFile ,readBuf ,XLOG_BLCKSZ )!= XLOG_BLCKSZ )
92479248{
9248- ereport (emode_for_corrupt_record (emode ),
9249+ ereport (emode_for_corrupt_record (emode , * RecPtr ),
92499250(errcode_for_file_access (),
92509251errmsg ("could not read from log file %u, segment %u, offset %u: %m" ,
92519252readId ,readSeg ,readOff )));
92529253gotonext_record_is_invalid ;
92539254}
9254- if (!ValidXLOGHeader ((XLogPageHeader )readBuf ,
9255- emode_for_corrupt_record (emode )))
9255+ if (!ValidXLOGHeader ((XLogPageHeader )readBuf ,emode ))
92569256gotonext_record_is_invalid ;
92579257}
92589258
92599259/* Read the requested page */
92609260readOff = targetPageOff ;
92619261if (lseek (readFile , (off_t )readOff ,SEEK_SET )< 0 )
92629262{
9263- ereport (emode_for_corrupt_record (emode ),
9263+ ereport (emode_for_corrupt_record (emode , * RecPtr ),
92649264(errcode_for_file_access (),
92659265errmsg ("could not seek in log file %u, segment %u to offset %u: %m" ,
92669266readId ,readSeg ,readOff )));
92679267gotonext_record_is_invalid ;
92689268}
92699269if (read (readFile ,readBuf ,XLOG_BLCKSZ )!= XLOG_BLCKSZ )
92709270{
9271- ereport (emode_for_corrupt_record (emode ),
9271+ ereport (emode_for_corrupt_record (emode , * RecPtr ),
92729272(errcode_for_file_access (),
92739273errmsg ("could not read from log file %u, segment %u, offset %u: %m" ,
92749274readId ,readSeg ,readOff )));
92759275gotonext_record_is_invalid ;
92769276}
9277- if (!ValidXLOGHeader ((XLogPageHeader )readBuf ,emode_for_corrupt_record ( emode ) ))
9277+ if (!ValidXLOGHeader ((XLogPageHeader )readBuf ,emode ))
92789278gotonext_record_is_invalid ;
92799279
92809280Assert (targetId == readId );
@@ -9316,10 +9316,17 @@ XLogPageRead(XLogRecPtr *RecPtr, int emode, bool fetching_ckpt,
93169316 * 'emode' is the error mode that would be used to report a file-not-found
93179317 * or legitimate end-of-WAL situation. It is upgraded to WARNING or PANIC
93189318 * if a corrupt record is not expected at this point.
9319+ *
9320+ * NOTE: This function remembers the RecPtr value it was last called with,
9321+ * to suppress repeated messages about the same record. Only call this when
9322+ * you are about to ereport(), or you might cause a later message to be
9323+ * erroneously suppressed.
93199324 */
93209325static int
9321- emode_for_corrupt_record (int emode )
9326+ emode_for_corrupt_record (int emode , XLogRecPtr RecPtr )
93229327{
9328+ static XLogRecPtr lastComplaint = {0 ,0 };
9329+
93239330/*
93249331 * We don't expect any invalid records in archive or in records streamed
93259332 * from master. Files in the archive should be complete, and we should
@@ -9340,6 +9347,17 @@ emode_for_corrupt_record(int emode)
93409347if (emode < WARNING )
93419348emode = WARNING ;
93429349}
9350+ /*
9351+ * If we retry reading a record in pg_xlog, only complain on the first
9352+ * time to keep the noise down.
9353+ */
9354+ else if (emode == LOG )
9355+ {
9356+ if (XLByteEQ (RecPtr ,lastComplaint ))
9357+ emode = DEBUG1 ;
9358+ else
9359+ lastComplaint = RecPtr ;
9360+ }
93439361return emode ;
93449362}
93459363