Refactor some repetitive SLRU code
authorÁlvaro Herrera <[email protected]>
Mon, 7 Jul 2025 14:49:19 +0000 (16:49 +0200)
committerÁlvaro Herrera <[email protected]>
Mon, 7 Jul 2025 14:49:19 +0000 (16:49 +0200)
Functions to bootstrap and zero pages in various SLRU callers were
fairly duplicative.  We can slash almost two hundred lines with a couple
of simple helpers:

 - SimpleLruZeroAndWritePage: Does the equivalent of SimpleLruZeroPage
   followed by flushing the page to disk
 - XLogSimpleInsertInt64: Does a XLogBeginInsert followed by XLogInsert
   of a trivial record whose data is just an int64.

Author: Evgeny Voropaev <[email protected]>
Reviewed by: Álvaro Herrera <[email protected]>
Reviewed by: Andrey Borodin <[email protected]>
Reviewed by: Aleksander Alekseev <[email protected]>
Discussion: https://www.postgresql.org/message-id/flat/97820ce8-a1cd-407f-a02b-47368fadb14b%40tantorlabs.com

src/backend/access/transam/clog.c
src/backend/access/transam/commit_ts.c
src/backend/access/transam/multixact.c
src/backend/access/transam/slru.c
src/backend/access/transam/subtrans.c
src/backend/access/transam/xloginsert.c
src/include/access/slru.h
src/include/access/xloginsert.h

index 48f10bec91e12fa9acc485852bf5acced24c9b4d..e80fbe109cf3c83cbf73e344fa52a44305250f80 100644 (file)
@@ -110,9 +110,7 @@ static SlruCtlData XactCtlData;
 #define XactCtl (&XactCtlData)
 
 
-static int ZeroCLOGPage(int64 pageno, bool writeXlog);
 static bool CLOGPagePrecedes(int64 page1, int64 page2);
-static void WriteZeroPageXlogRec(int64 pageno);
 static void WriteTruncateXlogRec(int64 pageno, TransactionId oldestXact,
                                 Oid oldestXactDb);
 static void TransactionIdSetPageStatus(TransactionId xid, int nsubxids,
@@ -832,41 +830,8 @@ check_transaction_buffers(int *newval, void **extra, GucSource source)
 void
 BootStrapCLOG(void)
 {
-   int         slotno;
-   LWLock     *lock = SimpleLruGetBankLock(XactCtl, 0);
-
-   LWLockAcquire(lock, LW_EXCLUSIVE);
-
-   /* Create and zero the first page of the commit log */
-   slotno = ZeroCLOGPage(0, false);
-
-   /* Make sure it's written out */
-   SimpleLruWritePage(XactCtl, slotno);
-   Assert(!XactCtl->shared->page_dirty[slotno]);
-
-   LWLockRelease(lock);
-}
-
-/*
- * Initialize (or reinitialize) a page of CLOG to zeroes.
- * If writeXlog is true, also emit an XLOG record saying we did this.
- *
- * The page is not actually written, just set up in shared memory.
- * The slot number of the new page is returned.
- *
- * Control lock must be held at entry, and will be held at exit.
- */
-static int
-ZeroCLOGPage(int64 pageno, bool writeXlog)
-{
-   int         slotno;
-
-   slotno = SimpleLruZeroPage(XactCtl, pageno);
-
-   if (writeXlog)
-       WriteZeroPageXlogRec(pageno);
-
-   return slotno;
+   /* Zero the initial page and flush it to disk */
+   SimpleLruZeroAndWritePage(XactCtl, 0);
 }
 
 /*
@@ -974,8 +939,9 @@ ExtendCLOG(TransactionId newestXact)
 
    LWLockAcquire(lock, LW_EXCLUSIVE);
 
-   /* Zero the page and make an XLOG entry about it */
-   ZeroCLOGPage(pageno, true);
+   /* Zero the page and make a WAL entry about it */
+   SimpleLruZeroPage(XactCtl, pageno);
+   XLogSimpleInsertInt64(RM_CLOG_ID, CLOG_ZEROPAGE, pageno);
 
    LWLockRelease(lock);
 }
@@ -1067,17 +1033,6 @@ CLOGPagePrecedes(int64 page1, int64 page2)
 }
 
 
-/*
- * Write a ZEROPAGE xlog record
- */
-static void
-WriteZeroPageXlogRec(int64 pageno)
-{
-   XLogBeginInsert();
-   XLogRegisterData(&pageno, sizeof(pageno));
-   (void) XLogInsert(RM_CLOG_ID, CLOG_ZEROPAGE);
-}
-
 /*
  * Write a TRUNCATE xlog record
  *
@@ -1114,19 +1069,9 @@ clog_redo(XLogReaderState *record)
    if (info == CLOG_ZEROPAGE)
    {
        int64       pageno;
-       int         slotno;
-       LWLock     *lock;
 
        memcpy(&pageno, XLogRecGetData(record), sizeof(pageno));
-
-       lock = SimpleLruGetBankLock(XactCtl, pageno);
-       LWLockAcquire(lock, LW_EXCLUSIVE);
-
-       slotno = ZeroCLOGPage(pageno, false);
-       SimpleLruWritePage(XactCtl, slotno);
-       Assert(!XactCtl->shared->page_dirty[slotno]);
-
-       LWLockRelease(lock);
+       SimpleLruZeroAndWritePage(XactCtl, pageno);
    }
    else if (info == CLOG_TRUNCATE)
    {
index 225ff7ca9f2d3a4c87efe1355d5d374a1344437f..370b38e048b9195aca197318ddfd6d72c87bc276 100644 (file)
@@ -114,11 +114,9 @@ static void SetXidCommitTsInPage(TransactionId xid, int nsubxids,
 static void TransactionIdSetCommitTs(TransactionId xid, TimestampTz ts,
                                     RepOriginId nodeid, int slotno);
 static void error_commit_ts_disabled(void);
-static int ZeroCommitTsPage(int64 pageno, bool writeXlog);
 static bool CommitTsPagePrecedes(int64 page1, int64 page2);
 static void ActivateCommitTs(void);
 static void DeactivateCommitTs(void);
-static void WriteZeroPageXlogRec(int64 pageno);
 static void WriteTruncateXlogRec(int64 pageno, TransactionId oldestXid);
 
 /*
@@ -602,28 +600,6 @@ BootStrapCommitTs(void)
     */
 }
 
-/*
- * Initialize (or reinitialize) a page of CommitTs to zeroes.
- * If writeXlog is true, also emit an XLOG record saying we did this.
- *
- * The page is not actually written, just set up in shared memory.
- * The slot number of the new page is returned.
- *
- * Control lock must be held at entry, and will be held at exit.
- */
-static int
-ZeroCommitTsPage(int64 pageno, bool writeXlog)
-{
-   int         slotno;
-
-   slotno = SimpleLruZeroPage(CommitTsCtl, pageno);
-
-   if (writeXlog)
-       WriteZeroPageXlogRec(pageno);
-
-   return slotno;
-}
-
 /*
  * This must be called ONCE during postmaster or standalone-backend startup,
  * after StartupXLOG has initialized TransamVariables->nextXid.
@@ -754,16 +730,7 @@ ActivateCommitTs(void)
 
    /* Create the current segment file, if necessary */
    if (!SimpleLruDoesPhysicalPageExist(CommitTsCtl, pageno))
-   {
-       LWLock     *lock = SimpleLruGetBankLock(CommitTsCtl, pageno);
-       int         slotno;
-
-       LWLockAcquire(lock, LW_EXCLUSIVE);
-       slotno = ZeroCommitTsPage(pageno, false);
-       SimpleLruWritePage(CommitTsCtl, slotno);
-       Assert(!CommitTsCtl->shared->page_dirty[slotno]);
-       LWLockRelease(lock);
-   }
+       SimpleLruZeroAndWritePage(CommitTsCtl, pageno);
 
    /* Change the activation status in shared memory. */
    LWLockAcquire(CommitTsLock, LW_EXCLUSIVE);
@@ -874,8 +841,12 @@ ExtendCommitTs(TransactionId newestXact)
 
    LWLockAcquire(lock, LW_EXCLUSIVE);
 
-   /* Zero the page and make an XLOG entry about it */
-   ZeroCommitTsPage(pageno, !InRecovery);
+   /* Zero the page ... */
+   SimpleLruZeroPage(CommitTsCtl, pageno);
+
+   /* and make a WAL entry about that, unless we're in REDO */
+   if (!InRecovery)
+       XLogSimpleInsertInt64(RM_COMMIT_TS_ID, COMMIT_TS_ZEROPAGE, pageno);
 
    LWLockRelease(lock);
 }
@@ -989,17 +960,6 @@ CommitTsPagePrecedes(int64 page1, int64 page2)
 }
 
 
-/*
- * Write a ZEROPAGE xlog record
- */
-static void
-WriteZeroPageXlogRec(int64 pageno)
-{
-   XLogBeginInsert();
-   XLogRegisterData(&pageno, sizeof(pageno));
-   (void) XLogInsert(RM_COMMIT_TS_ID, COMMIT_TS_ZEROPAGE);
-}
-
 /*
  * Write a TRUNCATE xlog record
  */
@@ -1030,19 +990,9 @@ commit_ts_redo(XLogReaderState *record)
    if (info == COMMIT_TS_ZEROPAGE)
    {
        int64       pageno;
-       int         slotno;
-       LWLock     *lock;
 
        memcpy(&pageno, XLogRecGetData(record), sizeof(pageno));
-
-       lock = SimpleLruGetBankLock(CommitTsCtl, pageno);
-       LWLockAcquire(lock, LW_EXCLUSIVE);
-
-       slotno = ZeroCommitTsPage(pageno, false);
-       SimpleLruWritePage(CommitTsCtl, slotno);
-       Assert(!CommitTsCtl->shared->page_dirty[slotno]);
-
-       LWLockRelease(lock);
+       SimpleLruZeroAndWritePage(CommitTsCtl, pageno);
    }
    else if (info == COMMIT_TS_TRUNCATE)
    {
index 7a7afe3edc6720e6ced98e70a8667254c8cc35b0..3cb09c3d5987c2b0a45cc848c2c312d590cb2713 100644 (file)
@@ -401,8 +401,6 @@ static void mXactCachePut(MultiXactId multi, int nmembers,
 static char *mxstatus_to_string(MultiXactStatus status);
 
 /* management of SLRU infrastructure */
-static int ZeroMultiXactOffsetPage(int64 pageno, bool writeXlog);
-static int ZeroMultiXactMemberPage(int64 pageno, bool writeXlog);
 static bool MultiXactOffsetPagePrecedes(int64 page1, int64 page2);
 static bool MultiXactMemberPagePrecedes(int64 page1, int64 page2);
 static bool MultiXactOffsetPrecedes(MultiXactOffset offset1,
@@ -413,7 +411,6 @@ static bool MultiXactOffsetWouldWrap(MultiXactOffset boundary,
                                     MultiXactOffset start, uint32 distance);
 static bool SetOffsetVacuumLimit(bool is_startup);
 static bool find_multixact_start(MultiXactId multi, MultiXactOffset *result);
-static void WriteMZeroPageXlogRec(int64 pageno, uint8 info);
 static void WriteMTruncateXlogRec(Oid oldestMultiDB,
                                  MultiXactId startTruncOff,
                                  MultiXactId endTruncOff,
@@ -2033,70 +2030,9 @@ check_multixact_member_buffers(int *newval, void **extra, GucSource source)
 void
 BootStrapMultiXact(void)
 {
-   int         slotno;
-   LWLock     *lock;
-
-   lock = SimpleLruGetBankLock(MultiXactOffsetCtl, 0);
-   LWLockAcquire(lock, LW_EXCLUSIVE);
-
-   /* Create and zero the first page of the offsets log */
-   slotno = ZeroMultiXactOffsetPage(0, false);
-
-   /* Make sure it's written out */
-   SimpleLruWritePage(MultiXactOffsetCtl, slotno);
-   Assert(!MultiXactOffsetCtl->shared->page_dirty[slotno]);
-
-   LWLockRelease(lock);
-
-   lock = SimpleLruGetBankLock(MultiXactMemberCtl, 0);
-   LWLockAcquire(lock, LW_EXCLUSIVE);
-
-   /* Create and zero the first page of the members log */
-   slotno = ZeroMultiXactMemberPage(0, false);
-
-   /* Make sure it's written out */
-   SimpleLruWritePage(MultiXactMemberCtl, slotno);
-   Assert(!MultiXactMemberCtl->shared->page_dirty[slotno]);
-
-   LWLockRelease(lock);
-}
-
-/*
- * Initialize (or reinitialize) a page of MultiXactOffset to zeroes.
- * If writeXlog is true, also emit an XLOG record saying we did this.
- *
- * The page is not actually written, just set up in shared memory.
- * The slot number of the new page is returned.
- *
- * Control lock must be held at entry, and will be held at exit.
- */
-static int
-ZeroMultiXactOffsetPage(int64 pageno, bool writeXlog)
-{
-   int         slotno;
-
-   slotno = SimpleLruZeroPage(MultiXactOffsetCtl, pageno);
-
-   if (writeXlog)
-       WriteMZeroPageXlogRec(pageno, XLOG_MULTIXACT_ZERO_OFF_PAGE);
-
-   return slotno;
-}
-
-/*
- * Ditto, for MultiXactMember
- */
-static int
-ZeroMultiXactMemberPage(int64 pageno, bool writeXlog)
-{
-   int         slotno;
-
-   slotno = SimpleLruZeroPage(MultiXactMemberCtl, pageno);
-
-   if (writeXlog)
-       WriteMZeroPageXlogRec(pageno, XLOG_MULTIXACT_ZERO_MEM_PAGE);
-
-   return slotno;
+   /* Zero the initial pages and flush them to disk */
+   SimpleLruZeroAndWritePage(MultiXactOffsetCtl, 0);
+   SimpleLruZeroAndWritePage(MultiXactMemberCtl, 0);
 }
 
 /*
@@ -2134,7 +2070,7 @@ MaybeExtendOffsetSlru(void)
         * with creating a new segment file even if the page we're writing is
         * not the first in it, so this is enough.
         */
-       slotno = ZeroMultiXactOffsetPage(pageno, false);
+       slotno = SimpleLruZeroPage(MultiXactOffsetCtl, pageno);
        SimpleLruWritePage(MultiXactOffsetCtl, slotno);
    }
 
@@ -2568,8 +2504,10 @@ ExtendMultiXactOffset(MultiXactId multi)
 
    LWLockAcquire(lock, LW_EXCLUSIVE);
 
-   /* Zero the page and make an XLOG entry about it */
-   ZeroMultiXactOffsetPage(pageno, true);
+   /* Zero the page and make a WAL entry about it */
+   SimpleLruZeroPage(MultiXactOffsetCtl, pageno);
+   XLogSimpleInsertInt64(RM_MULTIXACT_ID, XLOG_MULTIXACT_ZERO_OFF_PAGE,
+                         pageno);
 
    LWLockRelease(lock);
 }
@@ -2611,8 +2549,10 @@ ExtendMultiXactMember(MultiXactOffset offset, int nmembers)
 
            LWLockAcquire(lock, LW_EXCLUSIVE);
 
-           /* Zero the page and make an XLOG entry about it */
-           ZeroMultiXactMemberPage(pageno, true);
+           /* Zero the page and make a WAL entry about it */
+           SimpleLruZeroPage(MultiXactMemberCtl, pageno);
+           XLogSimpleInsertInt64(RM_MULTIXACT_ID,
+                                 XLOG_MULTIXACT_ZERO_MEM_PAGE, pageno);
 
            LWLockRelease(lock);
        }
@@ -3347,18 +3287,6 @@ MultiXactOffsetPrecedes(MultiXactOffset offset1, MultiXactOffset offset2)
    return (diff < 0);
 }
 
-/*
- * Write an xlog record reflecting the zeroing of either a MEMBERs or
- * OFFSETs page (info shows which)
- */
-static void
-WriteMZeroPageXlogRec(int64 pageno, uint8 info)
-{
-   XLogBeginInsert();
-   XLogRegisterData(&pageno, sizeof(pageno));
-   (void) XLogInsert(RM_MULTIXACT_ID, info);
-}
-
 /*
  * Write a TRUNCATE xlog record
  *
@@ -3401,36 +3329,16 @@ multixact_redo(XLogReaderState *record)
    if (info == XLOG_MULTIXACT_ZERO_OFF_PAGE)
    {
        int64       pageno;
-       int         slotno;
-       LWLock     *lock;
 
        memcpy(&pageno, XLogRecGetData(record), sizeof(pageno));
-
-       lock = SimpleLruGetBankLock(MultiXactOffsetCtl, pageno);
-       LWLockAcquire(lock, LW_EXCLUSIVE);
-
-       slotno = ZeroMultiXactOffsetPage(pageno, false);
-       SimpleLruWritePage(MultiXactOffsetCtl, slotno);
-       Assert(!MultiXactOffsetCtl->shared->page_dirty[slotno]);
-
-       LWLockRelease(lock);
+       SimpleLruZeroAndWritePage(MultiXactOffsetCtl, pageno);
    }
    else if (info == XLOG_MULTIXACT_ZERO_MEM_PAGE)
    {
        int64       pageno;
-       int         slotno;
-       LWLock     *lock;
 
        memcpy(&pageno, XLogRecGetData(record), sizeof(pageno));
-
-       lock = SimpleLruGetBankLock(MultiXactMemberCtl, pageno);
-       LWLockAcquire(lock, LW_EXCLUSIVE);
-
-       slotno = ZeroMultiXactMemberPage(pageno, false);
-       SimpleLruWritePage(MultiXactMemberCtl, slotno);
-       Assert(!MultiXactMemberCtl->shared->page_dirty[slotno]);
-
-       LWLockRelease(lock);
+       SimpleLruZeroAndWritePage(MultiXactMemberCtl, pageno);
    }
    else if (info == XLOG_MULTIXACT_CREATE_ID)
    {
index fe56286d9a972a26a99ef1f776d145b0cdb5bbaf..10ec259f3829541f4a7b303d2f1a512d94241fc4 100644 (file)
@@ -433,6 +433,31 @@ SimpleLruZeroLSNs(SlruCtl ctl, int slotno)
               shared->lsn_groups_per_page * sizeof(XLogRecPtr));
 }
 
+/*
+ * This is a convenience wrapper for the common case of zeroing a page and
+ * immediately flushing it to disk.
+ *
+ * Control lock is acquired and released here.
+ */
+void
+SimpleLruZeroAndWritePage(SlruCtl ctl, int64 pageno)
+{
+   int         slotno;
+   LWLock     *lock;
+
+   lock = SimpleLruGetBankLock(ctl, pageno);
+   LWLockAcquire(lock, LW_EXCLUSIVE);
+
+   /* Create and zero the page */
+   slotno = SimpleLruZeroPage(ctl, pageno);
+
+   /* Make sure it's written out */
+   SimpleLruWritePage(ctl, slotno);
+   Assert(!ctl->shared->page_dirty[slotno]);
+
+   LWLockRelease(lock);
+}
+
 /*
  * Wait for any active I/O on a page slot to finish.  (This does not
  * guarantee that new I/O hasn't been started before we return, though.
index 15153618fad1662fd4231278383bdd3fe963c10a..09aace9e09f0e68fde3ce4bd14531f49a9ca5b11 100644 (file)
@@ -74,7 +74,6 @@ static SlruCtlData SubTransCtlData;
 #define SubTransCtl  (&SubTransCtlData)
 
 
-static int ZeroSUBTRANSPage(int64 pageno);
 static bool SubTransPagePrecedes(int64 page1, int64 page2);
 
 
@@ -269,33 +268,8 @@ check_subtrans_buffers(int *newval, void **extra, GucSource source)
 void
 BootStrapSUBTRANS(void)
 {
-   int         slotno;
-   LWLock     *lock = SimpleLruGetBankLock(SubTransCtl, 0);
-
-   LWLockAcquire(lock, LW_EXCLUSIVE);
-
-   /* Create and zero the first page of the subtrans log */
-   slotno = ZeroSUBTRANSPage(0);
-
-   /* Make sure it's written out */
-   SimpleLruWritePage(SubTransCtl, slotno);
-   Assert(!SubTransCtl->shared->page_dirty[slotno]);
-
-   LWLockRelease(lock);
-}
-
-/*
- * Initialize (or reinitialize) a page of SUBTRANS to zeroes.
- *
- * The page is not actually written, just set up in shared memory.
- * The slot number of the new page is returned.
- *
- * Control lock must be held at entry, and will be held at exit.
- */
-static int
-ZeroSUBTRANSPage(int64 pageno)
-{
-   return SimpleLruZeroPage(SubTransCtl, pageno);
+   /* Zero the initial page and flush it to disk */
+   SimpleLruZeroAndWritePage(SubTransCtl, 0);
 }
 
 /*
@@ -335,7 +309,7 @@ StartupSUBTRANS(TransactionId oldestActiveXID)
            prevlock = lock;
        }
 
-       (void) ZeroSUBTRANSPage(startPage);
+       (void) SimpleLruZeroPage(SubTransCtl, startPage);
        if (startPage == endPage)
            break;
 
@@ -395,7 +369,7 @@ ExtendSUBTRANS(TransactionId newestXact)
    LWLockAcquire(lock, LW_EXCLUSIVE);
 
    /* Zero the page */
-   ZeroSUBTRANSPage(pageno);
+   SimpleLruZeroPage(SubTransCtl, pageno);
 
    LWLockRelease(lock);
 }
index 5ee9d0b028eaefa8ffa552c9c1a693c74874007c..c7571429e8e97bfcca6d3122812d7814b089846d 100644 (file)
@@ -529,6 +529,18 @@ XLogInsert(RmgrId rmid, uint8 info)
    return EndPos;
 }
 
+/*
+ * Simple wrapper to XLogInsert to insert a WAL record with elementary
+ * contents (only an int64 is supported as value currently).
+ */
+XLogRecPtr
+XLogSimpleInsertInt64(RmgrId rmid, uint8 info, int64 value)
+{
+   XLogBeginInsert();
+   XLogRegisterData(&value, sizeof(value));
+   return XLogInsert(rmid, info);
+}
+
 /*
  * Assemble a WAL record from the registered data and buffers into an
  * XLogRecData chain, ready for insertion with XLogInsertRecord().
index e142800aab216cd67bf0363ece8dadc9c7d5df73..20dbd1e0070be00ec5b03573fcb89c0430001a65 100644 (file)
@@ -187,6 +187,7 @@ extern void SimpleLruInit(SlruCtl ctl, const char *name, int nslots, int nlsns,
                          int bank_tranche_id, SyncRequestHandler sync_handler,
                          bool long_segment_names);
 extern int SimpleLruZeroPage(SlruCtl ctl, int64 pageno);
+extern void SimpleLruZeroAndWritePage(SlruCtl ctl, int64 pageno);
 extern int SimpleLruReadPage(SlruCtl ctl, int64 pageno, bool write_ok,
                              TransactionId xid);
 extern int SimpleLruReadPage_ReadOnly(SlruCtl ctl, int64 pageno,
index cf057f033a281d6cdea0dbf3f368fa1d4af955df..d6a71415d4fd7120bbcfb59a8bf237bf761256a9 100644 (file)
@@ -44,6 +44,7 @@
 extern void XLogBeginInsert(void);
 extern void XLogSetRecordFlags(uint8 flags);
 extern XLogRecPtr XLogInsert(RmgrId rmid, uint8 info);
+extern XLogRecPtr XLogSimpleInsertInt64(RmgrId rmid, uint8 info, int64 value);
 extern void XLogEnsureRecordSpace(int max_block_id, int ndatas);
 extern void XLogRegisterData(const void *data, uint32 len);
 extern void XLogRegisterBuffer(uint8 block_id, Buffer buffer, uint8 flags);