Location via proxy:   [ UP ]  
[Report a bug]   [Manage cookies]                
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

+61-55
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

+1-3
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

+4-4
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

+2-9
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)