1
0
mirror of https://github.com/postgres/postgres.git synced 2025-11-15 03:41:20 +03:00

Rework subtransaction commit protocol for hot standby.

This patch eliminates the marking of subtransactions as SUBCOMMITTED in pg_clog
during their commit; instead they remain in-progress until main transaction
commit.  At main transaction commit, the commit protocol is atomic-by-page
instead of one transaction at a time.  To avoid a race condition with some
subtransactions appearing committed before others in the case where they span
more than one pg_clog page, we conserve the logic that marks them subcommitted
before marking the parent committed.

Simon Riggs with minor help from me
This commit is contained in:
Alvaro Herrera
2008-10-20 19:18:18 +00:00
parent 3afffbc902
commit 06da3c570f
7 changed files with 279 additions and 212 deletions

View File

@@ -10,7 +10,7 @@
*
*
* IDENTIFICATION
* $PostgreSQL: pgsql/src/backend/access/transam/xact.c,v 1.265 2008/08/11 11:05:10 heikki Exp $
* $PostgreSQL: pgsql/src/backend/access/transam/xact.c,v 1.266 2008/10/20 19:18:18 alvherre Exp $
*
*-------------------------------------------------------------------------
*/
@@ -254,7 +254,6 @@ static void CommitTransaction(void);
static TransactionId RecordTransactionAbort(bool isSubXact);
static void StartTransaction(void);
static void RecordSubTransactionCommit(void);
static void StartSubTransaction(void);
static void CommitSubTransaction(void);
static void AbortSubTransaction(void);
@@ -952,11 +951,7 @@ RecordTransactionCommit(void)
* Now we may update the CLOG, if we wrote a COMMIT record above
*/
if (markXidCommitted)
{
TransactionIdCommit(xid);
/* to avoid race conditions, the parent must commit first */
TransactionIdCommitTree(nchildren, children);
}
TransactionIdCommitTree(xid, nchildren, children);
}
else
{
@@ -974,11 +969,7 @@ RecordTransactionCommit(void)
* flushed before the CLOG may be updated.
*/
if (markXidCommitted)
{
TransactionIdAsyncCommit(xid, XactLastRecEnd);
/* to avoid race conditions, the parent must commit first */
TransactionIdAsyncCommitTree(nchildren, children, XactLastRecEnd);
}
TransactionIdAsyncCommitTree(xid, nchildren, children, XactLastRecEnd);
}
/*
@@ -1156,36 +1147,6 @@ AtSubCommit_childXids(void)
s->maxChildXids = 0;
}
/*
* RecordSubTransactionCommit
*/
static void
RecordSubTransactionCommit(void)
{
TransactionId xid = GetCurrentTransactionIdIfAny();
/*
* We do not log the subcommit in XLOG; it doesn't matter until the
* top-level transaction commits.
*
* We must mark the subtransaction subcommitted in the CLOG if it had a
* valid XID assigned. If it did not, nobody else will ever know about
* the existence of this subxact. We don't have to deal with deletions
* scheduled for on-commit here, since they'll be reassigned to our parent
* (who might still abort).
*/
if (TransactionIdIsValid(xid))
{
/* XXX does this really need to be a critical section? */
START_CRIT_SECTION();
/* Record subtransaction subcommit */
TransactionIdSubCommit(xid);
END_CRIT_SECTION();
}
}
/* ----------------------------------------------------------------
* AbortTransaction stuff
* ----------------------------------------------------------------
@@ -1288,14 +1249,8 @@ RecordTransactionAbort(bool isSubXact)
* waiting for already-aborted subtransactions. It is OK to do it without
* having flushed the ABORT record to disk, because in event of a crash
* we'd be assumed to have aborted anyway.
*
* The ordering here isn't critical but it seems best to mark the parent
* first. This assures an atomic transition of all the subtransactions to
* aborted state from the point of view of concurrent
* TransactionIdDidAbort calls.
*/
TransactionIdAbort(xid);
TransactionIdAbortTree(nchildren, children);
TransactionIdAbortTree(xid, nchildren, children);
END_CRIT_SECTION();
@@ -3791,8 +3746,11 @@ CommitSubTransaction(void)
/* Must CCI to ensure commands of subtransaction are seen as done */
CommandCounterIncrement();
/* Mark subtransaction as subcommitted */
RecordSubTransactionCommit();
/*
* Prior to 8.4 we marked subcommit in clog at this point. We now only
* perform that step, if required, as part of the atomic update of the
* whole transaction tree at top level commit or abort.
*/
/* Post-commit cleanup */
if (TransactionIdIsValid(s->transactionId))
@@ -4259,11 +4217,9 @@ xact_redo_commit(xl_xact_commit *xlrec, TransactionId xid)
TransactionId max_xid;
int i;
TransactionIdCommit(xid);
/* Mark committed subtransactions as committed */
/* Mark the transaction committed in pg_clog */
sub_xids = (TransactionId *) &(xlrec->xnodes[xlrec->nrels]);
TransactionIdCommitTree(xlrec->nsubxacts, sub_xids);
TransactionIdCommitTree(xid, xlrec->nsubxacts, sub_xids);
/* Make sure nextXid is beyond any XID mentioned in the record */
max_xid = xid;
@@ -4299,11 +4255,9 @@ xact_redo_abort(xl_xact_abort *xlrec, TransactionId xid)
TransactionId max_xid;
int i;
TransactionIdAbort(xid);
/* Mark subtransactions as aborted */
/* Mark the transaction aborted in pg_clog */
sub_xids = (TransactionId *) &(xlrec->xnodes[xlrec->nrels]);
TransactionIdAbortTree(xlrec->nsubxacts, sub_xids);
TransactionIdAbortTree(xid, xlrec->nsubxacts, sub_xids);
/* Make sure nextXid is beyond any XID mentioned in the record */
max_xid = xid;