mirror of
https://github.com/postgres/postgres.git
synced 2025-11-07 19:06:32 +03:00
Add lock_timeout configuration parameter.
This GUC allows limiting the time spent waiting to acquire any one heavyweight lock. In support of this, improve the recently-added timeout infrastructure to permit efficiently enabling or disabling multiple timeouts at once. That reduces the performance hit from turning on lock_timeout, though it's still not zero. Zoltán Böszörményi, reviewed by Tom Lane, Stephen Frost, and Hari Babu
This commit is contained in:
@@ -55,6 +55,7 @@
|
||||
/* GUC variables */
|
||||
int DeadlockTimeout = 1000;
|
||||
int StatementTimeout = 0;
|
||||
int LockTimeout = 0;
|
||||
bool log_lock_waits = false;
|
||||
|
||||
/* Pointer to this process's PGPROC and PGXACT structs, if any */
|
||||
@@ -665,6 +666,7 @@ void
|
||||
LockErrorCleanup(void)
|
||||
{
|
||||
LWLockId partitionLock;
|
||||
DisableTimeoutParams timeouts[2];
|
||||
|
||||
AbortStrongLockAcquire();
|
||||
|
||||
@@ -672,8 +674,19 @@ LockErrorCleanup(void)
|
||||
if (lockAwaited == NULL)
|
||||
return;
|
||||
|
||||
/* Turn off the deadlock timer, if it's still running (see ProcSleep) */
|
||||
disable_timeout(DEADLOCK_TIMEOUT, false);
|
||||
/*
|
||||
* Turn off the deadlock and lock timeout timers, if they are still
|
||||
* running (see ProcSleep). Note we must preserve the LOCK_TIMEOUT
|
||||
* indicator flag, since this function is executed before
|
||||
* ProcessInterrupts when responding to SIGINT; else we'd lose the
|
||||
* knowledge that the SIGINT came from a lock timeout and not an external
|
||||
* source.
|
||||
*/
|
||||
timeouts[0].id = DEADLOCK_TIMEOUT;
|
||||
timeouts[0].keep_indicator = false;
|
||||
timeouts[1].id = LOCK_TIMEOUT;
|
||||
timeouts[1].keep_indicator = true;
|
||||
disable_timeouts(timeouts, 2);
|
||||
|
||||
/* Unlink myself from the wait queue, if on it (might not be anymore!) */
|
||||
partitionLock = LockHashPartitionLock(lockAwaited->hashcode);
|
||||
@@ -1072,8 +1085,24 @@ ProcSleep(LOCALLOCK *locallock, LockMethod lockMethodTable)
|
||||
*
|
||||
* By delaying the check until we've waited for a bit, we can avoid
|
||||
* running the rather expensive deadlock-check code in most cases.
|
||||
*
|
||||
* If LockTimeout is set, also enable the timeout for that. We can save a
|
||||
* few cycles by enabling both timeout sources in one call.
|
||||
*/
|
||||
enable_timeout_after(DEADLOCK_TIMEOUT, DeadlockTimeout);
|
||||
if (LockTimeout > 0)
|
||||
{
|
||||
EnableTimeoutParams timeouts[2];
|
||||
|
||||
timeouts[0].id = DEADLOCK_TIMEOUT;
|
||||
timeouts[0].type = TMPARAM_AFTER;
|
||||
timeouts[0].delay_ms = DeadlockTimeout;
|
||||
timeouts[1].id = LOCK_TIMEOUT;
|
||||
timeouts[1].type = TMPARAM_AFTER;
|
||||
timeouts[1].delay_ms = LockTimeout;
|
||||
enable_timeouts(timeouts, 2);
|
||||
}
|
||||
else
|
||||
enable_timeout_after(DEADLOCK_TIMEOUT, DeadlockTimeout);
|
||||
|
||||
/*
|
||||
* If someone wakes us between LWLockRelease and PGSemaphoreLock,
|
||||
@@ -1240,9 +1269,20 @@ ProcSleep(LOCALLOCK *locallock, LockMethod lockMethodTable)
|
||||
} while (myWaitStatus == STATUS_WAITING);
|
||||
|
||||
/*
|
||||
* Disable the timer, if it's still running
|
||||
* Disable the timers, if they are still running
|
||||
*/
|
||||
disable_timeout(DEADLOCK_TIMEOUT, false);
|
||||
if (LockTimeout > 0)
|
||||
{
|
||||
DisableTimeoutParams timeouts[2];
|
||||
|
||||
timeouts[0].id = DEADLOCK_TIMEOUT;
|
||||
timeouts[0].keep_indicator = false;
|
||||
timeouts[1].id = LOCK_TIMEOUT;
|
||||
timeouts[1].keep_indicator = false;
|
||||
disable_timeouts(timeouts, 2);
|
||||
}
|
||||
else
|
||||
disable_timeout(DEADLOCK_TIMEOUT, false);
|
||||
|
||||
/*
|
||||
* Re-acquire the lock table's partition lock. We have to do this to hold
|
||||
|
||||
Reference in New Issue
Block a user