mirror of
https://github.com/postgres/postgres.git
synced 2025-08-25 20:23:07 +03:00
Remove all use of ThisTimeLineID global variable outside of xlog.c
All such code deals with this global variable in one of three ways. Sometimes the same functions use it in more than one of these ways at the same time. First, sometimes it's an implicit argument to one or more functions being called in xlog.c or elsewhere, and must be set to the appropriate value before calling those functions lest they misbehave. In those cases, it is now passed as an explicit argument instead. Second, sometimes it's used to obtain the current timeline after the end of recovery, i.e. the timeline to which WAL is being written and flushed. Such code now calls GetWALInsertionTimeLine() or relies on the new out parameter added to GetFlushRecPtr(). Third, sometimes it's used during recovery to store the current replay timeline. That can change, so such code must generally update the value before each use. It can still do that, but must now use a local variable instead. The net effect of these changes is to reduce by a fair amount the amount of code that is directly accessing this global variable. That's good, because history has shown that we don't always think clearly about which timeline ID it's supposed to contain at any given point in time, or indeed, whether it has been or needs to be initialized at any given point in the code. Patch by me, reviewed and tested by Michael Paquier, Amul Sul, and Álvaro Herrera. Discussion: https://postgr.es/m/CA+TgmobfAAqhfWa1kaFBBFvX+5CjM=7TE=n4r4Q1o2bjbGYBpA@mail.gmail.com
This commit is contained in:
@@ -211,7 +211,7 @@ pg_logical_slot_get_changes_guts(FunctionCallInfo fcinfo, bool confirm, bool bin
|
||||
* Compute the current end-of-wal.
|
||||
*/
|
||||
if (!RecoveryInProgress())
|
||||
end_of_wal = GetFlushRecPtr();
|
||||
end_of_wal = GetFlushRecPtr(NULL);
|
||||
else
|
||||
end_of_wal = GetXLogReplayRecPtr(NULL);
|
||||
|
||||
|
@@ -2435,7 +2435,7 @@ get_flush_position(XLogRecPtr *write, XLogRecPtr *flush,
|
||||
bool *have_pending_txes)
|
||||
{
|
||||
dlist_mutable_iter iter;
|
||||
XLogRecPtr local_flush = GetFlushRecPtr();
|
||||
XLogRecPtr local_flush = GetFlushRecPtr(NULL);
|
||||
|
||||
*write = InvalidXLogRecPtr;
|
||||
*flush = InvalidXLogRecPtr;
|
||||
|
@@ -625,7 +625,7 @@ pg_replication_slot_advance(PG_FUNCTION_ARGS)
|
||||
* target position accordingly.
|
||||
*/
|
||||
if (!RecoveryInProgress())
|
||||
moveto = Min(moveto, GetFlushRecPtr());
|
||||
moveto = Min(moveto, GetFlushRecPtr(NULL));
|
||||
else
|
||||
moveto = Min(moveto, GetXLogReplayRecPtr(NULL));
|
||||
|
||||
|
@@ -122,10 +122,12 @@ static StringInfoData incoming_message;
|
||||
static void WalRcvFetchTimeLineHistoryFiles(TimeLineID first, TimeLineID last);
|
||||
static void WalRcvWaitForStartPosition(XLogRecPtr *startpoint, TimeLineID *startpointTLI);
|
||||
static void WalRcvDie(int code, Datum arg);
|
||||
static void XLogWalRcvProcessMsg(unsigned char type, char *buf, Size len);
|
||||
static void XLogWalRcvWrite(char *buf, Size nbytes, XLogRecPtr recptr);
|
||||
static void XLogWalRcvFlush(bool dying);
|
||||
static void XLogWalRcvClose(XLogRecPtr recptr);
|
||||
static void XLogWalRcvProcessMsg(unsigned char type, char *buf, Size len,
|
||||
TimeLineID tli);
|
||||
static void XLogWalRcvWrite(char *buf, Size nbytes, XLogRecPtr recptr,
|
||||
TimeLineID tli);
|
||||
static void XLogWalRcvFlush(bool dying, TimeLineID tli);
|
||||
static void XLogWalRcvClose(XLogRecPtr recptr, TimeLineID tli);
|
||||
static void XLogWalRcvSendReply(bool force, bool requestReply);
|
||||
static void XLogWalRcvSendHSFeedback(bool immed);
|
||||
static void ProcessWalSndrMessage(XLogRecPtr walEnd, TimestampTz sendTime);
|
||||
@@ -255,7 +257,7 @@ WalReceiverMain(void)
|
||||
pg_atomic_write_u64(&WalRcv->writtenUpto, 0);
|
||||
|
||||
/* Arrange to clean up at walreceiver exit */
|
||||
on_shmem_exit(WalRcvDie, 0);
|
||||
on_shmem_exit(WalRcvDie, PointerGetDatum(&startpointTLI));
|
||||
|
||||
/* Properly accept or ignore signals the postmaster might send us */
|
||||
pqsignal(SIGHUP, SignalHandlerForConfigReload); /* set flag to read config
|
||||
@@ -394,7 +396,6 @@ WalReceiverMain(void)
|
||||
options.startpoint = startpoint;
|
||||
options.slotname = slotname[0] != '\0' ? slotname : NULL;
|
||||
options.proto.physical.startpointTLI = startpointTLI;
|
||||
ThisTimeLineID = startpointTLI;
|
||||
if (walrcv_startstreaming(wrconn, &options))
|
||||
{
|
||||
if (first_stream)
|
||||
@@ -462,7 +463,8 @@ WalReceiverMain(void)
|
||||
*/
|
||||
last_recv_timestamp = GetCurrentTimestamp();
|
||||
ping_sent = false;
|
||||
XLogWalRcvProcessMsg(buf[0], &buf[1], len - 1);
|
||||
XLogWalRcvProcessMsg(buf[0], &buf[1], len - 1,
|
||||
startpointTLI);
|
||||
}
|
||||
else if (len == 0)
|
||||
break;
|
||||
@@ -487,7 +489,7 @@ WalReceiverMain(void)
|
||||
* let the startup process and primary server know about
|
||||
* them.
|
||||
*/
|
||||
XLogWalRcvFlush(false);
|
||||
XLogWalRcvFlush(false, startpointTLI);
|
||||
}
|
||||
|
||||
/* Check if we need to exit the streaming loop. */
|
||||
@@ -608,7 +610,7 @@ WalReceiverMain(void)
|
||||
{
|
||||
char xlogfname[MAXFNAMELEN];
|
||||
|
||||
XLogWalRcvFlush(false);
|
||||
XLogWalRcvFlush(false, startpointTLI);
|
||||
XLogFileName(xlogfname, recvFileTLI, recvSegNo, wal_segment_size);
|
||||
if (close(recvFile) != 0)
|
||||
ereport(PANIC,
|
||||
@@ -776,9 +778,12 @@ static void
|
||||
WalRcvDie(int code, Datum arg)
|
||||
{
|
||||
WalRcvData *walrcv = WalRcv;
|
||||
TimeLineID *startpointTLI_p = (TimeLineID *) DatumGetPointer(arg);
|
||||
|
||||
Assert(*startpointTLI_p != 0);
|
||||
|
||||
/* Ensure that all WAL records received are flushed to disk */
|
||||
XLogWalRcvFlush(true);
|
||||
XLogWalRcvFlush(true, *startpointTLI_p);
|
||||
|
||||
/* Mark ourselves inactive in shared memory */
|
||||
SpinLockAcquire(&walrcv->mutex);
|
||||
@@ -808,7 +813,7 @@ WalRcvDie(int code, Datum arg)
|
||||
* Accept the message from XLOG stream, and process it.
|
||||
*/
|
||||
static void
|
||||
XLogWalRcvProcessMsg(unsigned char type, char *buf, Size len)
|
||||
XLogWalRcvProcessMsg(unsigned char type, char *buf, Size len, TimeLineID tli)
|
||||
{
|
||||
int hdrlen;
|
||||
XLogRecPtr dataStart;
|
||||
@@ -838,7 +843,7 @@ XLogWalRcvProcessMsg(unsigned char type, char *buf, Size len)
|
||||
|
||||
buf += hdrlen;
|
||||
len -= hdrlen;
|
||||
XLogWalRcvWrite(buf, len, dataStart);
|
||||
XLogWalRcvWrite(buf, len, dataStart, tli);
|
||||
break;
|
||||
}
|
||||
case 'k': /* Keepalive */
|
||||
@@ -875,25 +880,27 @@ XLogWalRcvProcessMsg(unsigned char type, char *buf, Size len)
|
||||
* Write XLOG data to disk.
|
||||
*/
|
||||
static void
|
||||
XLogWalRcvWrite(char *buf, Size nbytes, XLogRecPtr recptr)
|
||||
XLogWalRcvWrite(char *buf, Size nbytes, XLogRecPtr recptr, TimeLineID tli)
|
||||
{
|
||||
int startoff;
|
||||
int byteswritten;
|
||||
|
||||
Assert(tli != 0);
|
||||
|
||||
while (nbytes > 0)
|
||||
{
|
||||
int segbytes;
|
||||
|
||||
/* Close the current segment if it's completed */
|
||||
if (recvFile >= 0 && !XLByteInSeg(recptr, recvSegNo, wal_segment_size))
|
||||
XLogWalRcvClose(recptr);
|
||||
XLogWalRcvClose(recptr, tli);
|
||||
|
||||
if (recvFile < 0)
|
||||
{
|
||||
/* Create/use new log file */
|
||||
XLByteToSeg(recptr, recvSegNo, wal_segment_size);
|
||||
recvFile = XLogFileInit(recvSegNo);
|
||||
recvFileTLI = ThisTimeLineID;
|
||||
recvFile = XLogFileInit(recvSegNo, tli);
|
||||
recvFileTLI = tli;
|
||||
}
|
||||
|
||||
/* Calculate the start offset of the received logs */
|
||||
@@ -946,7 +953,7 @@ XLogWalRcvWrite(char *buf, Size nbytes, XLogRecPtr recptr)
|
||||
* segment is received and written.
|
||||
*/
|
||||
if (recvFile >= 0 && !XLByteInSeg(recptr, recvSegNo, wal_segment_size))
|
||||
XLogWalRcvClose(recptr);
|
||||
XLogWalRcvClose(recptr, tli);
|
||||
}
|
||||
|
||||
/*
|
||||
@@ -956,13 +963,15 @@ XLogWalRcvWrite(char *buf, Size nbytes, XLogRecPtr recptr)
|
||||
* an error, so we skip sending a reply in that case.
|
||||
*/
|
||||
static void
|
||||
XLogWalRcvFlush(bool dying)
|
||||
XLogWalRcvFlush(bool dying, TimeLineID tli)
|
||||
{
|
||||
Assert(tli != 0);
|
||||
|
||||
if (LogstreamResult.Flush < LogstreamResult.Write)
|
||||
{
|
||||
WalRcvData *walrcv = WalRcv;
|
||||
|
||||
issue_xlog_fsync(recvFile, recvSegNo);
|
||||
issue_xlog_fsync(recvFile, recvSegNo, tli);
|
||||
|
||||
LogstreamResult.Flush = LogstreamResult.Write;
|
||||
|
||||
@@ -972,7 +981,7 @@ XLogWalRcvFlush(bool dying)
|
||||
{
|
||||
walrcv->latestChunkStart = walrcv->flushedUpto;
|
||||
walrcv->flushedUpto = LogstreamResult.Flush;
|
||||
walrcv->receivedTLI = ThisTimeLineID;
|
||||
walrcv->receivedTLI = tli;
|
||||
}
|
||||
SpinLockRelease(&walrcv->mutex);
|
||||
|
||||
@@ -1009,17 +1018,18 @@ XLogWalRcvFlush(bool dying)
|
||||
* Create an archive notification file since the segment is known completed.
|
||||
*/
|
||||
static void
|
||||
XLogWalRcvClose(XLogRecPtr recptr)
|
||||
XLogWalRcvClose(XLogRecPtr recptr, TimeLineID tli)
|
||||
{
|
||||
char xlogfname[MAXFNAMELEN];
|
||||
|
||||
Assert(recvFile >= 0 && !XLByteInSeg(recptr, recvSegNo, wal_segment_size));
|
||||
Assert(tli != 0);
|
||||
|
||||
/*
|
||||
* fsync() and close current file before we switch to next one. We would
|
||||
* otherwise have to reopen this file to fsync it later
|
||||
*/
|
||||
XLogWalRcvFlush(false);
|
||||
XLogWalRcvFlush(false, tli);
|
||||
|
||||
XLogFileName(xlogfname, recvFileTLI, recvSegNo, wal_segment_size);
|
||||
|
||||
|
@@ -230,7 +230,7 @@ static void WalSndShutdown(void) pg_attribute_noreturn();
|
||||
static void XLogSendPhysical(void);
|
||||
static void XLogSendLogical(void);
|
||||
static void WalSndDone(WalSndSendDataCallback send_data);
|
||||
static XLogRecPtr GetStandbyFlushRecPtr(void);
|
||||
static XLogRecPtr GetStandbyFlushRecPtr(TimeLineID *tli);
|
||||
static void IdentifySystem(void);
|
||||
static void ReadReplicationSlot(ReadReplicationSlotCmd *cmd);
|
||||
static void CreateReplicationSlot(CreateReplicationSlotCmd *cmd);
|
||||
@@ -385,6 +385,7 @@ IdentifySystem(void)
|
||||
TupleDesc tupdesc;
|
||||
Datum values[4];
|
||||
bool nulls[4];
|
||||
TimeLineID currTLI;
|
||||
|
||||
/*
|
||||
* Reply with a result set with one row, four columns. First col is system
|
||||
@@ -397,12 +398,9 @@ IdentifySystem(void)
|
||||
|
||||
am_cascading_walsender = RecoveryInProgress();
|
||||
if (am_cascading_walsender)
|
||||
{
|
||||
/* this also updates ThisTimeLineID */
|
||||
logptr = GetStandbyFlushRecPtr();
|
||||
}
|
||||
logptr = GetStandbyFlushRecPtr(&currTLI);
|
||||
else
|
||||
logptr = GetFlushRecPtr();
|
||||
logptr = GetFlushRecPtr(&currTLI);
|
||||
|
||||
snprintf(xloc, sizeof(xloc), "%X/%X", LSN_FORMAT_ARGS(logptr));
|
||||
|
||||
@@ -441,7 +439,7 @@ IdentifySystem(void)
|
||||
values[0] = CStringGetTextDatum(sysid);
|
||||
|
||||
/* column 2: timeline */
|
||||
values[1] = Int32GetDatum(ThisTimeLineID);
|
||||
values[1] = Int32GetDatum(currTLI);
|
||||
|
||||
/* column 3: wal location */
|
||||
values[2] = CStringGetTextDatum(xloc);
|
||||
@@ -537,7 +535,7 @@ ReadReplicationSlot(ReadReplicationSlotCmd *cmd)
|
||||
if (RecoveryInProgress())
|
||||
(void) GetXLogReplayRecPtr(¤t_timeline);
|
||||
else
|
||||
current_timeline = ThisTimeLineID;
|
||||
current_timeline = GetWALInsertionTimeLine();
|
||||
|
||||
timeline_history = readTimeLineHistory(current_timeline);
|
||||
slots_position_timeline = tliOfPointInHistory(slot_contents.data.restart_lsn,
|
||||
@@ -671,6 +669,7 @@ StartReplication(StartReplicationCmd *cmd)
|
||||
{
|
||||
StringInfoData buf;
|
||||
XLogRecPtr FlushPtr;
|
||||
TimeLineID FlushTLI;
|
||||
|
||||
/* create xlogreader for physical replication */
|
||||
xlogreader =
|
||||
@@ -710,24 +709,20 @@ StartReplication(StartReplicationCmd *cmd)
|
||||
|
||||
/*
|
||||
* Select the timeline. If it was given explicitly by the client, use
|
||||
* that. Otherwise use the timeline of the last replayed record, which is
|
||||
* kept in ThisTimeLineID.
|
||||
* that. Otherwise use the timeline of the last replayed record.
|
||||
*/
|
||||
am_cascading_walsender = RecoveryInProgress();
|
||||
if (am_cascading_walsender)
|
||||
{
|
||||
/* this also updates ThisTimeLineID */
|
||||
FlushPtr = GetStandbyFlushRecPtr();
|
||||
}
|
||||
FlushPtr = GetStandbyFlushRecPtr(&FlushTLI);
|
||||
else
|
||||
FlushPtr = GetFlushRecPtr();
|
||||
FlushPtr = GetFlushRecPtr(&FlushTLI);
|
||||
|
||||
if (cmd->timeline != 0)
|
||||
{
|
||||
XLogRecPtr switchpoint;
|
||||
|
||||
sendTimeLine = cmd->timeline;
|
||||
if (sendTimeLine == ThisTimeLineID)
|
||||
if (sendTimeLine == FlushTLI)
|
||||
{
|
||||
sendTimeLineIsHistoric = false;
|
||||
sendTimeLineValidUpto = InvalidXLogRecPtr;
|
||||
@@ -742,7 +737,7 @@ StartReplication(StartReplicationCmd *cmd)
|
||||
* Check that the timeline the client requested exists, and the
|
||||
* requested start location is on that timeline.
|
||||
*/
|
||||
timeLineHistory = readTimeLineHistory(ThisTimeLineID);
|
||||
timeLineHistory = readTimeLineHistory(FlushTLI);
|
||||
switchpoint = tliSwitchPoint(cmd->timeline, timeLineHistory,
|
||||
&sendTimeLineNextTLI);
|
||||
list_free_deep(timeLineHistory);
|
||||
@@ -781,7 +776,7 @@ StartReplication(StartReplicationCmd *cmd)
|
||||
}
|
||||
else
|
||||
{
|
||||
sendTimeLine = ThisTimeLineID;
|
||||
sendTimeLine = FlushTLI;
|
||||
sendTimeLineValidUpto = InvalidXLogRecPtr;
|
||||
sendTimeLineIsHistoric = false;
|
||||
}
|
||||
@@ -909,9 +904,16 @@ logical_read_xlog_page(XLogReaderState *state, XLogRecPtr targetPagePtr, int req
|
||||
int count;
|
||||
WALReadError errinfo;
|
||||
XLogSegNo segno;
|
||||
TimeLineID currTLI = GetWALInsertionTimeLine();
|
||||
|
||||
XLogReadDetermineTimeline(state, targetPagePtr, reqLen);
|
||||
sendTimeLineIsHistoric = (state->currTLI != ThisTimeLineID);
|
||||
/*
|
||||
* Since logical decoding is only permitted on a primary server, we know
|
||||
* that the current timeline ID can't be changing any more. If we did this
|
||||
* on a standby, we'd have to worry about the values we compute here
|
||||
* becoming invalid due to a promotion or timeline change.
|
||||
*/
|
||||
XLogReadDetermineTimeline(state, targetPagePtr, reqLen, currTLI);
|
||||
sendTimeLineIsHistoric = (state->currTLI != currTLI);
|
||||
sendTimeLine = state->currTLI;
|
||||
sendTimeLineValidUpto = state->currTLIValidUntil;
|
||||
sendTimeLineNextTLI = state->nextTLI;
|
||||
@@ -1487,7 +1489,7 @@ WalSndWaitForWal(XLogRecPtr loc)
|
||||
|
||||
/* Get a more recent flush pointer. */
|
||||
if (!RecoveryInProgress())
|
||||
RecentFlushPtr = GetFlushRecPtr();
|
||||
RecentFlushPtr = GetFlushRecPtr(NULL);
|
||||
else
|
||||
RecentFlushPtr = GetXLogReplayRecPtr(NULL);
|
||||
|
||||
@@ -1521,7 +1523,7 @@ WalSndWaitForWal(XLogRecPtr loc)
|
||||
|
||||
/* Update our idea of the currently flushed position. */
|
||||
if (!RecoveryInProgress())
|
||||
RecentFlushPtr = GetFlushRecPtr();
|
||||
RecentFlushPtr = GetFlushRecPtr(NULL);
|
||||
else
|
||||
RecentFlushPtr = GetXLogReplayRecPtr(NULL);
|
||||
|
||||
@@ -2683,6 +2685,8 @@ XLogSendPhysical(void)
|
||||
}
|
||||
else if (am_cascading_walsender)
|
||||
{
|
||||
TimeLineID SendRqstTLI;
|
||||
|
||||
/*
|
||||
* Streaming the latest timeline on a standby.
|
||||
*
|
||||
@@ -2702,14 +2706,12 @@ XLogSendPhysical(void)
|
||||
*/
|
||||
bool becameHistoric = false;
|
||||
|
||||
SendRqstPtr = GetStandbyFlushRecPtr();
|
||||
SendRqstPtr = GetStandbyFlushRecPtr(&SendRqstTLI);
|
||||
|
||||
if (!RecoveryInProgress())
|
||||
{
|
||||
/*
|
||||
* We have been promoted. RecoveryInProgress() updated
|
||||
* ThisTimeLineID to the new current timeline.
|
||||
*/
|
||||
/* We have been promoted. */
|
||||
SendRqstTLI = GetWALInsertionTimeLine();
|
||||
am_cascading_walsender = false;
|
||||
becameHistoric = true;
|
||||
}
|
||||
@@ -2717,10 +2719,9 @@ XLogSendPhysical(void)
|
||||
{
|
||||
/*
|
||||
* Still a cascading standby. But is the timeline we're sending
|
||||
* still the one recovery is recovering from? ThisTimeLineID was
|
||||
* updated by the GetStandbyFlushRecPtr() call above.
|
||||
* still the one recovery is recovering from?
|
||||
*/
|
||||
if (sendTimeLine != ThisTimeLineID)
|
||||
if (sendTimeLine != SendRqstTLI)
|
||||
becameHistoric = true;
|
||||
}
|
||||
|
||||
@@ -2733,7 +2734,7 @@ XLogSendPhysical(void)
|
||||
*/
|
||||
List *history;
|
||||
|
||||
history = readTimeLineHistory(ThisTimeLineID);
|
||||
history = readTimeLineHistory(SendRqstTLI);
|
||||
sendTimeLineValidUpto = tliSwitchPoint(sendTimeLine, history, &sendTimeLineNextTLI);
|
||||
|
||||
Assert(sendTimeLine < sendTimeLineNextTLI);
|
||||
@@ -2756,7 +2757,7 @@ XLogSendPhysical(void)
|
||||
* primary: if the primary subsequently crashes and restarts, standbys
|
||||
* must not have applied any WAL that got lost on the primary.
|
||||
*/
|
||||
SendRqstPtr = GetFlushRecPtr();
|
||||
SendRqstPtr = GetFlushRecPtr(NULL);
|
||||
}
|
||||
|
||||
/*
|
||||
@@ -2997,9 +2998,9 @@ XLogSendLogical(void)
|
||||
* we only need to update flushPtr if EndRecPtr is past it.
|
||||
*/
|
||||
if (flushPtr == InvalidXLogRecPtr)
|
||||
flushPtr = GetFlushRecPtr();
|
||||
flushPtr = GetFlushRecPtr(NULL);
|
||||
else if (logical_decoding_ctx->reader->EndRecPtr >= flushPtr)
|
||||
flushPtr = GetFlushRecPtr();
|
||||
flushPtr = GetFlushRecPtr(NULL);
|
||||
|
||||
/* If EndRecPtr is still past our flushPtr, it means we caught up. */
|
||||
if (logical_decoding_ctx->reader->EndRecPtr >= flushPtr)
|
||||
@@ -3069,11 +3070,11 @@ WalSndDone(WalSndSendDataCallback send_data)
|
||||
* can be sent to the standby. This should only be called when in recovery,
|
||||
* ie. we're streaming to a cascaded standby.
|
||||
*
|
||||
* As a side-effect, ThisTimeLineID is updated to the TLI of the last
|
||||
* As a side-effect, *tli is updated to the TLI of the last
|
||||
* replayed WAL record.
|
||||
*/
|
||||
static XLogRecPtr
|
||||
GetStandbyFlushRecPtr(void)
|
||||
GetStandbyFlushRecPtr(TimeLineID *tli)
|
||||
{
|
||||
XLogRecPtr replayPtr;
|
||||
TimeLineID replayTLI;
|
||||
@@ -3090,10 +3091,10 @@ GetStandbyFlushRecPtr(void)
|
||||
receivePtr = GetWalRcvFlushRecPtr(NULL, &receiveTLI);
|
||||
replayPtr = GetXLogReplayRecPtr(&replayTLI);
|
||||
|
||||
ThisTimeLineID = replayTLI;
|
||||
*tli = replayTLI;
|
||||
|
||||
result = replayPtr;
|
||||
if (receiveTLI == ThisTimeLineID && receivePtr > replayPtr)
|
||||
if (receiveTLI == replayTLI && receivePtr > replayPtr)
|
||||
result = receivePtr;
|
||||
|
||||
return result;
|
||||
|
Reference in New Issue
Block a user