First cut at being able to use shutdown checkpoints as valid starting places for...
authorSimon Riggs <simon@2ndQuadrant.com>
Fri, 2 Oct 2009 19:57:01 +0000 (20:57 +0100)
committerSimon Riggs <simon@2ndQuadrant.com>
Fri, 2 Oct 2009 19:57:01 +0000 (20:57 +0100)
src/backend/access/transam/twophase.c
src/backend/access/transam/xlog.c
src/backend/storage/ipc/procarray.c
src/include/access/twophase.h
src/include/storage/procarray.h

index 54c9ff4006bf8df9de8de6ecb66002ecf448c41d..e753c1124130d820e91ab12469629342942e95ab 100644 (file)
@@ -1592,6 +1592,62 @@ PrescanPreparedTransactions(void)
        return result;
 }
 
+/*
+ * Check all prepared transaction files are valid, or remove them
+ * 
+ * Report whether we found any still valid.
+ */
+bool
+ValidatePreparedTransactions(void)
+{
+       DIR                *cldir;
+       struct dirent *clde;
+       bool            found = false;
+
+       cldir = AllocateDir(TWOPHASE_DIR);
+       while ((clde = ReadDir(cldir, TWOPHASE_DIR)) != NULL)
+       {
+               if (strlen(clde->d_name) == 8 &&
+                       strspn(clde->d_name, "0123456789ABCDEF") == 8)
+               {
+                       TransactionId xid;
+                       char       *buf;
+                       TwoPhaseFileHeader *hdr;
+
+                       xid = (TransactionId) strtoul(clde->d_name, NULL, 16);
+
+                       /* Read and validate file */
+                       buf = ReadTwoPhaseFile(xid);
+                       if (buf == NULL)
+                       {
+                               ereport(WARNING,
+                                         (errmsg("removing corrupt two-phase state file \"%s\"",
+                                                         clde->d_name)));
+                               RemoveTwoPhaseFile(xid, true);
+                               continue;
+                       }
+
+                       /* Deconstruct header */
+                       hdr = (TwoPhaseFileHeader *) buf;
+                       if (!TransactionIdEquals(hdr->xid, xid))
+                       {
+                               ereport(WARNING,
+                                         (errmsg("removing corrupt two-phase state file \"%s\"",
+                                                         clde->d_name)));
+                               RemoveTwoPhaseFile(xid, true);
+                               pfree(buf);
+                               continue;
+                       }
+
+                       pfree(buf);
+                       found = true;
+               }
+       }
+       FreeDir(cldir);
+
+       return found;
+}
+
 /*
  * RecoverPreparedTransactions
  *
index 5dac9c768301b871d573f68a3eb1c2886f99954b..a2be37f59b53e420d71cb1d8d97a8595c777d46b 100644 (file)
@@ -6214,6 +6214,7 @@ StartupXLOG(void)
        if (InRecovery)
        {
                int                     rmid;
+               bool            validPreparedTransactionsExist;
 
                /*
                 * Update pg_control to show that we are recovering and to show the
@@ -6272,11 +6273,19 @@ StartupXLOG(void)
                                                                BACKUP_LABEL_FILE, BACKUP_LABEL_OLD)));
                }
 
+               /*
+                * Remove invalid prepared transactions and see if any valid ones
+                * remain to be processed.
+                */
+               validPreparedTransactionsExist = ValidatePreparedTransactions();
+
                /* Initialize recovery connections, if enabled */               
                if (InHotStandby)
                {
                        CheckMaxConnections(checkPoint.MaxConnections);
                        InitRecoveryTransactionEnvironment();
+                       if (wasShutdown && !validPreparedTransactionsExist)
+                               ProcArrayInitRecoveryInfo();
                        StartCleanupDelayStats();
                        if (recoveryStartsPaused)
                                SetRecoveryTargetMode(RECOVERY_TARGET_PAUSE_ALL,
index 4cb0bc9a2cb18e797c0cf9a28626c5a182d36702..0145ab644861301332c788e4e3b76a373be8e4c7 100644 (file)
@@ -569,6 +569,33 @@ ProcArrayApplyRecoveryInfo(XLogRecPtr lsn, xl_xact_running_xacts *xlrec)
                        "recovery snapshots are now enabled");
 }
 
+/*
+ * ProcArrayInitRecoveryInfo -- init recovery info about xids and locks
+ *
+ * Only used during recovery when we start from a shutdown checkpoint.
+ */
+void
+ProcArrayInitRecoveryInfo(void)
+{
+       Assert(InHotStandby);
+
+       /*
+        * OK, we need to initialise from the RunningXactData record
+        */
+       initRunningXactData = true;
+       recoverySnapshotValid = true;
+
+       /* also initialize latestCompletedXid, to nextXid - 1 */
+       ShmemVariableCache->latestCompletedXid = ShmemVariableCache->nextXid;
+       TransactionIdRetreat(ShmemVariableCache->latestCompletedXid);
+       latestObservedXid = ShmemVariableCache->latestCompletedXid;
+
+       elog(trace_recovery(DEBUG2), 
+               "running transaction data initialized");
+       elog(trace_recovery(DEBUG2), 
+               "recovery snapshots are now enabled");
+}
+
 /*
  * Is the data available to allow valid snapshots?
  */
index d09eb24c8aa04695ed0b2f48afa901d9206d4563..400e8c67981d1b26d6550773bb4b90021f21f5ee 100644 (file)
@@ -40,6 +40,7 @@ extern void StartPrepare(GlobalTransaction gxact);
 extern void EndPrepare(GlobalTransaction gxact);
 
 extern TransactionId PrescanPreparedTransactions(void);
+extern bool ValidatePreparedTransactions(void);
 extern void RecoverPreparedTransactions(void);
 
 extern void ProcessTwoPhaseStandbyRecords(TransactionId xid);
index 302090398ec6746df589f68135f74ca5a97a7020..fe4684e0726bd438e71373ddbcb9703a90fb3c29 100644 (file)
@@ -27,6 +27,7 @@ extern void ProcArrayRemove(PGPROC *proc, TransactionId latestXid);
 extern void ProcArrayEndTransaction(PGPROC *proc, TransactionId latestXid);
 extern void ProcArrayClearTransaction(PGPROC *proc);
 extern void ProcArrayApplyRecoveryInfo(XLogRecPtr lsn, xl_xact_running_xacts *xlrec);
+extern void ProcArrayInitRecoveryInfo(void);
 
 extern void RecordKnownAssignedTransactionIds(TransactionId xid);
 extern void ExpireTreeKnownAssignedTransactionIds(TransactionId xid,