summaryrefslogtreecommitdiff
path: root/src/backend/storage/lmgr/lock.c
diff options
context:
space:
mode:
Diffstat (limited to 'src/backend/storage/lmgr/lock.c')
-rw-r--r--src/backend/storage/lmgr/lock.c66
1 files changed, 48 insertions, 18 deletions
diff --git a/src/backend/storage/lmgr/lock.c b/src/backend/storage/lmgr/lock.c
index a4a0910d39..06a4f7adae 100644
--- a/src/backend/storage/lmgr/lock.c
+++ b/src/backend/storage/lmgr/lock.c
@@ -8,7 +8,7 @@
*
*
* IDENTIFICATION
- * $PostgreSQL: pgsql/src/backend/storage/lmgr/lock.c,v 1.177 2007/07/16 21:09:50 tgl Exp $
+ * $PostgreSQL: pgsql/src/backend/storage/lmgr/lock.c,v 1.178 2007/09/05 18:10:47 tgl Exp $
*
* NOTES
* A lock table is a shared memory hash table. When
@@ -1681,20 +1681,24 @@ LockReassignCurrentOwner(void)
/*
* GetLockConflicts
- * Get a list of TransactionIds of xacts currently holding locks
+ * Get an array of VirtualTransactionIds of xacts currently holding locks
* that would conflict with the specified lock/lockmode.
* xacts merely awaiting such a lock are NOT reported.
*
+ * The result array is palloc'd and is terminated with an invalid VXID.
+ *
* Of course, the result could be out of date by the time it's returned,
* so use of this function has to be thought about carefully.
*
- * Only top-level XIDs are reported. Note we never include the current xact
- * in the result list, since an xact never blocks itself.
+ * Note we never include the current xact's vxid in the result array,
+ * since an xact never blocks itself. Also, prepared transactions are
+ * ignored, which is a bit more debatable but is appropriate for current
+ * uses of the result.
*/
-List *
+VirtualTransactionId *
GetLockConflicts(const LOCKTAG *locktag, LOCKMODE lockmode)
{
- List *result = NIL;
+ VirtualTransactionId *vxids;
LOCKMETHODID lockmethodid = locktag->locktag_lockmethodid;
LockMethod lockMethodTable;
LOCK *lock;
@@ -1703,6 +1707,7 @@ GetLockConflicts(const LOCKTAG *locktag, LOCKMODE lockmode)
PROCLOCK *proclock;
uint32 hashcode;
LWLockId partitionLock;
+ int count = 0;
if (lockmethodid <= 0 || lockmethodid >= lengthof(LockMethods))
elog(ERROR, "unrecognized lock method: %d", lockmethodid);
@@ -1711,6 +1716,14 @@ GetLockConflicts(const LOCKTAG *locktag, LOCKMODE lockmode)
elog(ERROR, "unrecognized lock mode: %d", lockmode);
/*
+ * Allocate memory to store results, and fill with InvalidVXID. We
+ * only need enough space for MaxBackends + a terminator, since
+ * prepared xacts don't count.
+ */
+ vxids = (VirtualTransactionId *)
+ palloc0(sizeof(VirtualTransactionId) * (MaxBackends + 1));
+
+ /*
* Look up the lock object matching the tag.
*/
hashcode = LockTagHashCode(locktag);
@@ -1730,7 +1743,7 @@ GetLockConflicts(const LOCKTAG *locktag, LOCKMODE lockmode)
* on this lockable object.
*/
LWLockRelease(partitionLock);
- return NIL;
+ return vxids;
}
/*
@@ -1752,18 +1765,17 @@ GetLockConflicts(const LOCKTAG *locktag, LOCKMODE lockmode)
/* A backend never blocks itself */
if (proc != MyProc)
{
- /* Fetch xid just once - see GetNewTransactionId */
- TransactionId xid = proc->xid;
+ VirtualTransactionId vxid;
+
+ GET_VXID_FROM_PGPROC(vxid, *proc);
/*
- * Race condition: during xact commit/abort we zero out
- * PGPROC's xid before we mark its locks released. If we see
- * zero in the xid field, assume the xact is in process of
- * shutting down and act as though the lock is already
- * released.
+ * If we see an invalid VXID, then either the xact has already
+ * committed (or aborted), or it's a prepared xact. In
+ * either case we may ignore it.
*/
- if (TransactionIdIsValid(xid))
- result = lappend_xid(result, xid);
+ if (VirtualTransactionIdIsValid(vxid))
+ vxids[count++] = vxid;
}
}
@@ -1773,7 +1785,10 @@ GetLockConflicts(const LOCKTAG *locktag, LOCKMODE lockmode)
LWLockRelease(partitionLock);
- return result;
+ if (count > MaxBackends) /* should never happen */
+ elog(PANIC, "too many conflicting locks found");
+
+ return vxids;
}
@@ -1782,7 +1797,7 @@ GetLockConflicts(const LOCKTAG *locktag, LOCKMODE lockmode)
* Do the preparatory work for a PREPARE: make 2PC state file records
* for all locks currently held.
*
- * Non-transactional locks are ignored.
+ * Non-transactional locks are ignored, as are VXID locks.
*
* There are some special cases that we error out on: we can't be holding
* any session locks (should be OK since only VACUUM uses those) and we
@@ -1812,6 +1827,13 @@ AtPrepare_Locks(void)
if (!LockMethods[LOCALLOCK_LOCKMETHOD(*locallock)]->transactional)
continue;
+ /*
+ * Ignore VXID locks. We don't want those to be held by prepared
+ * transactions, since they aren't meaningful after a restart.
+ */
+ if (locallock->tag.lock.locktag_type == LOCKTAG_VIRTUALTRANSACTION)
+ continue;
+
/* Ignore it if we don't actually hold the lock */
if (locallock->nLocks <= 0)
continue;
@@ -1899,6 +1921,10 @@ PostPrepare_Locks(TransactionId xid)
if (!LockMethods[LOCALLOCK_LOCKMETHOD(*locallock)]->transactional)
continue;
+ /* Ignore VXID locks */
+ if (locallock->tag.lock.locktag_type == LOCKTAG_VIRTUALTRANSACTION)
+ continue;
+
/* We already checked there are no session locks */
/* Mark the proclock to show we need to release this lockmode */
@@ -1944,6 +1970,10 @@ PostPrepare_Locks(TransactionId xid)
if (!LockMethods[LOCK_LOCKMETHOD(*lock)]->transactional)
goto next_item;
+ /* Ignore VXID locks */
+ if (lock->tag.locktag_type == LOCKTAG_VIRTUALTRANSACTION)
+ goto next_item;
+
PROCLOCK_PRINT("PostPrepare_Locks", proclock);
LOCK_PRINT("PostPrepare_Locks", lock, 0);
Assert(lock->nRequested >= 0);