|
55 | 55 | /* GUC variables */ |
56 | 56 | int DeadlockTimeout = 1000; |
57 | 57 | int StatementTimeout = 0; |
| 58 | +int LockTimeout = 0; |
58 | 59 | bool log_lock_waits = false; |
59 | 60 |
|
60 | 61 | /* Pointer to this process's PGPROC and PGXACT structs, if any */ |
@@ -665,15 +666,27 @@ void |
665 | 666 | LockErrorCleanup(void) |
666 | 667 | { |
667 | 668 | LWLockId partitionLock; |
| 669 | + DisableTimeoutParams timeouts[2]; |
668 | 670 |
|
669 | 671 | AbortStrongLockAcquire(); |
670 | 672 |
|
671 | 673 | /* Nothing to do if we weren't waiting for a lock */ |
672 | 674 | if (lockAwaited == NULL) |
673 | 675 | return; |
674 | 676 |
|
675 | | - /* Turn off the deadlock timer, if it's still running (see ProcSleep) */ |
676 | | - disable_timeout(DEADLOCK_TIMEOUT, false); |
| 677 | + /* |
| 678 | + * Turn off the deadlock and lock timeout timers, if they are still |
| 679 | + * running (see ProcSleep). Note we must preserve the LOCK_TIMEOUT |
| 680 | + * indicator flag, since this function is executed before |
| 681 | + * ProcessInterrupts when responding to SIGINT; else we'd lose the |
| 682 | + * knowledge that the SIGINT came from a lock timeout and not an external |
| 683 | + * source. |
| 684 | + */ |
| 685 | + timeouts[0].id = DEADLOCK_TIMEOUT; |
| 686 | + timeouts[0].keep_indicator = false; |
| 687 | + timeouts[1].id = LOCK_TIMEOUT; |
| 688 | + timeouts[1].keep_indicator = true; |
| 689 | + disable_timeouts(timeouts, 2); |
677 | 690 |
|
678 | 691 | /* Unlink myself from the wait queue, if on it (might not be anymore!) */ |
679 | 692 | partitionLock = LockHashPartitionLock(lockAwaited->hashcode); |
@@ -1072,8 +1085,24 @@ ProcSleep(LOCALLOCK *locallock, LockMethod lockMethodTable) |
1072 | 1085 | * |
1073 | 1086 | * By delaying the check until we've waited for a bit, we can avoid |
1074 | 1087 | * running the rather expensive deadlock-check code in most cases. |
| 1088 | + * |
| 1089 | + * If LockTimeout is set, also enable the timeout for that. We can save a |
| 1090 | + * few cycles by enabling both timeout sources in one call. |
1075 | 1091 | */ |
1076 | | - enable_timeout_after(DEADLOCK_TIMEOUT, DeadlockTimeout); |
| 1092 | + if (LockTimeout > 0) |
| 1093 | + { |
| 1094 | + EnableTimeoutParams timeouts[2]; |
| 1095 | + |
| 1096 | + timeouts[0].id = DEADLOCK_TIMEOUT; |
| 1097 | + timeouts[0].type = TMPARAM_AFTER; |
| 1098 | + timeouts[0].delay_ms = DeadlockTimeout; |
| 1099 | + timeouts[1].id = LOCK_TIMEOUT; |
| 1100 | + timeouts[1].type = TMPARAM_AFTER; |
| 1101 | + timeouts[1].delay_ms = LockTimeout; |
| 1102 | + enable_timeouts(timeouts, 2); |
| 1103 | + } |
| 1104 | + else |
| 1105 | + enable_timeout_after(DEADLOCK_TIMEOUT, DeadlockTimeout); |
1077 | 1106 |
|
1078 | 1107 | /* |
1079 | 1108 | * If someone wakes us between LWLockRelease and PGSemaphoreLock, |
@@ -1240,9 +1269,20 @@ ProcSleep(LOCALLOCK *locallock, LockMethod lockMethodTable) |
1240 | 1269 | } while (myWaitStatus == STATUS_WAITING); |
1241 | 1270 |
|
1242 | 1271 | /* |
1243 | | - * Disable the timer, if it's still running |
| 1272 | + * Disable the timers, if they are still running |
1244 | 1273 | */ |
1245 | | - disable_timeout(DEADLOCK_TIMEOUT, false); |
| 1274 | + if (LockTimeout > 0) |
| 1275 | + { |
| 1276 | + DisableTimeoutParams timeouts[2]; |
| 1277 | + |
| 1278 | + timeouts[0].id = DEADLOCK_TIMEOUT; |
| 1279 | + timeouts[0].keep_indicator = false; |
| 1280 | + timeouts[1].id = LOCK_TIMEOUT; |
| 1281 | + timeouts[1].keep_indicator = false; |
| 1282 | + disable_timeouts(timeouts, 2); |
| 1283 | + } |
| 1284 | + else |
| 1285 | + disable_timeout(DEADLOCK_TIMEOUT, false); |
1246 | 1286 |
|
1247 | 1287 | /* |
1248 | 1288 | * Re-acquire the lock table's partition lock. We have to do this to hold |
|
0 commit comments