From da223287c12d0077951a00f2be7eff9cdc6ae880 Mon Sep 17 00:00:00 2001 From: Bharath Rupireddy Date: Tue, 31 Jan 2023 08:23:51 +0000 Subject: [PATCH v1] Reduce power consumption by WAL writer --- src/backend/access/transam/xlog.c | 55 +++++++++++++++++++++++++ src/backend/access/transam/xloginsert.c | 6 +++ src/backend/postmaster/walwriter.c | 20 +++++---- src/include/access/xlog.h | 1 + 4 files changed, 75 insertions(+), 7 deletions(-) diff --git a/src/backend/access/transam/xlog.c b/src/backend/access/transam/xlog.c index fb4c860bde..918f3959d3 100644 --- a/src/backend/access/transam/xlog.c +++ b/src/backend/access/transam/xlog.c @@ -2393,6 +2393,61 @@ XLogSetAsyncXactLSN(XLogRecPtr asyncXactLSN) SetLatch(ProcGlobal->walwriterLatch); } +/* + * Wake up WAL writer process to write and flush newly generated WAL. + * + * This function better be in walwriter.c, but it reads LogwrtResult, a static + * variable from xlog.c. Hence we choose to keep it here for the sake of + * simplicity. + */ +void +WakeupWALWriter(void) +{ + XLogRecPtr WriteRqstPtr = XactLastRecEnd; + + /* back off to last completed page boundary */ + WriteRqstPtr -= WriteRqstPtr % XLOG_BLCKSZ; + + /* + * Let's not nudge WAL writer if somebody (this backend itself in + * XLogInsertRecord() or other backend or WAL writer itself in the ongoing + * run) already flushed that far. This avoids unnecessary WAL writer + * wakeups. + * + * It's possible that LogwrtResult is older, in which case, we nudge the + * WAL writer and it may do nothing. This is okay than to make this + * function costly by acquiring info_lck and read LogwrtResult freshly. + */ + if (WriteRqstPtr <= LogwrtResult.Flush) + return; + + /* + * XXXX: While more number of nudges/SetLatch() calls reduce the amount of + * WAL that this backend needs to write/flsuh, it might burden the WAL + * writer too much. + * + * To reduce the number of nudges, we can do all or some of the following + * things: + * + * 1) Nudge only when WAL writer is sleeping (use WalWriterSleeping). + * + * 2) Nudge only after wal_writer_delay has elapsed since the last nudge. + * + * 3) Nudge only after this backend has generated a configurable amount of + * WAL. Introduce a new GUC for this purpose wal_writer_wakeup_after + * (Amount of WAL written out by a backend that wakes up WAL writer to + * help write and flush WAL). Or use existing GUC + * wal_writer_flush_after. + */ + + /* + * Nudge WAL writer. Even if WAL writer is woken up, it does its work only + * when necessary at its own pace, see XLogBackgroundFlush() for details. + */ + if (ProcGlobal->walwriterLatch) + SetLatch(ProcGlobal->walwriterLatch); +} + /* * Record the LSN up to which we can remove WAL because it's not required by * any replication slot. diff --git a/src/backend/access/transam/xloginsert.c b/src/backend/access/transam/xloginsert.c index 008612e032..3d7dfec3ba 100644 --- a/src/backend/access/transam/xloginsert.c +++ b/src/backend/access/transam/xloginsert.c @@ -503,6 +503,12 @@ XLogInsert(RmgrId rmid, uint8 info) XLogResetInsertion(); + /* + * XXX: Effects of calling WakeupWALWriter() in XLogInsert() needs to be + * measured, say with high-write workload. + */ + WakeupWALWriter(); + return EndPos; } diff --git a/src/backend/postmaster/walwriter.c b/src/backend/postmaster/walwriter.c index 3113e8fbdd..9e30679cdc 100644 --- a/src/backend/postmaster/walwriter.c +++ b/src/backend/postmaster/walwriter.c @@ -71,12 +71,10 @@ int WalWriterDelay = 200; int WalWriterFlushAfter = 128; /* - * Number of do-nothing loops before lengthening the delay time, and the - * multiplier to apply to WalWriterDelay when we do decide to hibernate. + * Number of do-nothing loops before lengthening the delay time. * (Perhaps these need to be configurable?) */ #define LOOPS_UNTIL_HIBERNATE 50 -#define HIBERNATE_FACTOR 25 /* Prototypes for private functions */ static void HandleWalWriterInterrupts(void); @@ -226,6 +224,7 @@ WalWriterMain(void) for (;;) { long cur_timeout; + int wakeEvents; /* * Advertise whether we might hibernate in this cycle. We do this @@ -262,16 +261,23 @@ WalWriterMain(void) /* * Sleep until we are signaled or WalWriterDelay has elapsed. If we - * haven't done anything useful for quite some time, lengthen the - * sleep time so as to reduce the server's idle power consumption. + * haven't done anything useful for quite some time, sleep until an + * event occurs so as to reduce the server's idle power consumption. */ if (left_till_hibernate > 0) + { cur_timeout = WalWriterDelay; /* in ms */ + wakeEvents = WL_LATCH_SET | WL_TIMEOUT | WL_EXIT_ON_PM_DEATH; + } else - cur_timeout = WalWriterDelay * HIBERNATE_FACTOR; + { + Assert(hibernating == true); + cur_timeout = -1L; + wakeEvents = WL_LATCH_SET | WL_EXIT_ON_PM_DEATH; + } (void) WaitLatch(MyLatch, - WL_LATCH_SET | WL_TIMEOUT | WL_EXIT_ON_PM_DEATH, + wakeEvents, cur_timeout, WAIT_EVENT_WAL_WRITER_MAIN); } diff --git a/src/include/access/xlog.h b/src/include/access/xlog.h index cfe5409738..f30decfb7a 100644 --- a/src/include/access/xlog.h +++ b/src/include/access/xlog.h @@ -207,6 +207,7 @@ extern int XLogFileOpen(XLogSegNo segno, TimeLineID tli); extern void CheckXLogRemoved(XLogSegNo segno, TimeLineID tli); extern XLogSegNo XLogGetLastRemovedSegno(void); extern void XLogSetAsyncXactLSN(XLogRecPtr asyncXactLSN); +extern void WakeupWALWriter(void); extern void XLogSetReplicationSlotMinimumLSN(XLogRecPtr lsn); extern void xlog_redo(struct XLogReaderState *record); -- 2.34.1