aboutsummaryrefslogtreecommitdiff
path: root/src/backend/access/transam/twophase.c
diff options
context:
space:
mode:
authorHeikki Linnakangas <heikki.linnakangas@iki.fi>2009-11-23 09:58:36 +0000
committerHeikki Linnakangas <heikki.linnakangas@iki.fi>2009-11-23 09:58:36 +0000
commitcd87b6f8a5084c070c3e56b07794be8fea33647d (patch)
tree20c1c2d08a56147198288ea6845791a41e888c91 /src/backend/access/transam/twophase.c
parentc194ff20d2fa1541d62c366bb6a9000fb0d3b983 (diff)
downloadpostgresql-cd87b6f8a5084c070c3e56b07794be8fea33647d.tar.gz
postgresql-cd87b6f8a5084c070c3e56b07794be8fea33647d.zip
Fix an old bug in multixact and two-phase commit. Prepared transactions can
be part of multixacts, so allocate a slot for each prepared transaction in the "oldest member" array in multixact.c. On PREPARE TRANSACTION, transfer the oldest member value from the current backends slot to the prepared xact slot. Also save and recover the value from the 2pc state file. The symptom of the bug was that after a transaction prepared, a shared lock still held by the prepared transaction was sometimes ignored by other transactions. Fix back to 8.1, where both 2PC and multixact were introduced.
Diffstat (limited to 'src/backend/access/transam/twophase.c')
-rw-r--r--src/backend/access/transam/twophase.c33
1 files changed, 32 insertions, 1 deletions
diff --git a/src/backend/access/transam/twophase.c b/src/backend/access/transam/twophase.c
index 1548c89ca14..db5795324b2 100644
--- a/src/backend/access/transam/twophase.c
+++ b/src/backend/access/transam/twophase.c
@@ -7,7 +7,7 @@
* Portions Copyright (c) 1994, Regents of the University of California
*
* IDENTIFICATION
- * $PostgreSQL: pgsql/src/backend/access/transam/twophase.c,v 1.55 2009/09/01 04:15:45 tgl Exp $
+ * $PostgreSQL: pgsql/src/backend/access/transam/twophase.c,v 1.56 2009/11/23 09:58:36 heikki Exp $
*
* NOTES
* Each global transaction is associated with a global transaction
@@ -109,6 +109,7 @@ int max_prepared_xacts = 0;
typedef struct GlobalTransactionData
{
PGPROC proc; /* dummy proc */
+ BackendId dummyBackendId; /* similar to backend id for backends */
TimestampTz prepared_at; /* time of preparation */
XLogRecPtr prepare_lsn; /* XLOG offset of prepare record */
Oid owner; /* ID of user that executed the xact */
@@ -200,6 +201,20 @@ TwoPhaseShmemInit(void)
{
gxacts[i].proc.links.next = (SHM_QUEUE *) TwoPhaseState->freeGXacts;
TwoPhaseState->freeGXacts = &gxacts[i];
+
+ /*
+ * Assign a unique ID for each dummy proc, so that the range of
+ * dummy backend IDs immediately follows the range of normal
+ * backend IDs. We don't dare to assign a real backend ID to
+ * dummy procs, because prepared transactions don't take part in
+ * cache invalidation like a real backend ID would imply, but
+ * having a unique ID for them is nevertheless handy. This
+ * arrangement allows you to allocate an array of size
+ * (MaxBackends + max_prepared_xacts + 1), and have a slot for
+ * every backend and prepared transaction. Currently multixact.c
+ * uses that technique.
+ */
+ gxacts[i].dummyBackendId = MaxBackends + 1 + i;
}
}
else
@@ -649,6 +664,22 @@ pg_prepared_xact(PG_FUNCTION_ARGS)
/*
* TwoPhaseGetDummyProc
+ * Get the dummy backend ID for prepared transaction specified by XID
+ *
+ * Dummy backend IDs are similar to real backend IDs of real backends.
+ * They start at MaxBackends + 1, and are unique across all currently active
+ * real backends and prepared transactions.
+ */
+BackendId
+TwoPhaseGetDummyBackendId(TransactionId xid)
+{
+ PGPROC *proc = TwoPhaseGetDummyProc(xid);
+
+ return ((GlobalTransaction) proc)->dummyBackendId;
+}
+
+/*
+ * TwoPhaseGetDummyProc
* Get the PGPROC that represents a prepared transaction specified by XID
*/
PGPROC *