{
TransactionId xid;
PGPROC *proc = NULL;
- bool unobserved = false;
bool mark_subtrans = false;
Xid_to_Proc *hentry;
bool found = false;
elog(trace_recovery(DEBUG4),
"record known xact top_xid %u child_xid %u %s%slatestObservedXid %u",
top_xid, child_xid,
- (unobserved ? "unobserved " : " "),
+ (found ? "new top_xid " : " "),
(mark_subtrans ? "mark subtrans " : " "),
latestObservedXid);
return true;
}
+static void
+RecordKnownAssignedSubTransactionIds(int nsubxacts, TransactionId *sub_xids)
+{
+ int i;
+
+ /*
+ * We may receive a completion record that contains unrecorded
+ * xids, so sometimes we must do further processing to ensure we
+ * get the xid arrival sequence exactly correct. We assume that
+ * xids are already in modulo ascending order. The code is
+ * deliberately similar to how topxid and childxid are handled in
+ * RecordKnownAssignedTransactionIds().
+ */
+ for (i = 0; i < nsubxacts; i++)
+ {
+ TransactionId next_expected_xid = latestObservedXid;
+ TransactionId subxid = sub_xids[i];
+ TransactionIdAdvance(next_expected_xid);
+
+ if (next_expected_xid == subxid)
+ {
+ Assert(!XidInUnobservedTransactions(subxid));
+ latestObservedXid = subxid;
+ }
+ else if (TransactionIdPrecedes(next_expected_xid, subxid))
+ {
+ UnobservedTransactionsAddXids(next_expected_xid, subxid);
+ latestObservedXid = subxid;
+ }
+ else
+ elog(FATAL, "transaction ids not in sequence");
+ }
+}
+
/*
* LatestRemovedXidAdvances - returns true if latestRemovedXid is moved
* forwards by the latest provided value
max_xid = TransactionIdLatest(xid, xlrec->nsubxacts, sub_xids);
+ if (TransactionIdPrecedes(latestObservedXid, max_xid))
+ RecordKnownAssignedSubTransactionIds(xlrec->nsubxacts, sub_xids);
+
/* Mark the transaction committed in pg_clog */
TransactionIdCommitTree(xid, xlrec->nsubxacts, sub_xids);
sub_xids = (TransactionId *) &(xlrec->xnodes[xlrec->nrels]);
max_xid = TransactionIdLatest(xid, xlrec->nsubxacts, sub_xids);
+ if (TransactionIdPrecedes(latestObservedXid, max_xid))
+ RecordKnownAssignedSubTransactionIds(xlrec->nsubxacts, sub_xids);
+
/* Mark the transaction aborted in pg_clog */
TransactionIdAbortTree(xid, xlrec->nsubxacts, sub_xids);
{
Xid_to_Proc *hentry = (Xid_to_Proc *)
hash_search(local_recovery_xid_to_proc_hash,
- (void *) &xid,
+ (void *) &topxid,
HASH_REMOVE, NULL);
Assert(hentry->proc != NULL);
{
xl_xact_commit_prepared *xlrec = (xl_xact_commit_prepared *) rec;
- appendStringInfo(buf, "commit %u: ", xlrec->xid);
+ appendStringInfo(buf, "commit prepared %u: ", xlrec->xid);
xact_desc_commit(buf, &xlrec->crec);
}
else if (info == XLOG_XACT_ABORT_PREPARED)
{
xl_xact_abort_prepared *xlrec = (xl_xact_abort_prepared *) rec;
- appendStringInfo(buf, "abort %u: ", xlrec->xid);
+ appendStringInfo(buf, "abort prepared %u: ", xlrec->xid);
xact_desc_abort(buf, &xlrec->arec);
}
else if (info == XLOG_XACT_ASSIGNMENT)