77 * Portions Copyright (c) 1996-2004, 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.166 2004/08/2905:06:40 momjian Exp $
10+ * $PostgreSQL: pgsql/src/backend/access/transam/xlog.c,v 1.167 2004/08/2916:34:47 tgl Exp $
1111 *
1212 *-------------------------------------------------------------------------
1313 */
@@ -409,6 +409,10 @@ static uint32 readOff = 0;
409409/* Buffer for currently read page (BLCKSZ bytes) */
410410static char * readBuf = NULL ;
411411
412+ /* Buffer for current ReadRecord result (expandable) */
413+ static char * readRecordBuf = NULL ;
414+ static uint32 readRecordBufSize = 0 ;
415+
412416/* State information for XLOG reading */
413417static XLogRecPtr ReadRecPtr ;
414418static XLogRecPtr EndRecPtr ;
@@ -440,11 +444,9 @@ static bool RestoreArchivedFile(char *path, const char *xlogfname,
440444const char * recovername ,off_t expectedSize );
441445static void PreallocXlogFiles (XLogRecPtr endptr );
442446static void MoveOfflineLogs (uint32 log ,uint32 seg ,XLogRecPtr endptr );
443- static XLogRecord * ReadRecord (XLogRecPtr * RecPtr ,int emode , char * buffer );
447+ static XLogRecord * ReadRecord (XLogRecPtr * RecPtr ,int emode );
444448static bool ValidXLOGHeader (XLogPageHeader hdr ,int emode );
445- static XLogRecord * ReadCheckpointRecord (XLogRecPtr RecPtr ,
446- int whichChkpt ,
447- char * buffer );
449+ static XLogRecord * ReadCheckpointRecord (XLogRecPtr RecPtr ,int whichChkpt );
448450static List * readTimeLineHistory (TimeLineID targetTLI );
449451static bool existsTimeLineHistory (TimeLineID probeTLI );
450452static TimeLineID findNewestTimeLine (TimeLineID startTLI );
@@ -627,7 +629,7 @@ begin:;
627629 * may not be true forever. If you need to remove the len == 0 check,
628630 * also remove the check for xl_len == 0 in ReadRecord, below.
629631 */
630- if (len == 0 || len > MAXLOGRECSZ )
632+ if (len == 0 )
631633elog (PANIC ,"invalid xlog record length %u" ,len );
632634
633635START_CRIT_SECTION ();
@@ -745,14 +747,6 @@ begin:;
745747/* Insert record header */
746748
747749record -> xl_prev = Insert -> PrevRecord ;
748- if (no_tran )
749- {
750- record -> xl_xact_prev .xlogid = 0 ;
751- record -> xl_xact_prev .xrecoff = 0 ;
752- }
753- else
754- record -> xl_xact_prev = MyLastRecPtr ;
755-
756750record -> xl_xid = GetCurrentTransactionId ();
757751record -> xl_len = len ;/* doesn't include backup blocks */
758752record -> xl_info = info ;
@@ -2316,14 +2310,14 @@ RecordIsValid(XLogRecord *record, XLogRecPtr recptr, int emode)
23162310 * If no valid record is available, returns NULL, or fails if emode is PANIC.
23172311 * (emode must be either PANIC or LOG.)
23182312 *
2319- * buffer is a workspace at least _INTL_MAXLOGRECSZ bytes long. It is needed
2320- * to reassemble a record that crosses block boundaries. Note that on
2321- * successful return, the returned record pointer always points at buffer.
2313+ * The record is copied into readRecordBuf, so that on successful return,
2314+ * the returned record pointer always points there.
23222315 */
23232316static XLogRecord *
2324- ReadRecord (XLogRecPtr * RecPtr ,int emode , char * buffer )
2317+ ReadRecord (XLogRecPtr * RecPtr ,int emode )
23252318{
23262319XLogRecord * record ;
2320+ char * buffer ;
23272321XLogRecPtr tmpRecPtr = EndRecPtr ;
23282322bool randAccess = false;
23292323uint32 len ,
@@ -2467,6 +2461,13 @@ got_record:;
24672461RecPtr -> xlogid ,RecPtr -> xrecoff )));
24682462gotonext_record_is_invalid ;
24692463}
2464+ if (record -> xl_rmid > RM_MAX_ID )
2465+ {
2466+ ereport (emode ,
2467+ (errmsg ("invalid resource manager ID %u at %X/%X" ,
2468+ record -> xl_rmid ,RecPtr -> xlogid ,RecPtr -> xrecoff )));
2469+ gotonext_record_is_invalid ;
2470+ }
24702471
24712472/*
24722473 * Compute total length of record including any appended backup
@@ -2481,24 +2482,34 @@ got_record:;
24812482}
24822483
24832484/*
2484- * Make sure it will fit in buffer (currently, it is mechanically
2485- * impossible for this test to fail, but it seems like a good idea
2486- * anyway).
2485+ * Allocate or enlarge readRecordBuf as needed. To avoid useless
2486+ * small increases, round its size to a multiple of BLCKSZ, and make
2487+ * sure it's at least 4*BLCKSZ to start with. (That is enough for
2488+ * all "normal" records, but very large commit or abort records might
2489+ * need more space.)
24872490 */
2488- if (total_len > _INTL_MAXLOGRECSZ )
2489- {
2490- ereport (emode ,
2491- (errmsg ("record length %u at %X/%X too long" ,
2492- total_len ,RecPtr -> xlogid ,RecPtr -> xrecoff )));
2493- gotonext_record_is_invalid ;
2494- }
2495- if (record -> xl_rmid > RM_MAX_ID )
2491+ if (total_len > readRecordBufSize )
24962492{
2497- ereport (emode ,
2498- (errmsg ("invalid resource manager ID %u at %X/%X" ,
2499- record -> xl_rmid ,RecPtr -> xlogid ,RecPtr -> xrecoff )));
2500- gotonext_record_is_invalid ;
2493+ uint32 newSize = total_len ;
2494+
2495+ newSize += BLCKSZ - (newSize %BLCKSZ );
2496+ newSize = Max (newSize ,4 * BLCKSZ );
2497+ if (readRecordBuf )
2498+ free (readRecordBuf );
2499+ readRecordBuf = (char * )malloc (newSize );
2500+ if (!readRecordBuf )
2501+ {
2502+ readRecordBufSize = 0 ;
2503+ /* We treat this as a "bogus data" condition */
2504+ ereport (emode ,
2505+ (errmsg ("record length %u at %X/%X too long" ,
2506+ total_len ,RecPtr -> xlogid ,RecPtr -> xrecoff )));
2507+ gotonext_record_is_invalid ;
2508+ }
2509+ readRecordBufSize = newSize ;
25012510}
2511+
2512+ buffer = readRecordBuf ;
25022513nextRecord = NULL ;
25032514len = BLCKSZ - RecPtr -> xrecoff %BLCKSZ ;
25042515if (total_len > len )
@@ -3481,8 +3492,6 @@ BootStrapXLOG(void)
34813492record = (XLogRecord * ) ((char * )page + SizeOfXLogLongPHD );
34823493record -> xl_prev .xlogid = 0 ;
34833494record -> xl_prev .xrecoff = 0 ;
3484- record -> xl_xact_prev .xlogid = 0 ;
3485- record -> xl_xact_prev .xrecoff = 0 ;
34863495record -> xl_xid = InvalidTransactionId ;
34873496record -> xl_len = sizeof (checkPoint );
34883497record -> xl_info = XLOG_CHECKPOINT_SHUTDOWN ;
@@ -3981,12 +3990,8 @@ StartupXLOG(void)
39813990uint32 endLogId ;
39823991uint32 endLogSeg ;
39833992XLogRecord * record ;
3984- char * buffer ;
39853993uint32 freespace ;
39863994
3987- /* Use malloc() to ensure record buffer is MAXALIGNED */
3988- buffer = (char * )malloc (_INTL_MAXLOGRECSZ );
3989-
39903995CritSectionCount ++ ;
39913996
39923997/*
@@ -4063,7 +4068,7 @@ StartupXLOG(void)
40634068 * from the checkpoint it identifies, rather than using
40644069 * pg_control.
40654070 */
4066- record = ReadCheckpointRecord (checkPointLoc ,0 , buffer );
4071+ record = ReadCheckpointRecord (checkPointLoc ,0 );
40674072if (record != NULL )
40684073{
40694074ereport (LOG ,
@@ -4085,7 +4090,7 @@ StartupXLOG(void)
40854090 * according to pg_control is broken, try the next-to-last one.
40864091 */
40874092checkPointLoc = ControlFile -> checkPoint ;
4088- record = ReadCheckpointRecord (checkPointLoc ,1 , buffer );
4093+ record = ReadCheckpointRecord (checkPointLoc ,1 );
40894094if (record != NULL )
40904095{
40914096ereport (LOG ,
@@ -4095,7 +4100,7 @@ StartupXLOG(void)
40954100else
40964101{
40974102checkPointLoc = ControlFile -> prevCheckPoint ;
4098- record = ReadCheckpointRecord (checkPointLoc ,2 , buffer );
4103+ record = ReadCheckpointRecord (checkPointLoc ,2 );
40994104if (record != NULL )
41004105{
41014106ereport (LOG ,
@@ -4198,12 +4203,12 @@ StartupXLOG(void)
41984203if (XLByteLT (checkPoint .redo ,RecPtr ))
41994204{
42004205/* back up to find the record */
4201- record = ReadRecord (& (checkPoint .redo ),PANIC , buffer );
4206+ record = ReadRecord (& (checkPoint .redo ),PANIC );
42024207}
42034208else
42044209{
42054210/* just have to read next record after CheckPoint */
4206- record = ReadRecord (NULL ,LOG , buffer );
4211+ record = ReadRecord (NULL ,LOG );
42074212}
42084213
42094214if (record != NULL )
@@ -4263,7 +4268,7 @@ StartupXLOG(void)
42634268
42644269LastRec = ReadRecPtr ;
42654270
4266- record = ReadRecord (NULL ,LOG , buffer );
4271+ record = ReadRecord (NULL ,LOG );
42674272}while (record != NULL && recoveryContinue );
42684273
42694274/*
@@ -4287,7 +4292,7 @@ StartupXLOG(void)
42874292 * Re-fetch the last valid or last applied record, so we can identify
42884293 * the exact endpoint of what we consider the valid portion of WAL.
42894294 */
4290- record = ReadRecord (& LastRec ,PANIC , buffer );
4295+ record = ReadRecord (& LastRec ,PANIC );
42914296EndOfLog = EndRecPtr ;
42924297XLByteToPrevSeg (EndOfLog ,endLogId ,endLogSeg );
42934298
@@ -4404,7 +4409,7 @@ StartupXLOG(void)
44044409RecPtr .xlogid ,RecPtr .xrecoff )));
44054410do
44064411{
4407- record = ReadRecord (& RecPtr ,PANIC , buffer );
4412+ record = ReadRecord (& RecPtr ,PANIC );
44084413if (TransactionIdIsValid (record -> xl_xid )&&
44094414!TransactionIdDidCommit (record -> xl_xid ))
44104415RmgrTable [record -> xl_rmid ].rm_undo (EndRecPtr ,record );
@@ -4498,8 +4503,12 @@ StartupXLOG(void)
44984503free (readBuf );
44994504readBuf = NULL ;
45004505}
4501-
4502- free (buffer );
4506+ if (readRecordBuf )
4507+ {
4508+ free (readRecordBuf );
4509+ readRecordBuf = NULL ;
4510+ readRecordBufSize = 0 ;
4511+ }
45034512}
45044513
45054514/*
@@ -4509,9 +4518,7 @@ StartupXLOG(void)
45094518 * 1 for "primary", 2 for "secondary", 0 for "other" (backup_label)
45104519 */
45114520static XLogRecord *
4512- ReadCheckpointRecord (XLogRecPtr RecPtr ,
4513- int whichChkpt ,
4514- char * buffer )
4521+ ReadCheckpointRecord (XLogRecPtr RecPtr ,int whichChkpt )
45154522{
45164523XLogRecord * record ;
45174524
@@ -4535,7 +4542,7 @@ ReadCheckpointRecord(XLogRecPtr RecPtr,
45354542return NULL ;
45364543}
45374544
4538- record = ReadRecord (& RecPtr ,LOG , buffer );
4545+ record = ReadRecord (& RecPtr ,LOG );
45394546
45404547if (record == NULL )
45414548{
@@ -5080,9 +5087,8 @@ xlog_outrec(char *buf, XLogRecord *record)
50805087int bkpb ;
50815088int i ;
50825089
5083- sprintf (buf + strlen (buf ),"prev %X/%X;xprev %X/%X; xid %u" ,
5090+ sprintf (buf + strlen (buf ),"prev %X/%X; xid %u" ,
50845091record -> xl_prev .xlogid ,record -> xl_prev .xrecoff ,
5085- record -> xl_xact_prev .xlogid ,record -> xl_xact_prev .xrecoff ,
50865092record -> xl_xid );
50875093
50885094for (i = 0 ,bkpb = 0 ;i < XLR_MAX_BKP_BLOCKS ;i ++ )