Make use FullTransactionId in 2PC filenames
authorAlexander Korotkov <[email protected]>
Tue, 28 Nov 2023 23:43:13 +0000 (01:43 +0200)
committerAlexander Korotkov <[email protected]>
Tue, 28 Nov 2023 23:43:36 +0000 (01:43 +0200)
Switch from using TransactionId to FullTransactionId in naming of 2PC files.
Transaction state file in the pg_twophase directory now have extra 8 bytes in
the name to address an epoch of a given xid.

Author: Maxim Orlov, Aleksander Alekseev, Alexander Korotkov, Teodor Sigaev
Author: Nikita Glukhov, Pavel Borisov, Yura Sokolov
Reviewed-by: Jacob Champion, Heikki Linnakangas, Alexander Korotkov
Reviewed-by: Japin Li, Pavel Borisov, Tom Lane, Peter Eisentraut, Andres Freund
Reviewed-by: Andrey Borodin, Dilip Kumar, Aleksander Alekseev
Discussion: https://postgr.es/m/CACG%3DezZe1NQSCnfHOr78AtAZxJZeCvxrts0ygrxYwe%3DpyyjVWA%40mail.gmail.com
Discussion: https://postgr.es/m/CAJ7c6TPDOYBYrnCAeyndkBktO0WG2xSdYduTF0nxq%2BvfkmTF5Q%40mail.gmail.com

src/backend/access/transam/twophase.c

index c6af8cfd7e2899e8ee82dbcd59d66d4f5700ab77..a91ef0deeafd7ff9ead087afebc9ddb3e8185fb1 100644 (file)
@@ -942,8 +942,46 @@ TwoPhaseGetDummyProc(TransactionId xid, bool lock_held)
 /* State file support                                                  */
 /************************************************************************/
 
-#define TwoPhaseFilePath(path, xid) \
-   snprintf(path, MAXPGPATH, TWOPHASE_DIR "/%08X", xid)
+/*
+ * Compute the FullTransactionId for the given TransactionId.
+ *
+ * The wrap logic is safe here because the span of active xids cannot exceed one
+ * epoch at any given time.
+ */
+static inline FullTransactionId
+AdjustToFullTransactionId(TransactionId xid)
+{
+   FullTransactionId nextFullXid;
+   TransactionId nextXid;
+   uint32      epoch;
+
+   Assert(TransactionIdIsValid(xid));
+
+   LWLockAcquire(XidGenLock, LW_SHARED);
+   nextFullXid = ShmemVariableCache->nextXid;
+   LWLockRelease(XidGenLock);
+
+   nextXid = XidFromFullTransactionId(nextFullXid);
+   epoch = EpochFromFullTransactionId(nextFullXid);
+   if (unlikely(xid > nextXid))
+   {
+       /* Wraparound occured, must be from a prev epoch. */
+       Assert(epoch > 0);
+       epoch--;
+   }
+
+   return FullTransactionIdFromEpochAndXid(epoch, xid);
+}
+
+static inline int
+TwoPhaseFilePath(char *path, TransactionId xid)
+{
+   FullTransactionId fxid = AdjustToFullTransactionId(xid);
+
+   return snprintf(path, MAXPGPATH, TWOPHASE_DIR "/%08X%08X",
+                   EpochFromFullTransactionId(fxid),
+                   XidFromFullTransactionId(fxid));
+}
 
 /*
  * 2PC state file format:
@@ -1882,13 +1920,15 @@ restoreTwoPhaseData(void)
    cldir = AllocateDir(TWOPHASE_DIR);
    while ((clde = ReadDir(cldir, TWOPHASE_DIR)) != NULL)
    {
-       if (strlen(clde->d_name) == 8 &&
-           strspn(clde->d_name, "0123456789ABCDEF") == 8)
+       if (strlen(clde->d_name) == 16 &&
+           strspn(clde->d_name, "0123456789ABCDEF") == 16)
        {
            TransactionId xid;
+           FullTransactionId fxid;
            char       *buf;
 
-           xid = (TransactionId) strtoul(clde->d_name, NULL, 16);
+           fxid = FullTransactionIdFromU64(strtou64(clde->d_name, NULL, 16));
+           xid = XidFromFullTransactionId(fxid);
 
            buf = ProcessTwoPhaseBuffer(xid, InvalidXLogRecPtr,
                                        true, false, false);