From addfc07b80e304194129423eabe78a4608335220 Mon Sep 17 00:00:00 2001
From: Robert Haas <rhaas@postgresql.org>
Date: Mon, 25 Jan 2021 11:32:11 -0500
Subject: [PATCH v1 4/4] In StartupCLOG(), correct an off-by-one error.

nextXid represents the first XID that hasn't yet been allocated, not
the last one that gets allocated. So, we should use the previous XID
to determine the last CLOG page that ought to exist.

As far as we currently know, this mistake doesn't have any adverse
consequences at present, but it seems better to make the logic
more correct.
---
 src/backend/access/transam/clog.c | 27 ++++++++++++++++++++-------
 1 file changed, 20 insertions(+), 7 deletions(-)

diff --git a/src/backend/access/transam/clog.c b/src/backend/access/transam/clog.c
index 6fa4713fb4..bad883d5a2 100644
--- a/src/backend/access/transam/clog.c
+++ b/src/backend/access/transam/clog.c
@@ -742,6 +742,23 @@ ZeroCLOGPage(int pageno, bool writeXlog)
 	return slotno;
 }
 
+/*
+ * Based on ShmemVariableCache->nextXid, compute the latest CLOG page that
+ * is expected to exist.
+ */
+static int
+FullTransactionIdToLatestPageNumber(FullTransactionId nextXid)
+{
+	/*
+	 * If nextXid coresponds to the first transaction on a CLOG page, then
+	 * the CLOG page will not have been initialized yet, but if it corresponds
+	 * to the second or later transaction on the page, then it should already
+	 * exist. See GetNewTransactionId().
+	 */
+	FullTransactionIdRetreat(&nextXid);
+	return TransactionIdToPage(XidFromFullTransactionId(nextXid));
+}
+
 /*
  * This must be called ONCE during postmaster or standalone-backend startup,
  * after StartupXLOG has initialized ShmemVariableCache->nextXid.
@@ -749,16 +766,12 @@ ZeroCLOGPage(int pageno, bool writeXlog)
 void
 StartupCLOG(void)
 {
-	TransactionId xid = XidFromFullTransactionId(ShmemVariableCache->nextXid);
-	int			pageno = TransactionIdToPage(xid);
+	int			pageno;
 
+	/* Initialize our idea of the latest page number. */
+	pageno = FullTransactionIdToLatestPageNumber(ShmemVariableCache->nextXid);
 	LWLockAcquire(XactSLRULock, LW_EXCLUSIVE);
-
-	/*
-	 * Initialize our idea of the latest page number.
-	 */
 	XactCtl->shared->latest_page_number = pageno;
-
 	LWLockRelease(XactSLRULock);
 }
 
-- 
2.24.3 (Apple Git-128)

