diff options
Diffstat (limited to 'src/backend/storage/lmgr/lock.c')
-rw-r--r-- | src/backend/storage/lmgr/lock.c | 154 |
1 files changed, 105 insertions, 49 deletions
diff --git a/src/backend/storage/lmgr/lock.c b/src/backend/storage/lmgr/lock.c index cfe3954637d..98fc02529e3 100644 --- a/src/backend/storage/lmgr/lock.c +++ b/src/backend/storage/lmgr/lock.c @@ -345,6 +345,7 @@ static void BeginStrongLockAcquire(LOCALLOCK *locallock, uint32 fasthashcode); static void FinishStrongLockAcquire(void); static void WaitOnLock(LOCALLOCK *locallock, ResourceOwner owner); static void ReleaseLockIfHeld(LOCALLOCK *locallock, bool sessionLock); +static void LockReassignOwner(LOCALLOCK *locallock, ResourceOwner parent); static bool UnGrantLock(LOCK *lock, LOCKMODE lockmode, PROCLOCK *proclock, LockMethod lockMethodTable); static void CleanUpLock(LOCK *lock, PROCLOCK *proclock, @@ -1098,8 +1099,16 @@ SetupLockInTable(LockMethod lockMethodTable, PGPROC *proc, static void RemoveLocalLock(LOCALLOCK *locallock) { + int i; + + for (i = locallock->numLockOwners - 1; i >= 0; i--) + { + if (locallock->lockOwners[i].owner != NULL) + ResourceOwnerForgetLock(locallock->lockOwners[i].owner, locallock); + } pfree(locallock->lockOwners); locallock->lockOwners = NULL; + if (locallock->holdsStrongLockCount) { uint32 fasthashcode; @@ -1112,6 +1121,7 @@ RemoveLocalLock(LOCALLOCK *locallock) locallock->holdsStrongLockCount = FALSE; SpinLockRelease(&FastPathStrongRelationLocks->mutex); } + if (!hash_search(LockMethodLocalHash, (void *) &(locallock->tag), HASH_REMOVE, NULL)) @@ -1355,6 +1365,8 @@ GrantLockLocal(LOCALLOCK *locallock, ResourceOwner owner) lockOwners[i].owner = owner; lockOwners[i].nLocks = 1; locallock->numLockOwners++; + if (owner != NULL) + ResourceOwnerRememberLock(owner, locallock); } /* @@ -1670,6 +1682,8 @@ LockRelease(const LOCKTAG *locktag, LOCKMODE lockmode, bool sessionLock) Assert(lockOwners[i].nLocks > 0); if (--lockOwners[i].nLocks == 0) { + if (owner != NULL) + ResourceOwnerForgetLock(owner, locallock); /* compact out unused slot */ locallock->numLockOwners--; if (i < locallock->numLockOwners) @@ -1862,14 +1876,13 @@ LockReleaseAll(LOCKMETHODID lockmethodid, bool allLocks) { LOCALLOCKOWNER *lockOwners = locallock->lockOwners; - /* If it's above array position 0, move it down to 0 */ - for (i = locallock->numLockOwners - 1; i > 0; i--) + /* If session lock is above array position 0, move it down to 0 */ + for (i = 0; i < locallock->numLockOwners ; i++) { if (lockOwners[i].owner == NULL) - { lockOwners[0] = lockOwners[i]; - break; - } + else + ResourceOwnerForgetLock(lockOwners[i].owner, locallock); } if (locallock->numLockOwners > 0 && @@ -1882,6 +1895,8 @@ LockReleaseAll(LOCKMETHODID lockmethodid, bool allLocks) /* We aren't deleting this locallock, so done */ continue; } + else + locallock->numLockOwners = 0; } /* @@ -2067,18 +2082,31 @@ LockReleaseSession(LOCKMETHODID lockmethodid) /* * LockReleaseCurrentOwner * Release all locks belonging to CurrentResourceOwner + * + * If the caller knows what those locks are, it can pass them as an array. + * That speeds up the call significantly, when a lot of locks are held. + * Otherwise, pass NULL for locallocks, and we'll traverse through our hash + * table to find them. */ void -LockReleaseCurrentOwner(void) +LockReleaseCurrentOwner(LOCALLOCK **locallocks, int nlocks) { - HASH_SEQ_STATUS status; - LOCALLOCK *locallock; + if (locallocks == NULL) + { + HASH_SEQ_STATUS status; + LOCALLOCK *locallock; - hash_seq_init(&status, LockMethodLocalHash); + hash_seq_init(&status, LockMethodLocalHash); - while ((locallock = (LOCALLOCK *) hash_seq_search(&status)) != NULL) + while ((locallock = (LOCALLOCK *) hash_seq_search(&status)) != NULL) + ReleaseLockIfHeld(locallock, false); + } + else { - ReleaseLockIfHeld(locallock, false); + int i; + + for (i = nlocks - 1; i >= 0; i--) + ReleaseLockIfHeld(locallocks[i], false); } } @@ -2124,6 +2152,8 @@ ReleaseLockIfHeld(LOCALLOCK *locallock, bool sessionLock) locallock->nLocks -= lockOwners[i].nLocks; /* compact out unused slot */ locallock->numLockOwners--; + if (owner != NULL) + ResourceOwnerForgetLock(owner, locallock); if (i < locallock->numLockOwners) lockOwners[i] = lockOwners[locallock->numLockOwners]; } @@ -2146,57 +2176,83 @@ ReleaseLockIfHeld(LOCALLOCK *locallock, bool sessionLock) /* * LockReassignCurrentOwner * Reassign all locks belonging to CurrentResourceOwner to belong - * to its parent resource owner + * to its parent resource owner. + * + * If the caller knows what those locks are, it can pass them as an array. + * That speeds up the call significantly, when a lot of locks are held + * (e.g pg_dump with a large schema). Otherwise, pass NULL for locallocks, + * and we'll traverse through our hash table to find them. */ void -LockReassignCurrentOwner(void) +LockReassignCurrentOwner(LOCALLOCK **locallocks, int nlocks) { ResourceOwner parent = ResourceOwnerGetParent(CurrentResourceOwner); - HASH_SEQ_STATUS status; - LOCALLOCK *locallock; - LOCALLOCKOWNER *lockOwners; Assert(parent != NULL); - hash_seq_init(&status, LockMethodLocalHash); + if (locallocks == NULL) + { + HASH_SEQ_STATUS status; + LOCALLOCK *locallock; - while ((locallock = (LOCALLOCK *) hash_seq_search(&status)) != NULL) + hash_seq_init(&status, LockMethodLocalHash); + + while ((locallock = (LOCALLOCK *) hash_seq_search(&status)) != NULL) + LockReassignOwner(locallock, parent); + } + else { - int i; - int ic = -1; - int ip = -1; + int i; - /* - * Scan to see if there are any locks belonging to current owner or - * its parent - */ - lockOwners = locallock->lockOwners; - for (i = locallock->numLockOwners - 1; i >= 0; i--) - { - if (lockOwners[i].owner == CurrentResourceOwner) - ic = i; - else if (lockOwners[i].owner == parent) - ip = i; - } + for (i = nlocks - 1; i >= 0; i--) + LockReassignOwner(locallocks[i], parent); + } +} - if (ic < 0) - continue; /* no current locks */ +/* + * Subroutine of LockReassignCurrentOwner. Reassigns a given lock belonging to + * CurrentResourceOwner to its parent. + */ +static void +LockReassignOwner(LOCALLOCK *locallock, ResourceOwner parent) +{ + LOCALLOCKOWNER *lockOwners; + int i; + int ic = -1; + int ip = -1; - if (ip < 0) - { - /* Parent has no slot, so just give it child's slot */ - lockOwners[ic].owner = parent; - } - else - { - /* Merge child's count with parent's */ - lockOwners[ip].nLocks += lockOwners[ic].nLocks; - /* compact out unused slot */ - locallock->numLockOwners--; - if (ic < locallock->numLockOwners) - lockOwners[ic] = lockOwners[locallock->numLockOwners]; - } + /* + * Scan to see if there are any locks belonging to current owner or + * its parent + */ + lockOwners = locallock->lockOwners; + for (i = locallock->numLockOwners - 1; i >= 0; i--) + { + if (lockOwners[i].owner == CurrentResourceOwner) + ic = i; + else if (lockOwners[i].owner == parent) + ip = i; + } + + if (ic < 0) + return; /* no current locks */ + + if (ip < 0) + { + /* Parent has no slot, so just give it the child's slot */ + lockOwners[ic].owner = parent; + ResourceOwnerRememberLock(parent, locallock); + } + else + { + /* Merge child's count with parent's */ + lockOwners[ip].nLocks += lockOwners[ic].nLocks; + /* compact out unused slot */ + locallock->numLockOwners--; + if (ic < locallock->numLockOwners) + lockOwners[ic] = lockOwners[locallock->numLockOwners]; } + ResourceOwnerForgetLock(CurrentResourceOwner, locallock); } /* |