mirror of
https://github.com/postgres/postgres.git
synced 2025-09-03 15:22:11 +03:00
Improve control logic for bgwriter hibernation mode.
Commit 6d90eaaa89
added a hibernation mode
to the bgwriter to reduce the server's idle-power consumption. However,
its interaction with the detailed behavior of BgBufferSync's feedback
control loop wasn't very well thought out. That control loop depends
primarily on the rate of buffer allocation, not the rate of buffer
dirtying, so the hibernation mode has to be designed to operate only when
no new buffer allocations are happening. Also, the check for whether the
system is effectively idle was not quite right and would fail to detect
a constant low level of activity, thus allowing the bgwriter to go into
hibernation mode in a way that would let the cycle time vary quite a bit,
possibly further confusing the feedback loop. To fix, move the wakeup
support from MarkBufferDirty and SetBufferCommitInfoNeedsSave into
StrategyGetBuffer, and prevent the bgwriter from entering hibernation mode
unless no buffer allocations have happened recently.
In addition, fix the delaying logic to remove the problem of possibly not
responding to signals promptly, which was basically caused by trying to use
the process latch's is_set flag for multiple purposes. I can't prove it
but I'm suspicious that that hack was responsible for the intermittent
"postmaster does not shut down" failures we've been seeing in the buildfarm
lately. In any case it did nothing to improve the readability or
robustness of the code.
In passing, express the hibernation sleep time as a multiplier on
BgWriterDelay, not a constant. I'm not sure whether there's any value in
exposing the longer sleep time as an independently configurable setting,
but we can at least make it act like this for little extra code.
This commit is contained in:
@@ -41,6 +41,11 @@ typedef struct
|
||||
*/
|
||||
uint32 completePasses; /* Complete cycles of the clock sweep */
|
||||
uint32 numBufferAllocs; /* Buffers allocated since last reset */
|
||||
|
||||
/*
|
||||
* Notification latch, or NULL if none. See StrategyNotifyBgWriter.
|
||||
*/
|
||||
Latch *bgwriterLatch;
|
||||
} BufferStrategyControl;
|
||||
|
||||
/* Pointers to shared state */
|
||||
@@ -107,6 +112,7 @@ volatile BufferDesc *
|
||||
StrategyGetBuffer(BufferAccessStrategy strategy, bool *lock_held)
|
||||
{
|
||||
volatile BufferDesc *buf;
|
||||
Latch *bgwriterLatch;
|
||||
int trycounter;
|
||||
|
||||
/*
|
||||
@@ -134,6 +140,21 @@ StrategyGetBuffer(BufferAccessStrategy strategy, bool *lock_held)
|
||||
*/
|
||||
StrategyControl->numBufferAllocs++;
|
||||
|
||||
/*
|
||||
* If bgwriterLatch is set, we need to waken the bgwriter, but we should
|
||||
* not do so while holding BufFreelistLock; so release and re-grab. This
|
||||
* is annoyingly tedious, but it happens at most once per bgwriter cycle,
|
||||
* so the performance hit is minimal.
|
||||
*/
|
||||
bgwriterLatch = StrategyControl->bgwriterLatch;
|
||||
if (bgwriterLatch)
|
||||
{
|
||||
StrategyControl->bgwriterLatch = NULL;
|
||||
LWLockRelease(BufFreelistLock);
|
||||
SetLatch(bgwriterLatch);
|
||||
LWLockAcquire(BufFreelistLock, LW_EXCLUSIVE);
|
||||
}
|
||||
|
||||
/*
|
||||
* Try to get a buffer from the freelist. Note that the freeNext fields
|
||||
* are considered to be protected by the BufFreelistLock not the
|
||||
@@ -269,6 +290,27 @@ StrategySyncStart(uint32 *complete_passes, uint32 *num_buf_alloc)
|
||||
return result;
|
||||
}
|
||||
|
||||
/*
|
||||
* StrategyNotifyBgWriter -- set or clear allocation notification latch
|
||||
*
|
||||
* If bgwriterLatch isn't NULL, the next invocation of StrategyGetBuffer will
|
||||
* set that latch. Pass NULL to clear the pending notification before it
|
||||
* happens. This feature is used by the bgwriter process to wake itself up
|
||||
* from hibernation, and is not meant for anybody else to use.
|
||||
*/
|
||||
void
|
||||
StrategyNotifyBgWriter(Latch *bgwriterLatch)
|
||||
{
|
||||
/*
|
||||
* We acquire the BufFreelistLock just to ensure that the store appears
|
||||
* atomic to StrategyGetBuffer. The bgwriter should call this rather
|
||||
* infrequently, so there's no performance penalty from being safe.
|
||||
*/
|
||||
LWLockAcquire(BufFreelistLock, LW_EXCLUSIVE);
|
||||
StrategyControl->bgwriterLatch = bgwriterLatch;
|
||||
LWLockRelease(BufFreelistLock);
|
||||
}
|
||||
|
||||
|
||||
/*
|
||||
* StrategyShmemSize
|
||||
@@ -344,6 +386,9 @@ StrategyInitialize(bool init)
|
||||
/* Clear statistics */
|
||||
StrategyControl->completePasses = 0;
|
||||
StrategyControl->numBufferAllocs = 0;
|
||||
|
||||
/* No pending notification */
|
||||
StrategyControl->bgwriterLatch = NULL;
|
||||
}
|
||||
else
|
||||
Assert(!init);
|
||||
|
Reference in New Issue
Block a user