diff --git a/src/backend/access/transam/clog.c b/src/backend/access/transam/clog.c index 33b5ca2..ac8d62b 100644 --- a/src/backend/access/transam/clog.c +++ b/src/backend/access/transam/clog.c @@ -37,6 +37,8 @@ #include "access/transam.h" #include "miscadmin.h" #include "pg_trace.h" +#include "storage/procarray.h" +#include "utils/snapmgr.h" /* * Defines for CLOG page sizes. A page is the same BLCKSZ as is used @@ -691,6 +693,41 @@ CLOGPagePrecedes(int page1, int page2) /* + * Write dirty CLOG pages that won't receive any more updates. + * + * Return true if we do any work, and false otherwise. + */ +bool +BackgroundWriteCLOG() +{ + int pageno; + bool result; + static SnapshotData DummySnapshotData; + + /* + * Compute cutoff page - i.e. the point before which we don't expect to + * do any more writes. During recovery it may not be possible to compute + * a snapshot, so we just skip it in that case. (There might be a way + * to improve this.) + */ + if (RecoveryInProgress()) + return false; + GetSnapshotData(&DummySnapshotData); + pageno = TransactionIdToPage(RecentXmin); + + /* + * The actual write is done by the SLRU code, but we must acquire the + * lock first. + */ + LWLockAcquire(CLogControlLock, LW_EXCLUSIVE); + result = SimpleLruBackgroundFlush(ClogCtl, pageno); + LWLockRelease(CLogControlLock); + + return result; +} + + +/* * Write a ZEROPAGE xlog record */ static void diff --git a/src/backend/access/transam/slru.c b/src/backend/access/transam/slru.c index a8e3f19..6f9b993 100644 --- a/src/backend/access/transam/slru.c +++ b/src/backend/access/transam/slru.c @@ -1091,6 +1091,42 @@ SimpleLruFlush(SlruCtl ctl, bool checkpoint) } /* + * Write out a dirty page, if there's one that precedes the cutoff point. + * + * The intention here is that pageno should be chosen so that no further writes + * are expected in any preceding page. That way, we won't do background writes + * of pages that will be re-dirtied. + */ +bool +SimpleLruBackgroundFlush(SlruCtl ctl, int pageno) +{ + SlruShared shared = ctl->shared; + int slotno; + int target_slot = -1; + int target_page = pageno; + + /* Find the oldest valid, dirty page before the cutoff point. */ + for (slotno = 0; slotno < shared->num_slots; slotno++) + { + if (shared->page_status[slotno] == SLRU_PAGE_VALID && + shared->page_dirty[slotno] && + ctl->PagePrecedes(shared->page_number[slotno], target_page)) + { + target_slot = slotno; + target_page = shared->page_number[slotno]; + } + } + + /* No qualifying pages, so indicate that there's no work to be done. */ + if (target_slot == -1) + return false; + + /* Write the page. */ + SlruInternalWritePage(ctl, target_slot, NULL); + return true; +} + +/* * Remove all segments before the one holding the passed page number */ void diff --git a/src/backend/postmaster/bgwriter.c b/src/backend/postmaster/bgwriter.c index 59c539a..971f03f 100644 --- a/src/backend/postmaster/bgwriter.c +++ b/src/backend/postmaster/bgwriter.c @@ -42,6 +42,7 @@ #include #include +#include "access/clog.h" #include "access/xlog_internal.h" #include "libpq/pqsignal.h" #include "miscadmin.h" @@ -285,6 +286,10 @@ BackgroundWriterMain(void) ResetLatch(&MyProc->procLatch); lapped = BgBufferSync(); + /* Consider writing old CLOG pages. */ + if (BackgroundWriteCLOG()) + lapped = false; + if (lapped && !hibernating) { /* diff --git a/src/include/access/clog.h b/src/include/access/clog.h index bed3b8c..577df43 100644 --- a/src/include/access/clog.h +++ b/src/include/access/clog.h @@ -40,6 +40,7 @@ extern void StartupCLOG(void); extern void TrimCLOG(void); extern void ShutdownCLOG(void); extern void CheckPointCLOG(void); +extern bool BackgroundWriteCLOG(void); extern void ExtendCLOG(TransactionId newestXact); extern void TruncateCLOG(TransactionId oldestXact); diff --git a/src/include/access/slru.h b/src/include/access/slru.h index 41cd484..52dfe31 100644 --- a/src/include/access/slru.h +++ b/src/include/access/slru.h @@ -143,6 +143,7 @@ extern int SimpleLruReadPage(SlruCtl ctl, int pageno, bool write_ok, extern int SimpleLruReadPage_ReadOnly(SlruCtl ctl, int pageno, TransactionId xid); extern void SimpleLruWritePage(SlruCtl ctl, int slotno); +extern bool SimpleLruBackgroundFlush(SlruCtl ctl, int pageno); extern void SimpleLruFlush(SlruCtl ctl, bool checkpoint); extern void SimpleLruTruncate(SlruCtl ctl, int cutoffPage);