Skip to content

Commit 2b3e467

Browse files
committed
Don't ERROR on PreallocXlogFiles() race condition.
Before a restartpoint finishes PreallocXlogFiles(), a startup process KeepFileRestoredFromArchive() call can unlink the preallocated segment. If a CHECKPOINT sql command had elicited the restartpoint experiencing the race condition, that sql command failed. Moreover, the restartpoint omitted its log_checkpoints message and some inessential resource reclamation. Prevent the ERROR by skipping open() of the segment. Since these consequences are so minor, no back-patch. Discussion: https://postgr.es/m/20210202151416.GB3304930@rfd.leadboat.com
1 parent 421484f commit 2b3e467

File tree

3 files changed

+58
-27
lines changed

3 files changed

+58
-27
lines changed

src/backend/access/transam/xlog.c

Lines changed: 56 additions & 23 deletions
Original file line numberDiff line numberDiff line change
@@ -2424,7 +2424,6 @@ XLogWrite(XLogwrtRqst WriteRqst, bool flexible)
24242424
bool ispartialpage;
24252425
bool last_iteration;
24262426
bool finishing_seg;
2427-
bool added;
24282427
int curridx;
24292428
int npages;
24302429
int startidx;
@@ -2490,7 +2489,7 @@ XLogWrite(XLogwrtRqst WriteRqst, bool flexible)
24902489
wal_segment_size);
24912490

24922491
/* create/use new log file */
2493-
openLogFile = XLogFileInit(openLogSegNo, &added);
2492+
openLogFile = XLogFileInit(openLogSegNo);
24942493
ReserveExternalFD();
24952494
}
24962495

@@ -3255,23 +3254,21 @@ XLogNeedsFlush(XLogRecPtr record)
32553254
}
32563255

32573256
/*
3258-
* Create a new XLOG file segment, or open a pre-existing one.
3257+
* Try to make a given XLOG file segment exist.
32593258
*
3260-
* logsegno: identify segment to be created/opened.
3259+
* logsegno: identify segment.
32613260
*
32623261
* *added: on return, true if this call raised the number of extant segments.
32633262
*
3264-
* Returns FD of opened file.
3263+
* path: on return, this char[MAXPGPATH] has the path to the logsegno file.
32653264
*
3266-
* Note: errors here are ERROR not PANIC because we might or might not be
3267-
* inside a critical section (eg, during checkpoint there is no reason to
3268-
* take down the system on failure). They will promote to PANIC if we are
3269-
* in a critical section.
3265+
* Returns -1 or FD of opened file. A -1 here is not an error; a caller
3266+
* wanting an open segment should attempt to open "path", which usually will
3267+
* succeed. (This is weird, but it's efficient for the callers.)
32703268
*/
3271-
int
3272-
XLogFileInit(XLogSegNo logsegno, bool *added)
3269+
static int
3270+
XLogFileInitInternal(XLogSegNo logsegno, bool *added, char *path)
32733271
{
3274-
char path[MAXPGPATH];
32753272
char tmppath[MAXPGPATH];
32763273
PGAlignedXLogBlock zbuffer;
32773274
XLogSegNo installed_segno;
@@ -3424,26 +3421,53 @@ XLogFileInit(XLogSegNo logsegno, bool *added)
34243421
*/
34253422
max_segno = logsegno + CheckPointSegments;
34263423
if (InstallXLogFileSegment(&installed_segno, tmppath, true, max_segno))
3424+
{
34273425
*added = true;
3426+
elog(DEBUG2, "done creating and filling new WAL file");
3427+
}
34283428
else
34293429
{
34303430
/*
34313431
* No need for any more future segments, or InstallXLogFileSegment()
3432-
* failed to rename the file into place. If the rename failed, opening
3433-
* the file below will fail.
3432+
* failed to rename the file into place. If the rename failed, a
3433+
* caller opening the file may fail.
34343434
*/
34353435
unlink(tmppath);
3436+
elog(DEBUG2, "abandoned new WAL file");
34363437
}
34373438

3439+
return -1;
3440+
}
3441+
3442+
/*
3443+
* Create a new XLOG file segment, or open a pre-existing one.
3444+
*
3445+
* logsegno: identify segment to be created/opened.
3446+
*
3447+
* Returns FD of opened file.
3448+
*
3449+
* Note: errors here are ERROR not PANIC because we might or might not be
3450+
* inside a critical section (eg, during checkpoint there is no reason to
3451+
* take down the system on failure). They will promote to PANIC if we are
3452+
* in a critical section.
3453+
*/
3454+
int
3455+
XLogFileInit(XLogSegNo logsegno)
3456+
{
3457+
bool ignore_added;
3458+
char path[MAXPGPATH];
3459+
int fd;
3460+
3461+
fd = XLogFileInitInternal(logsegno, &ignore_added, path);
3462+
if (fd >= 0)
3463+
return fd;
3464+
34383465
/* Now open original target segment (might not be file I just made) */
34393466
fd = BasicOpenFile(path, O_RDWR | PG_BINARY | get_sync_bit(sync_method));
34403467
if (fd < 0)
34413468
ereport(ERROR,
34423469
(errcode_for_file_access(),
34433470
errmsg("could not open file \"%s\": %m", path)));
3444-
3445-
elog(DEBUG2, "done creating and filling new WAL file");
3446-
34473471
return fd;
34483472
}
34493473

@@ -3903,22 +3927,33 @@ XLogFileClose(void)
39033927
* High-volume systems will be OK once they've built up a sufficient set of
39043928
* recycled log segments, but the startup transient is likely to include
39053929
* a lot of segment creations by foreground processes, which is not so good.
3930+
*
3931+
* XLogFileInitInternal() can ereport(ERROR). All known causes indicate big
3932+
* trouble; for example, a full filesystem is one cause. The checkpoint WAL
3933+
* and/or ControlFile updates already completed. If a RequestCheckpoint()
3934+
* initiated the present checkpoint and an ERROR ends this function, the
3935+
* command that called RequestCheckpoint() fails. That's not ideal, but it's
3936+
* not worth contorting more functions to use caller-specified elevel values.
3937+
* (With or without RequestCheckpoint(), an ERROR forestalls some inessential
3938+
* reporting and resource reclamation.)
39063939
*/
39073940
static void
39083941
PreallocXlogFiles(XLogRecPtr endptr)
39093942
{
39103943
XLogSegNo _logSegNo;
39113944
int lf;
39123945
bool added;
3946+
char path[MAXPGPATH];
39133947
uint64 offset;
39143948

39153949
XLByteToPrevSeg(endptr, _logSegNo, wal_segment_size);
39163950
offset = XLogSegmentOffset(endptr - 1, wal_segment_size);
39173951
if (offset >= (uint32) (0.75 * wal_segment_size))
39183952
{
39193953
_logSegNo++;
3920-
lf = XLogFileInit(_logSegNo, &added);
3921-
close(lf);
3954+
lf = XLogFileInitInternal(_logSegNo, &added, path);
3955+
if (lf >= 0)
3956+
close(lf);
39223957
if (added)
39233958
CheckpointStats.ckpt_segs_added++;
39243959
}
@@ -5214,7 +5249,6 @@ BootStrapXLOG(void)
52145249
XLogLongPageHeader longpage;
52155250
XLogRecord *record;
52165251
char *recptr;
5217-
bool added;
52185252
uint64 sysidentifier;
52195253
struct timeval tv;
52205254
pg_crc32c crc;
@@ -5311,7 +5345,7 @@ BootStrapXLOG(void)
53115345
record->xl_crc = crc;
53125346

53135347
/* Create first XLOG segment file */
5314-
openLogFile = XLogFileInit(1, &added);
5348+
openLogFile = XLogFileInit(1);
53155349

53165350
/*
53175351
* We needn't bother with Reserve/ReleaseExternalFD here, since we'll
@@ -5617,10 +5651,9 @@ exitArchiveRecovery(TimeLineID endTLI, XLogRecPtr endOfLog)
56175651
* The switch happened at a segment boundary, so just create the next
56185652
* segment on the new timeline.
56195653
*/
5620-
bool added;
56215654
int fd;
56225655

5623-
fd = XLogFileInit(startLogSegNo, &added);
5656+
fd = XLogFileInit(startLogSegNo);
56245657

56255658
if (close(fd) != 0)
56265659
{

src/backend/replication/walreceiver.c

Lines changed: 1 addition & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -885,8 +885,6 @@ XLogWalRcvWrite(char *buf, Size nbytes, XLogRecPtr recptr)
885885

886886
if (recvFile < 0 || !XLByteInSeg(recptr, recvSegNo, wal_segment_size))
887887
{
888-
bool added;
889-
890888
/*
891889
* fsync() and close current file before we switch to next one. We
892890
* would otherwise have to reopen this file to fsync it later
@@ -923,7 +921,7 @@ XLogWalRcvWrite(char *buf, Size nbytes, XLogRecPtr recptr)
923921

924922
/* Create/use new log file */
925923
XLByteToSeg(recptr, recvSegNo, wal_segment_size);
926-
recvFile = XLogFileInit(recvSegNo, &added);
924+
recvFile = XLogFileInit(recvSegNo);
927925
recvFileTLI = ThisTimeLineID;
928926
}
929927

src/include/access/xlog.h

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -296,7 +296,7 @@ extern XLogRecPtr XLogInsertRecord(struct XLogRecData *rdata,
296296
extern void XLogFlush(XLogRecPtr RecPtr);
297297
extern bool XLogBackgroundFlush(void);
298298
extern bool XLogNeedsFlush(XLogRecPtr RecPtr);
299-
extern int XLogFileInit(XLogSegNo segno, bool *added);
299+
extern int XLogFileInit(XLogSegNo segno);
300300
extern int XLogFileOpen(XLogSegNo segno);
301301

302302
extern void CheckXLogRemoved(XLogSegNo segno, TimeLineID tli);

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