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
*
if (InRecovery)
{
int rmid;
+ bool validPreparedTransactionsExist;
/*
* Update pg_control to show that we are recovering and to show the
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,
"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?
*/
extern void EndPrepare(GlobalTransaction gxact);
extern TransactionId PrescanPreparedTransactions(void);
+extern bool ValidatePreparedTransactions(void);
extern void RecoverPreparedTransactions(void);
extern void ProcessTwoPhaseStandbyRecords(TransactionId xid);
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,