Assert that we don't acquire a heavyweight lock on another object after
relation extension lock. The only exception to the rule is that we can try to acquire the same relation extension lock more than once. This is allowed as we are not creating any new lock for this case. This restriction implies that the relation extension lock won't ever participate in the deadlock cycle because we can never wait for any other heavyweight lock after acquiring this lock. Such a restriction is okay for relation extension locks as unlike other heavyweight locks these are not held till the transaction end. These are taken for a short duration to extend a particular relation and then released. Author: Dilip Kumar, with few changes by Amit Kapila Reviewed-by: Amit Kapila, Kuntal Ghosh and Sawada Masahiko Discussion: https://postgr.es/m/CAD21AoCmT3cFQUN4aVvzy5chw7DuzXrJCbrjTU05B+Ss=Gn1LA@mail.gmail.com
This commit is contained in:
parent
b897b3aae6
commit
15ef6ff4b9
@ -170,6 +170,21 @@ typedef struct TwoPhaseLockRecord
|
|||||||
*/
|
*/
|
||||||
static int FastPathLocalUseCount = 0;
|
static int FastPathLocalUseCount = 0;
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Flag to indicate if the relation extension lock is held by this backend.
|
||||||
|
* This flag is used to ensure that while holding the relation extension lock
|
||||||
|
* we don't try to acquire a heavyweight lock on any other object. This
|
||||||
|
* restriction implies that the relation extension lock won't ever participate
|
||||||
|
* in the deadlock cycle because we can never wait for any other heavyweight
|
||||||
|
* lock after acquiring this lock.
|
||||||
|
*
|
||||||
|
* Such a restriction is okay for relation extension locks as unlike other
|
||||||
|
* heavyweight locks these are not held till the transaction end. These are
|
||||||
|
* taken for a short duration to extend a particular relation and then
|
||||||
|
* released.
|
||||||
|
*/
|
||||||
|
static bool IsRelationExtensionLockHeld PG_USED_FOR_ASSERTS_ONLY = false;
|
||||||
|
|
||||||
/* Macros for manipulating proc->fpLockBits */
|
/* Macros for manipulating proc->fpLockBits */
|
||||||
#define FAST_PATH_BITS_PER_SLOT 3
|
#define FAST_PATH_BITS_PER_SLOT 3
|
||||||
#define FAST_PATH_LOCKNUMBER_OFFSET 1
|
#define FAST_PATH_LOCKNUMBER_OFFSET 1
|
||||||
@ -840,6 +855,13 @@ LockAcquireExtended(const LOCKTAG *locktag,
|
|||||||
return LOCKACQUIRE_ALREADY_HELD;
|
return LOCKACQUIRE_ALREADY_HELD;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
* We don't acquire any other heavyweight lock while holding the relation
|
||||||
|
* extension lock. We do allow to acquire the same relation extension
|
||||||
|
* lock more than once but that case won't reach here.
|
||||||
|
*/
|
||||||
|
Assert(!IsRelationExtensionLockHeld);
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* Prepare to emit a WAL record if acquisition of this lock needs to be
|
* Prepare to emit a WAL record if acquisition of this lock needs to be
|
||||||
* replayed in a standby server.
|
* replayed in a standby server.
|
||||||
@ -1287,6 +1309,23 @@ SetupLockInTable(LockMethod lockMethodTable, PGPROC *proc,
|
|||||||
return proclock;
|
return proclock;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Check and set/reset the flag that we hold the relation extension lock.
|
||||||
|
*
|
||||||
|
* It is callers responsibility that this function is called after
|
||||||
|
* acquiring/releasing the relation extension lock.
|
||||||
|
*
|
||||||
|
* Pass acquired as true if lock is acquired, false otherwise.
|
||||||
|
*/
|
||||||
|
static inline void
|
||||||
|
CheckAndSetLockHeld(LOCALLOCK *locallock, bool acquired)
|
||||||
|
{
|
||||||
|
#ifdef USE_ASSERT_CHECKING
|
||||||
|
if (LOCALLOCK_LOCKTAG(*locallock) == LOCKTAG_RELATION_EXTEND)
|
||||||
|
IsRelationExtensionLockHeld = acquired;
|
||||||
|
#endif
|
||||||
|
}
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* Subroutine to free a locallock entry
|
* Subroutine to free a locallock entry
|
||||||
*/
|
*/
|
||||||
@ -1322,6 +1361,11 @@ RemoveLocalLock(LOCALLOCK *locallock)
|
|||||||
(void *) &(locallock->tag),
|
(void *) &(locallock->tag),
|
||||||
HASH_REMOVE, NULL))
|
HASH_REMOVE, NULL))
|
||||||
elog(WARNING, "locallock table corrupted");
|
elog(WARNING, "locallock table corrupted");
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Indicate that the lock is released for certain types of locks
|
||||||
|
*/
|
||||||
|
CheckAndSetLockHeld(locallock, false);
|
||||||
}
|
}
|
||||||
|
|
||||||
/*
|
/*
|
||||||
@ -1618,6 +1662,9 @@ GrantLockLocal(LOCALLOCK *locallock, ResourceOwner owner)
|
|||||||
locallock->numLockOwners++;
|
locallock->numLockOwners++;
|
||||||
if (owner != NULL)
|
if (owner != NULL)
|
||||||
ResourceOwnerRememberLock(owner, locallock);
|
ResourceOwnerRememberLock(owner, locallock);
|
||||||
|
|
||||||
|
/* Indicate that the lock is acquired for certain types of locks. */
|
||||||
|
CheckAndSetLockHeld(locallock, true);
|
||||||
}
|
}
|
||||||
|
|
||||||
/*
|
/*
|
||||||
|
@ -419,6 +419,7 @@ typedef struct LOCALLOCK
|
|||||||
} LOCALLOCK;
|
} LOCALLOCK;
|
||||||
|
|
||||||
#define LOCALLOCK_LOCKMETHOD(llock) ((llock).tag.lock.locktag_lockmethodid)
|
#define LOCALLOCK_LOCKMETHOD(llock) ((llock).tag.lock.locktag_lockmethodid)
|
||||||
|
#define LOCALLOCK_LOCKTAG(llock) ((LockTagType) (llock).tag.lock.locktag_type)
|
||||||
|
|
||||||
|
|
||||||
/*
|
/*
|
||||||
|
Loading…
x
Reference in New Issue
Block a user