Skip to content

Commit 0ffe11a

Browse files
committed
Widen xl_len field of XLogRecord header to 32 bits, so that we'll have
a more tolerable limit on the number of subtransactions or deleted files in COMMIT and ABORT records. Buy back the extra space by eliminating the xl_xact_prev field, which isn't being used for anything and is rather unlikely ever to be used for anything. This does not force initdb, but you do need to do pg_resetxlog if you want to upgrade an existing 8.0 installation without initdb.
1 parent b6b71b8 commit 0ffe11a

File tree

4 files changed

+68
-71
lines changed

4 files changed

+68
-71
lines changed

src/backend/access/transam/xlog.c

Lines changed: 61 additions & 55 deletions
Original file line numberDiff line numberDiff line change
@@ -7,7 +7,7 @@
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/29 05:06:40 momjian Exp $
10+
* $PostgreSQL: pgsql/src/backend/access/transam/xlog.c,v 1.167 2004/08/29 16:34:47 tgl Exp $
1111
*
1212
*-------------------------------------------------------------------------
1313
*/
@@ -409,6 +409,10 @@ static uint32 readOff = 0;
409409
/* Buffer for currently read page (BLCKSZ bytes) */
410410
static 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 */
413417
static XLogRecPtr ReadRecPtr;
414418
static XLogRecPtr EndRecPtr;
@@ -440,11 +444,9 @@ static bool RestoreArchivedFile(char *path, const char *xlogfname,
440444
const char *recovername, off_t expectedSize);
441445
static void PreallocXlogFiles(XLogRecPtr endptr);
442446
static 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);
444448
static 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);
448450
static List *readTimeLineHistory(TimeLineID targetTLI);
449451
static bool existsTimeLineHistory(TimeLineID probeTLI);
450452
static 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)
631633
elog(PANIC, "invalid xlog record length %u", len);
632634

633635
START_CRIT_SECTION();
@@ -745,14 +747,6 @@ begin:;
745747
/* Insert record header */
746748

747749
record->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-
756750
record->xl_xid = GetCurrentTransactionId();
757751
record->xl_len = len; /* doesn't include backup blocks */
758752
record->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
*/
23232316
static XLogRecord *
2324-
ReadRecord(XLogRecPtr *RecPtr, int emode, char *buffer)
2317+
ReadRecord(XLogRecPtr *RecPtr, int emode)
23252318
{
23262319
XLogRecord *record;
2320+
char *buffer;
23272321
XLogRecPtr tmpRecPtr = EndRecPtr;
23282322
bool randAccess = false;
23292323
uint32 len,
@@ -2467,6 +2461,13 @@ got_record:;
24672461
RecPtr->xlogid, RecPtr->xrecoff)));
24682462
goto next_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+
goto next_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-
goto next_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-
goto next_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+
goto next_record_is_invalid;
2508+
}
2509+
readRecordBufSize = newSize;
25012510
}
2511+
2512+
buffer = readRecordBuf;
25022513
nextRecord = NULL;
25032514
len = BLCKSZ - RecPtr->xrecoff % BLCKSZ;
25042515
if (total_len > len)
@@ -3481,8 +3492,6 @@ BootStrapXLOG(void)
34813492
record = (XLogRecord *) ((char *) page + SizeOfXLogLongPHD);
34823493
record->xl_prev.xlogid = 0;
34833494
record->xl_prev.xrecoff = 0;
3484-
record->xl_xact_prev.xlogid = 0;
3485-
record->xl_xact_prev.xrecoff = 0;
34863495
record->xl_xid = InvalidTransactionId;
34873496
record->xl_len = sizeof(checkPoint);
34883497
record->xl_info = XLOG_CHECKPOINT_SHUTDOWN;
@@ -3981,12 +3990,8 @@ StartupXLOG(void)
39813990
uint32 endLogId;
39823991
uint32 endLogSeg;
39833992
XLogRecord *record;
3984-
char *buffer;
39853993
uint32 freespace;
39863994

3987-
/* Use malloc() to ensure record buffer is MAXALIGNED */
3988-
buffer = (char *) malloc(_INTL_MAXLOGRECSZ);
3989-
39903995
CritSectionCount++;
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);
40674072
if (record != NULL)
40684073
{
40694074
ereport(LOG,
@@ -4085,7 +4090,7 @@ StartupXLOG(void)
40854090
* according to pg_control is broken, try the next-to-last one.
40864091
*/
40874092
checkPointLoc = ControlFile->checkPoint;
4088-
record = ReadCheckpointRecord(checkPointLoc, 1, buffer);
4093+
record = ReadCheckpointRecord(checkPointLoc, 1);
40894094
if (record != NULL)
40904095
{
40914096
ereport(LOG,
@@ -4095,7 +4100,7 @@ StartupXLOG(void)
40954100
else
40964101
{
40974102
checkPointLoc = ControlFile->prevCheckPoint;
4098-
record = ReadCheckpointRecord(checkPointLoc, 2, buffer);
4103+
record = ReadCheckpointRecord(checkPointLoc, 2);
40994104
if (record != NULL)
41004105
{
41014106
ereport(LOG,
@@ -4198,12 +4203,12 @@ StartupXLOG(void)
41984203
if (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
}
42034208
else
42044209
{
42054210
/* just have to read next record after CheckPoint */
4206-
record = ReadRecord(NULL, LOG, buffer);
4211+
record = ReadRecord(NULL, LOG);
42074212
}
42084213

42094214
if (record != NULL)
@@ -4263,7 +4268,7 @@ StartupXLOG(void)
42634268

42644269
LastRec = 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);
42914296
EndOfLog = EndRecPtr;
42924297
XLByteToPrevSeg(EndOfLog, endLogId, endLogSeg);
42934298

@@ -4404,7 +4409,7 @@ StartupXLOG(void)
44044409
RecPtr.xlogid, RecPtr.xrecoff)));
44054410
do
44064411
{
4407-
record = ReadRecord(&RecPtr, PANIC, buffer);
4412+
record = ReadRecord(&RecPtr, PANIC);
44084413
if (TransactionIdIsValid(record->xl_xid) &&
44094414
!TransactionIdDidCommit(record->xl_xid))
44104415
RmgrTable[record->xl_rmid].rm_undo(EndRecPtr, record);
@@ -4498,8 +4503,12 @@ StartupXLOG(void)
44984503
free(readBuf);
44994504
readBuf = 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
*/
45114520
static XLogRecord *
4512-
ReadCheckpointRecord(XLogRecPtr RecPtr,
4513-
int whichChkpt,
4514-
char *buffer)
4521+
ReadCheckpointRecord(XLogRecPtr RecPtr, int whichChkpt)
45154522
{
45164523
XLogRecord *record;
45174524

@@ -4535,7 +4542,7 @@ ReadCheckpointRecord(XLogRecPtr RecPtr,
45354542
return NULL;
45364543
}
45374544

4538-
record = ReadRecord(&RecPtr, LOG, buffer);
4545+
record = ReadRecord(&RecPtr, LOG);
45394546

45404547
if (record == NULL)
45414548
{
@@ -5080,9 +5087,8 @@ xlog_outrec(char *buf, XLogRecord *record)
50805087
int bkpb;
50815088
int 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",
50845091
record->xl_prev.xlogid, record->xl_prev.xrecoff,
5085-
record->xl_xact_prev.xlogid, record->xl_xact_prev.xrecoff,
50865092
record->xl_xid);
50875093

50885094
for (i = 0, bkpb = 0; i < XLR_MAX_BKP_BLOCKS; i++)

src/bin/pg_resetxlog/pg_resetxlog.c

Lines changed: 1 addition & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -23,7 +23,7 @@
2323
* Portions Copyright (c) 1996-2004, PostgreSQL Global Development Group
2424
* Portions Copyright (c) 1994, Regents of the University of California
2525
*
26-
* $PostgreSQL: pgsql/src/bin/pg_resetxlog/pg_resetxlog.c,v 1.23 2004/08/29 05:06:54 momjian Exp $
26+
* $PostgreSQL: pgsql/src/bin/pg_resetxlog/pg_resetxlog.c,v 1.24 2004/08/29 16:34:48 tgl Exp $
2727
*
2828
*-------------------------------------------------------------------------
2929
*/
@@ -645,8 +645,6 @@ WriteEmptyXLOG(void)
645645
record = (XLogRecord *) ((char *) page + SizeOfXLogLongPHD);
646646
record->xl_prev.xlogid = 0;
647647
record->xl_prev.xrecoff = 0;
648-
record->xl_xact_prev.xlogid = 0;
649-
record->xl_xact_prev.xrecoff = 0;
650648
record->xl_xid = InvalidTransactionId;
651649
record->xl_len = sizeof(CheckPoint);
652650
record->xl_info = XLOG_CHECKPOINT_SHUTDOWN;

src/include/access/xlog.h

Lines changed: 4 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -6,7 +6,7 @@
66
* Portions Copyright (c) 1996-2004, PostgreSQL Global Development Group
77
* Portions Copyright (c) 1994, Regents of the University of California
88
*
9-
* $PostgreSQL: pgsql/src/include/access/xlog.h,v 1.57 2004/08/29 05:06:55 momjian Exp $
9+
* $PostgreSQL: pgsql/src/include/access/xlog.h,v 1.58 2004/08/29 16:34:48 tgl Exp $
1010
*/
1111
#ifndef XLOG_H
1212
#define XLOG_H
@@ -35,18 +35,18 @@ typedef struct XLogRecord
3535
{
3636
crc64 xl_crc; /* CRC for this record */
3737
XLogRecPtr xl_prev; /* ptr to previous record in log */
38-
XLogRecPtr xl_xact_prev; /* ptr to previous record of this xact */
3938
TransactionId xl_xid; /* xact id */
40-
uint16 xl_len; /* total len of rmgr data */
39+
uint32 xl_len; /* total len of rmgr data */
4140
uint8 xl_info; /* flag bits, see below */
4241
RmgrId xl_rmid; /* resource manager for this record */
4342

43+
/* Depending on MAXALIGN, there are either 2 or 6 wasted bytes here */
44+
4445
/* ACTUAL LOG DATA FOLLOWS AT END OF STRUCT */
4546

4647
} XLogRecord;
4748

4849
#define SizeOfXLogRecord MAXALIGN(sizeof(XLogRecord))
49-
#define MAXLOGRECSZ 65535 /* the most that'll fit in xl_len */
5050

5151
#define XLogRecGetData(record) ((char*) (record) + SizeOfXLogRecord)
5252

src/include/access/xlog_internal.h

Lines changed: 2 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -11,7 +11,7 @@
1111
* Portions Copyright (c) 1996-2004, PostgreSQL Global Development Group
1212
* Portions Copyright (c) 1994, Regents of the University of California
1313
*
14-
* $PostgreSQL: pgsql/src/include/access/xlog_internal.h,v 1.4 2004/08/29 05:06:55 momjian Exp $
14+
* $PostgreSQL: pgsql/src/include/access/xlog_internal.h,v 1.5 2004/08/29 16:34:48 tgl Exp $
1515
*/
1616
#ifndef XLOG_INTERNAL_H
1717
#define XLOG_INTERNAL_H
@@ -58,7 +58,7 @@ typedef struct XLogContRecord
5858
/*
5959
* Each page of XLOG file has a header like this:
6060
*/
61-
#define XLOG_PAGE_MAGIC 0xD05B /* can be used as WAL version indicator */
61+
#define XLOG_PAGE_MAGIC 0xD05C /* can be used as WAL version indicator */
6262

6363
typedef struct XLogPageHeaderData
6464
{
@@ -203,13 +203,6 @@ typedef XLogLongPageHeaderData *XLogLongPageHeader;
203203

204204
extern char XLogDir[MAXPGPATH];
205205

206-
/*
207-
* _INTL_MAXLOGRECSZ: max space needed for a record including header and
208-
* any backup-block data.
209-
*/
210-
#define _INTL_MAXLOGRECSZ (SizeOfXLogRecord + MAXLOGRECSZ + \
211-
XLR_MAX_BKP_BLOCKS * (sizeof(BkpBlock) + BLCKSZ))
212-
213206

214207
/*
215208
* Method table for resource managers.

0 commit comments

Comments
 (0)
pFad - Phonifier reborn

Pfad - The Proxy pFad of © 2024 Garber Painting. All rights reserved.

Note: This service is not intended for secure transactions such as banking, social media, email, or purchasing. Use at your own risk. We assume no liability whatsoever for broken pages.


Alternative Proxies:

Alternative Proxy

pFad Proxy

pFad v3 Proxy

pFad v4 Proxy