diff options
| author | Tom Lane <tgl@sss.pgh.pa.us> | 2013-03-16 23:22:17 -0400 |
|---|---|---|
| committer | Tom Lane <tgl@sss.pgh.pa.us> | 2013-03-16 23:22:57 -0400 |
| commit | d43837d03067487560af481474ae985df894f786 (patch) | |
| tree | 7289d038a184fa3dc59195aaa27538714ea85ad9 /src/backend/storage/lmgr/proc.c | |
| parent | d2bef5f7db5f3afdbbb3f58b8eff49f0bc7ef790 (diff) | |
| download | postgresql-d43837d03067487560af481474ae985df894f786.tar.gz | |
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
Diffstat (limited to 'src/backend/storage/lmgr/proc.c')
| -rw-r--r-- | src/backend/storage/lmgr/proc.c | 50 |
1 files changed, 45 insertions, 5 deletions
diff --git a/src/backend/storage/lmgr/proc.c b/src/backend/storage/lmgr/proc.c index 2e012fad11..5809a79798 100644 --- a/src/backend/storage/lmgr/proc.c +++ b/src/backend/storage/lmgr/proc.c @@ -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 |
