diff --git a/src/backend/access/transam/clog.c b/src/backend/access/transam/clog.c index 33b5ca2..3da8aee 100644 --- a/src/backend/access/transam/clog.c +++ b/src/backend/access/transam/clog.c @@ -691,6 +691,34 @@ CLOGPagePrecedes(int page1, int page2) /* + * Flush dirty CLOG pages, if they're not too recent. + * + * Return true if we do any work, and false otherwise. + */ +bool +BackgroundWriteCLOG() +{ + int pageno; + bool result; + TransactionId cutoff_xid; + + /* + * We read nextXid without taking XidGenLock; the read is atomic, and it + * doesn't really matter if we get a slightly stale value. + */ + cutoff_xid = ShmemVariableCache->nextXid; + cutoff_xid -= 2 * CLOG_XACTS_PER_PAGE; + pageno = TransactionIdToPage(cutoff_xid); + + 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);