]> git.ipfire.org Git - thirdparty/postgresql.git/commitdiff
Refactor some repetitive SLRU code
authorÁlvaro Herrera <alvherre@kurilemu.de>
Mon, 7 Jul 2025 14:49:19 +0000 (16:49 +0200)
committerÁlvaro Herrera <alvherre@kurilemu.de>
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 <evgeny.voropaev@tantorlabs.com>
Reviewed by: Álvaro Herrera <alvherre@kurilemu.de>
Reviewed by: Andrey Borodin <x4mmm@yandex-team.ru>
Reviewed by: Aleksander Alekseev <aleksander@timescale.com>
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);