Provide XLogRecGetFullXid().
authorThomas Munro <tmunro@postgresql.org>
Mon, 15 Jul 2019 05:03:46 +0000 (17:03 +1200)
committerThomas Munro <tmunro@postgresql.org>
Mon, 15 Jul 2019 05:04:29 +0000 (17:04 +1200)
In order to be able to work with FullTransactionId values during replay
without increasing the size of the WAL, infer the epoch.  In general we
can't do that safely, but during replay we can because we know that
nextFullXid can't advance concurrently.

Prevent frontend code from seeing this new function, due to the above
restriction.  Perhaps in future it will be possible to extract the value
entirely from independent WAL records, and then this restriction can be
lifted.

Author: Thomas Munro, based on earlier code from Andres Freund
Discussion: https://postgr.es/m/CA%2BhUKG%2BmLmuDjMi6o1dxkKvGRL56Y2Rz%2BiXAcrZV03G9ZuFQ8Q%40mail.gmail.com

src/backend/access/transam/xlogreader.c
src/include/access/xlogreader.h

index 41dae916b46875083f04fc0f8ce14fbb87b218d7..33ccfc155315ceca6a5e2c48c7db425a95dda190 100644 (file)
@@ -26,6 +26,7 @@
 #include "replication/origin.h"
 
 #ifndef FRONTEND
+#include "miscadmin.h"
 #include "utils/memutils.h"
 #endif
 
@@ -1443,3 +1444,37 @@ RestoreBlockImage(XLogReaderState *record, uint8 block_id, char *page)
 
        return true;
 }
+
+#ifndef FRONTEND
+
+/*
+ * Extract the FullTransactionId from a WAL record.
+ */
+FullTransactionId
+XLogRecGetFullXid(XLogReaderState *record)
+{
+       TransactionId   xid,
+                                       next_xid;
+       uint32                  epoch;
+
+       /*
+        * This function is only safe during replay, because it depends on the
+        * replay state.  See AdvanceNextFullTransactionIdPastXid() for more.
+        */
+       Assert(AmStartupProcess() || !IsUnderPostmaster);
+
+       xid = XLogRecGetXid(record);
+       next_xid = XidFromFullTransactionId(ShmemVariableCache->nextFullXid);
+       epoch = EpochFromFullTransactionId(ShmemVariableCache->nextFullXid);
+
+       /*
+        * If xid is numerically greater than next_xid, it has to be from the
+        * last epoch.
+        */
+       if (unlikely(xid > next_xid))
+               --epoch;
+
+       return FullTransactionIdFromEpochAndXid(epoch, xid);
+};
+
+#endif
index 04228e2a8715866e3a981402bd1e7baa7e7bc4c7..a12c94cba67db406f80701572a3a5e39cae677bb 100644 (file)
 #ifndef XLOGREADER_H
 #define XLOGREADER_H
 
+#ifndef FRONTEND
+#include "access/transam.h"
+#endif
+
 #include "access/xlogrecord.h"
 
 typedef struct XLogReaderState XLogReaderState;
@@ -240,6 +244,10 @@ extern bool DecodeXLogRecord(XLogReaderState *state, XLogRecord *record,
 #define XLogRecBlockImageApply(decoder, block_id) \
        ((decoder)->blocks[block_id].apply_image)
 
+#ifndef FRONTEND
+extern FullTransactionId XLogRecGetFullXid(XLogReaderState *record);
+#endif
+
 extern bool RestoreBlockImage(XLogReaderState *recoder, uint8 block_id, char *dst);
 extern char *XLogRecGetBlockData(XLogReaderState *record, uint8 block_id, Size *len);
 extern bool XLogRecGetBlockTag(XLogReaderState *record, uint8 block_id,