Location via proxy:   [ UP ]  
[Report a bug]   [Manage cookies]                
Skip to content

Commit acd4c7d

Browse files
committed
Fix an issue in recent walwriter hibernation patch.
Users of asynchronous-commit mode expect there to be a guaranteed maximum delay before an async commit's WAL records get flushed to disk. The original version of the walwriter hibernation patch broke that. Add an extra shared-memory flag to allow async commits to kick the walwriter out of hibernation mode, without adding any noticeable overhead in cases where no action is needed.
1 parent 8b77e22 commit acd4c7d

File tree

3 files changed

+60
-7
lines changed

3 files changed

+60
-7
lines changed

src/backend/access/transam/xlog.c

Lines changed: 41 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -426,6 +426,13 @@ typedef struct XLogCtlData
426426
*/
427427
bool SharedHotStandbyActive;
428428

429+
/*
430+
* WalWriterSleeping indicates whether the WAL writer is currently in
431+
* low-power mode (and hence should be nudged if an async commit occurs).
432+
* Protected by info_lck.
433+
*/
434+
bool WalWriterSleeping;
435+
429436
/*
430437
* recoveryWakeupLatch is used to wake up the startup process to continue
431438
* WAL replay, if it is waiting for WAL to arrive or failover trigger file
@@ -1903,32 +1910,44 @@ XLogWrite(XLogwrtRqst WriteRqst, bool flexible, bool xlog_switch)
19031910

19041911
/*
19051912
* Record the LSN for an asynchronous transaction commit/abort
1906-
* and nudge the WALWriter if there is a complete page to write.
1913+
* and nudge the WALWriter if there is work for it to do.
19071914
* (This should not be called for synchronous commits.)
19081915
*/
19091916
void
19101917
XLogSetAsyncXactLSN(XLogRecPtr asyncXactLSN)
19111918
{
19121919
XLogRecPtr WriteRqstPtr = asyncXactLSN;
1920+
bool sleeping;
19131921

19141922
/* use volatile pointer to prevent code rearrangement */
19151923
volatile XLogCtlData *xlogctl = XLogCtl;
19161924

19171925
SpinLockAcquire(&xlogctl->info_lck);
19181926
LogwrtResult = xlogctl->LogwrtResult;
1927+
sleeping = xlogctl->WalWriterSleeping;
19191928
if (XLByteLT(xlogctl->asyncXactLSN, asyncXactLSN))
19201929
xlogctl->asyncXactLSN = asyncXactLSN;
19211930
SpinLockRelease(&xlogctl->info_lck);
19221931

1923-
/* back off to last completed page boundary */
1924-
WriteRqstPtr.xrecoff -= WriteRqstPtr.xrecoff % XLOG_BLCKSZ;
1932+
/*
1933+
* If the WALWriter is sleeping, we should kick it to make it come out of
1934+
* low-power mode. Otherwise, determine whether there's a full page of
1935+
* WAL available to write.
1936+
*/
1937+
if (!sleeping)
1938+
{
1939+
/* back off to last completed page boundary */
1940+
WriteRqstPtr.xrecoff -= WriteRqstPtr.xrecoff % XLOG_BLCKSZ;
19251941

1926-
/* if we have already flushed that far, we're done */
1927-
if (XLByteLE(WriteRqstPtr, LogwrtResult.Flush))
1928-
return;
1942+
/* if we have already flushed that far, we're done */
1943+
if (XLByteLE(WriteRqstPtr, LogwrtResult.Flush))
1944+
return;
1945+
}
19291946

19301947
/*
1931-
* Nudge the WALWriter if we have a full page of WAL to write.
1948+
* Nudge the WALWriter: it has a full page of WAL to write, or we want
1949+
* it to come out of low-power mode so that this async commit will reach
1950+
* disk within the expected amount of time.
19321951
*/
19331952
if (ProcGlobal->walwriterLatch)
19341953
SetLatch(ProcGlobal->walwriterLatch);
@@ -5100,6 +5119,7 @@ XLOGShmemInit(void)
51005119
XLogCtl->XLogCacheBlck = XLOGbuffers - 1;
51015120
XLogCtl->SharedRecoveryInProgress = true;
51025121
XLogCtl->SharedHotStandbyActive = false;
5122+
XLogCtl->WalWriterSleeping = false;
51035123
XLogCtl->Insert.currpage = (XLogPageHeader) (XLogCtl->pages);
51045124
SpinLockInit(&XLogCtl->info_lck);
51055125
InitSharedLatch(&XLogCtl->recoveryWakeupLatch);
@@ -10479,3 +10499,17 @@ WakeupRecovery(void)
1047910499
{
1048010500
SetLatch(&XLogCtl->recoveryWakeupLatch);
1048110501
}
10502+
10503+
/*
10504+
* Update the WalWriterSleeping flag.
10505+
*/
10506+
void
10507+
SetWalWriterSleeping(bool sleeping)
10508+
{
10509+
/* use volatile pointer to prevent code rearrangement */
10510+
volatile XLogCtlData *xlogctl = XLogCtl;
10511+
10512+
SpinLockAcquire(&xlogctl->info_lck);
10513+
xlogctl->WalWriterSleeping = sleeping;
10514+
SpinLockRelease(&xlogctl->info_lck);
10515+
}

src/backend/postmaster/walwriter.c

Lines changed: 18 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -99,6 +99,7 @@ WalWriterMain(void)
9999
sigjmp_buf local_sigjmp_buf;
100100
MemoryContext walwriter_context;
101101
int left_till_hibernate;
102+
bool hibernating;
102103

103104
/*
104105
* If possible, make this process a group leader, so that the postmaster
@@ -230,6 +231,8 @@ WalWriterMain(void)
230231
* Reset hibernation state after any error.
231232
*/
232233
left_till_hibernate = LOOPS_UNTIL_HIBERNATE;
234+
hibernating = false;
235+
SetWalWriterSleeping(false);
233236

234237
/*
235238
* Advertise our latch that backends can use to wake us up while we're
@@ -244,6 +247,21 @@ WalWriterMain(void)
244247
{
245248
long cur_timeout;
246249

250+
/*
251+
* Advertise whether we might hibernate in this cycle. We do this
252+
* before resetting the latch to ensure that any async commits will
253+
* see the flag set if they might possibly need to wake us up, and
254+
* that we won't miss any signal they send us. (If we discover work
255+
* to do in the last cycle before we would hibernate, the global flag
256+
* will be set unnecessarily, but little harm is done.) But avoid
257+
* touching the global flag if it doesn't need to change.
258+
*/
259+
if (hibernating != (left_till_hibernate <= 1))
260+
{
261+
hibernating = (left_till_hibernate <= 1);
262+
SetWalWriterSleeping(hibernating);
263+
}
264+
247265
/* Clear any already-pending wakeups */
248266
ResetLatch(&MyProc->procLatch);
249267

src/include/access/xlog.h

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -316,6 +316,7 @@ extern TimeLineID GetRecoveryTargetTLI(void);
316316

317317
extern bool CheckPromoteSignal(void);
318318
extern void WakeupRecovery(void);
319+
extern void SetWalWriterSleeping(bool sleeping);
319320

320321
/*
321322
* Starting/stopping a base backup

0 commit comments

Comments
 (0)