From 4216f942747a2322d46533e5f774b2f016b8be4e Mon Sep 17 00:00:00 2001
From: jcoleman <jtc331@gmail.com>
Date: Fri, 14 Jan 2022 22:26:10 +0000
Subject: [PATCH v1] Expose LSN of last commit via pg_last_committed_xact

---
 src/backend/access/transam/commit_ts.c | 27 ++++++++++++++++++--------
 src/backend/access/transam/twophase.c  |  2 +-
 src/backend/access/transam/xact.c      |  7 ++++---
 src/include/access/commit_ts.h         |  4 ++--
 src/include/catalog/pg_proc.dat        |  6 +++---
 5 files changed, 29 insertions(+), 17 deletions(-)

diff --git a/src/backend/access/transam/commit_ts.c b/src/backend/access/transam/commit_ts.c
index 659109f8d4..8ed6fb2b29 100644
--- a/src/backend/access/transam/commit_ts.c
+++ b/src/backend/access/transam/commit_ts.c
@@ -37,6 +37,7 @@
 #include "utils/builtins.h"
 #include "utils/snapmgr.h"
 #include "utils/timestamp.h"
+#include "utils/pg_lsn.h"
 
 /*
  * Defines for CommitTs page sizes.  A page is the same BLCKSZ as is used
@@ -93,6 +94,7 @@ static SlruCtlData CommitTsCtlData;
 typedef struct CommitTimestampShared
 {
 	TransactionId xidLastCommit;
+	XLogRecPtr lsnLastCommit;
 	CommitTimestampEntry dataLastCommit;
 	bool		commitTsActive;
 } CommitTimestampShared;
@@ -135,7 +137,7 @@ static void WriteTruncateXlogRec(int pageno, TransactionId oldestXid);
 void
 TransactionTreeSetCommitTsData(TransactionId xid, int nsubxids,
 							   TransactionId *subxids, TimestampTz timestamp,
-							   RepOriginId nodeid)
+							   XLogRecPtr commitLsn, RepOriginId nodeid)
 {
 	int			i;
 	TransactionId headxid;
@@ -198,6 +200,7 @@ TransactionTreeSetCommitTsData(TransactionId xid, int nsubxids,
 	/* update the cached value in shared memory */
 	LWLockAcquire(CommitTsLock, LW_EXCLUSIVE);
 	commitTsShared->xidLastCommit = xid;
+	commitTsShared->lsnLastCommit = commitLsn;
 	commitTsShared->dataLastCommit.time = timestamp;
 	commitTsShared->dataLastCommit.nodeid = nodeid;
 
@@ -349,7 +352,7 @@ TransactionIdGetCommitTsData(TransactionId xid, TimestampTz *ts,
  * as NULL if not wanted.
  */
 TransactionId
-GetLatestCommitTsData(TimestampTz *ts, RepOriginId *nodeid)
+GetLatestCommitTsData(TimestampTz *ts, XLogRecPtr *lsn, RepOriginId *nodeid)
 {
 	TransactionId xid;
 
@@ -362,6 +365,8 @@ GetLatestCommitTsData(TimestampTz *ts, RepOriginId *nodeid)
 	xid = commitTsShared->xidLastCommit;
 	if (ts)
 		*ts = commitTsShared->dataLastCommit.time;
+	if (lsn)
+		*lsn = commitTsShared->lsnLastCommit;
 	if (nodeid)
 		*nodeid = commitTsShared->dataLastCommit.nodeid;
 	LWLockRelease(CommitTsLock);
@@ -414,24 +419,27 @@ pg_last_committed_xact(PG_FUNCTION_ARGS)
 	TransactionId xid;
 	RepOriginId nodeid;
 	TimestampTz ts;
-	Datum		values[3];
-	bool		nulls[3];
+	XLogRecPtr lsn;
+	Datum		values[4];
+	bool		nulls[4];
 	TupleDesc	tupdesc;
 	HeapTuple	htup;
 
 	/* and construct a tuple with our data */
-	xid = GetLatestCommitTsData(&ts, &nodeid);
+	xid = GetLatestCommitTsData(&ts, &lsn, &nodeid);
 
 	/*
 	 * Construct a tuple descriptor for the result row.  This must match this
 	 * function's pg_proc entry!
 	 */
-	tupdesc = CreateTemplateTupleDesc(3);
+	tupdesc = CreateTemplateTupleDesc(4);
 	TupleDescInitEntry(tupdesc, (AttrNumber) 1, "xid",
 					   XIDOID, -1, 0);
 	TupleDescInitEntry(tupdesc, (AttrNumber) 2, "timestamp",
 					   TIMESTAMPTZOID, -1, 0);
-	TupleDescInitEntry(tupdesc, (AttrNumber) 3, "roident",
+	TupleDescInitEntry(tupdesc, (AttrNumber) 3, "lsn",
+					   PG_LSNOID, -1, 0);
+	TupleDescInitEntry(tupdesc, (AttrNumber) 4, "roident",
 					   OIDOID, -1, 0);
 	tupdesc = BlessTupleDesc(tupdesc);
 
@@ -447,8 +455,11 @@ pg_last_committed_xact(PG_FUNCTION_ARGS)
 		values[1] = TimestampTzGetDatum(ts);
 		nulls[1] = false;
 
-		values[2] = ObjectIdGetDatum((Oid) nodeid);
+		values[2] = LSNGetDatum(lsn);
 		nulls[2] = false;
+
+		values[3] = ObjectIdGetDatum((Oid) nodeid);
+		nulls[3] = false;
 	}
 
 	htup = heap_form_tuple(tupdesc, values, nulls);
diff --git a/src/backend/access/transam/twophase.c b/src/backend/access/transam/twophase.c
index 271a3146db..cd33849aea 100644
--- a/src/backend/access/transam/twophase.c
+++ b/src/backend/access/transam/twophase.c
@@ -2300,7 +2300,7 @@ RecordTransactionCommitPrepared(TransactionId xid,
 
 	TransactionTreeSetCommitTsData(xid, nchildren, children,
 								   replorigin_session_origin_timestamp,
-								   replorigin_session_origin);
+								   recptr, replorigin_session_origin);
 
 	/*
 	 * We don't currently try to sleep before flush here ... nor is there any
diff --git a/src/backend/access/transam/xact.c b/src/backend/access/transam/xact.c
index c9516e03fa..7256b3f015 100644
--- a/src/backend/access/transam/xact.c
+++ b/src/backend/access/transam/xact.c
@@ -1355,6 +1355,7 @@ RecordTransactionCommit(void)
 	else
 	{
 		bool		replorigin;
+		XLogRecPtr	commit_lsn;
 
 		/*
 		 * Are we using the replication origins feature?  Or, in other words,
@@ -1391,7 +1392,7 @@ RecordTransactionCommit(void)
 
 		SetCurrentTransactionStopTimestamp();
 
-		XactLogCommitRecord(xactStopTimestamp,
+		commit_lsn = XactLogCommitRecord(xactStopTimestamp,
 							nchildren, children, nrels, rels,
 							nmsgs, invalMessages,
 							RelcacheInitFileInval,
@@ -1418,7 +1419,7 @@ RecordTransactionCommit(void)
 
 		TransactionTreeSetCommitTsData(xid, nchildren, children,
 									   replorigin_session_origin_timestamp,
-									   replorigin_session_origin);
+									   commit_lsn, replorigin_session_origin);
 	}
 
 	/*
@@ -5881,7 +5882,7 @@ xact_redo_commit(xl_xact_parsed_commit *parsed,
 
 	/* Set the transaction commit timestamp and metadata */
 	TransactionTreeSetCommitTsData(xid, parsed->nsubxacts, parsed->subxacts,
-								   commit_time, origin_id);
+								   commit_time, lsn, origin_id);
 
 	if (standbyState == STANDBY_DISABLED)
 	{
diff --git a/src/include/access/commit_ts.h b/src/include/access/commit_ts.h
index 7662f8e1a9..e20c8d5c08 100644
--- a/src/include/access/commit_ts.h
+++ b/src/include/access/commit_ts.h
@@ -21,10 +21,10 @@ extern PGDLLIMPORT bool track_commit_timestamp;
 
 extern void TransactionTreeSetCommitTsData(TransactionId xid, int nsubxids,
 										   TransactionId *subxids, TimestampTz timestamp,
-										   RepOriginId nodeid);
+										   XLogRecPtr commitLsn, RepOriginId nodeid);
 extern bool TransactionIdGetCommitTsData(TransactionId xid,
 										 TimestampTz *ts, RepOriginId *nodeid);
-extern TransactionId GetLatestCommitTsData(TimestampTz *ts,
+extern TransactionId GetLatestCommitTsData(TimestampTz *ts, XLogRecPtr *lsn,
 										   RepOriginId *nodeid);
 
 extern Size CommitTsShmemBuffers(void);
diff --git a/src/include/catalog/pg_proc.dat b/src/include/catalog/pg_proc.dat
index d6bf1f3274..d5fe8f4161 100644
--- a/src/include/catalog/pg_proc.dat
+++ b/src/include/catalog/pg_proc.dat
@@ -6157,11 +6157,11 @@
   prosrc => 'pg_xact_commit_timestamp_origin' },
 
 { oid => '3583',
-  descr => 'get transaction Id, commit timestamp and replication origin of latest transaction commit',
+  descr => 'get transaction Id, commit timestamp, commit lsn and replication origin of latest transaction commit',
   proname => 'pg_last_committed_xact', provolatile => 'v',
   prorettype => 'record', proargtypes => '',
-  proallargtypes => '{xid,timestamptz,oid}', proargmodes => '{o,o,o}',
-  proargnames => '{xid,timestamp,roident}',
+  proallargtypes => '{xid,timestamptz,pg_lsn,oid}', proargmodes => '{o,o,o,o}',
+  proargnames => '{xid,timestamp,lsn,roident}',
   prosrc => 'pg_last_committed_xact' },
 
 { oid => '3537', descr => 'get identification of SQL object',
-- 
2.20.1

