diff options
Diffstat (limited to 'src/backend/storage/lmgr/lock.c')
| -rw-r--r-- | src/backend/storage/lmgr/lock.c | 66 |
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); |
