diff options
Diffstat (limited to 'src/backend/storage/lmgr')
| -rw-r--r-- | src/backend/storage/lmgr/lmgr.c | 77 | ||||
| -rw-r--r-- | src/backend/storage/lmgr/lock.c | 66 | ||||
| -rw-r--r-- | src/backend/storage/lmgr/proc.c | 12 |
3 files changed, 127 insertions, 28 deletions
diff --git a/src/backend/storage/lmgr/lmgr.c b/src/backend/storage/lmgr/lmgr.c index 1c5db36320..f947d226fe 100644 --- a/src/backend/storage/lmgr/lmgr.c +++ b/src/backend/storage/lmgr/lmgr.c @@ -8,7 +8,7 @@ * * * IDENTIFICATION - * $PostgreSQL: pgsql/src/backend/storage/lmgr/lmgr.c,v 1.92 2007/07/25 22:16:18 tgl Exp $ + * $PostgreSQL: pgsql/src/backend/storage/lmgr/lmgr.c,v 1.93 2007/09/05 18:10:47 tgl Exp $ * *------------------------------------------------------------------------- */ @@ -421,8 +421,8 @@ UnlockTuple(Relation relation, ItemPointer tid, LOCKMODE lockmode) * XactLockTableInsert * * Insert a lock showing that the given transaction ID is running --- - * this is done during xact startup. The lock can then be used to wait - * for the transaction to finish. + * this is done when an XID is acquired by a transaction or subtransaction. + * The lock can then be used to wait for the transaction to finish. */ void XactLockTableInsert(TransactionId xid) @@ -439,8 +439,7 @@ XactLockTableInsert(TransactionId xid) * * Delete the lock showing that the given transaction ID is running. * (This is never used for main transaction IDs; those locks are only - * released implicitly at transaction end. But we do use it for subtrans - * IDs.) + * released implicitly at transaction end. But we do use it for subtrans IDs.) */ void XactLockTableDelete(TransactionId xid) @@ -472,7 +471,7 @@ XactLockTableWait(TransactionId xid) for (;;) { Assert(TransactionIdIsValid(xid)); - Assert(!TransactionIdEquals(xid, GetTopTransactionId())); + Assert(!TransactionIdEquals(xid, GetTopTransactionIdIfAny())); SET_LOCKTAG_TRANSACTION(tag, xid); @@ -500,7 +499,7 @@ ConditionalXactLockTableWait(TransactionId xid) for (;;) { Assert(TransactionIdIsValid(xid)); - Assert(!TransactionIdEquals(xid, GetTopTransactionId())); + Assert(!TransactionIdEquals(xid, GetTopTransactionIdIfAny())); SET_LOCKTAG_TRANSACTION(tag, xid); @@ -517,6 +516,70 @@ ConditionalXactLockTableWait(TransactionId xid) return true; } + +/* + * VirtualXactLockTableInsert + * + * Insert a lock showing that the given virtual transaction ID is running --- + * this is done at main transaction start when its VXID is assigned. + * The lock can then be used to wait for the transaction to finish. + */ +void +VirtualXactLockTableInsert(VirtualTransactionId vxid) +{ + LOCKTAG tag; + + Assert(VirtualTransactionIdIsValid(vxid)); + + SET_LOCKTAG_VIRTUALTRANSACTION(tag, vxid); + + (void) LockAcquire(&tag, ExclusiveLock, false, false); +} + +/* + * VirtualXactLockTableWait + * + * Waits until the lock on the given VXID is released, which shows that + * the top-level transaction owning the VXID has ended. + */ +void +VirtualXactLockTableWait(VirtualTransactionId vxid) +{ + LOCKTAG tag; + + Assert(VirtualTransactionIdIsValid(vxid)); + + SET_LOCKTAG_VIRTUALTRANSACTION(tag, vxid); + + (void) LockAcquire(&tag, ShareLock, false, false); + + LockRelease(&tag, ShareLock, false); +} + +/* + * ConditionalVirtualXactLockTableWait + * + * As above, but only lock if we can get the lock without blocking. + * Returns TRUE if the lock was acquired. + */ +bool +ConditionalVirtualXactLockTableWait(VirtualTransactionId vxid) +{ + LOCKTAG tag; + + Assert(VirtualTransactionIdIsValid(vxid)); + + SET_LOCKTAG_VIRTUALTRANSACTION(tag, vxid); + + if (LockAcquire(&tag, ShareLock, false, true) == LOCKACQUIRE_NOT_AVAIL) + return false; + + LockRelease(&tag, ShareLock, false); + + return true; +} + + /* * LockDatabaseObject * 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); diff --git a/src/backend/storage/lmgr/proc.c b/src/backend/storage/lmgr/proc.c index 048fa31bcc..5441dd322d 100644 --- a/src/backend/storage/lmgr/proc.c +++ b/src/backend/storage/lmgr/proc.c @@ -8,7 +8,7 @@ * * * IDENTIFICATION - * $PostgreSQL: pgsql/src/backend/storage/lmgr/proc.c,v 1.192 2007/08/28 03:23:44 tgl Exp $ + * $PostgreSQL: pgsql/src/backend/storage/lmgr/proc.c,v 1.193 2007/09/05 18:10:47 tgl Exp $ * *------------------------------------------------------------------------- */ @@ -282,10 +282,12 @@ InitProcess(void) */ SHMQueueElemInit(&(MyProc->links)); MyProc->waitStatus = STATUS_OK; + MyProc->lxid = InvalidLocalTransactionId; MyProc->xid = InvalidTransactionId; MyProc->xmin = InvalidTransactionId; MyProc->pid = MyProcPid; - /* databaseId and roleId will be filled in later */ + /* backendId, databaseId and roleId will be filled in later */ + MyProc->backendId = InvalidBackendId; MyProc->databaseId = InvalidOid; MyProc->roleId = InvalidOid; MyProc->inCommit = false; @@ -359,7 +361,9 @@ InitProcessPhase2(void) * * Auxiliary processes are presently not expected to wait for real (lockmgr) * locks, so we need not set up the deadlock checker. They are never added - * to the ProcArray or the sinval messaging mechanism, either. + * to the ProcArray or the sinval messaging mechanism, either. They also + * don't get a VXID assigned, since this is only useful when we actually + * hold lockmgr locks. */ void InitAuxiliaryProcess(void) @@ -418,8 +422,10 @@ InitAuxiliaryProcess(void) */ SHMQueueElemInit(&(MyProc->links)); MyProc->waitStatus = STATUS_OK; + MyProc->lxid = InvalidLocalTransactionId; MyProc->xid = InvalidTransactionId; MyProc->xmin = InvalidTransactionId; + MyProc->backendId = InvalidBackendId; MyProc->databaseId = InvalidOid; MyProc->roleId = InvalidOid; MyProc->inCommit = false; |
