Movatterモバイル変換


[0]ホーム

URL:


Skip to content

Navigation Menu

Sign in
Appearance settings

Search code, repositories, users, issues, pull requests...

Provide feedback

We read every piece of feedback, and take your input very seriously.

Saved searches

Use saved searches to filter your results more quickly

Sign up
Appearance settings

Commitd43837d

Browse files
committed
Add lock_timeout configuration parameter.
This GUC allows limiting the time spent waiting to acquire any oneheavyweight lock.In support of this, improve the recently-added timeout infrastructureto permit efficiently enabling or disabling multiple timeouts at once.That reduces the performance hit from turning on lock_timeout, thoughit's still not zero.Zoltán Böszörményi, reviewed by Tom Lane,Stephen Frost, and Hari Babu
1 parentd2bef5f commitd43837d

File tree

16 files changed

+511
-116
lines changed

16 files changed

+511
-116
lines changed

‎doc/src/sgml/config.sgml

Lines changed: 37 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -5077,7 +5077,7 @@ COPY postgres_log FROM '/full/path/to/logfile.csv' WITH csv;
50775077
</indexterm>
50785078
<listitem>
50795079
<para>
5080-
Abort any statement that takesover the specified number of
5080+
Abort any statement that takesmore than the specified number of
50815081
milliseconds, starting from the time the command arrives at the server
50825082
from the client. If <varname>log_min_error_statement</> is set to
50835083
<literal>ERROR</> or lower, the statement that timed out will also be
@@ -5086,8 +5086,42 @@ COPY postgres_log FROM '/full/path/to/logfile.csv' WITH csv;
50865086

50875087
<para>
50885088
Setting <varname>statement_timeout</> in
5089-
<filename>postgresql.conf</> is not recommended because it
5090-
affects all sessions.
5089+
<filename>postgresql.conf</> is not recommended because it would
5090+
affect all sessions.
5091+
</para>
5092+
</listitem>
5093+
</varlistentry>
5094+
5095+
<varlistentry id="guc-lock-timeout" xreflabel="lock_timeout">
5096+
<term><varname>lock_timeout</varname> (<type>integer</type>)</term>
5097+
<indexterm>
5098+
<primary><varname>lock_timeout</> configuration parameter</primary>
5099+
</indexterm>
5100+
<listitem>
5101+
<para>
5102+
Abort any statement that waits longer than the specified number of
5103+
milliseconds while attempting to acquire a lock on a table, index,
5104+
row, or other database object. The time limit applies separately to
5105+
each lock acquisition attempt. The limit applies both to explicit
5106+
locking requests (such as <command>LOCK TABLE</>, or <command>SELECT
5107+
FOR UPDATE</> without <literal>NOWAIT</>) and to implicitly-acquired
5108+
locks. If <varname>log_min_error_statement</> is set to
5109+
<literal>ERROR</> or lower, the statement that timed out will be
5110+
logged. A value of zero (the default) turns this off.
5111+
</para>
5112+
5113+
<para>
5114+
Unlike <varname>statement_timeout</>, this timeout can only occur
5115+
while waiting for locks. Note that if <varname>statement_timeout</>
5116+
is nonzero, it is rather pointless to set <varname>lock_timeout</> to
5117+
the same or larger value, since the statement timeout would always
5118+
trigger first.
5119+
</para>
5120+
5121+
<para>
5122+
Setting <varname>lock_timeout</> in
5123+
<filename>postgresql.conf</> is not recommended because it would
5124+
affect all sessions.
50915125
</para>
50925126
</listitem>
50935127
</varlistentry>

‎src/backend/postmaster/autovacuum.c

Lines changed: 6 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -547,10 +547,11 @@ AutoVacLauncherMain(int argc, char *argv[])
547547
SetConfigOption("zero_damaged_pages","false",PGC_SUSET,PGC_S_OVERRIDE);
548548

549549
/*
550-
* Force statement_timeout to zero to avoida timeout setting from
551-
*preventing regular maintenance from being executed.
550+
* Force statement_timeoutand lock_timeoutto zero to avoidletting these
551+
*settings prevent regular maintenance from being executed.
552552
*/
553553
SetConfigOption("statement_timeout","0",PGC_SUSET,PGC_S_OVERRIDE);
554+
SetConfigOption("lock_timeout","0",PGC_SUSET,PGC_S_OVERRIDE);
554555

555556
/*
556557
* Force default_transaction_isolation to READ COMMITTED. We don't want
@@ -1573,10 +1574,11 @@ AutoVacWorkerMain(int argc, char *argv[])
15731574
SetConfigOption("zero_damaged_pages","false",PGC_SUSET,PGC_S_OVERRIDE);
15741575

15751576
/*
1576-
* Force statement_timeout to zero to avoida timeout setting from
1577-
*preventing regular maintenance from being executed.
1577+
* Force statement_timeoutand lock_timeoutto zero to avoidletting these
1578+
*settings prevent regular maintenance from being executed.
15781579
*/
15791580
SetConfigOption("statement_timeout","0",PGC_SUSET,PGC_S_OVERRIDE);
1581+
SetConfigOption("lock_timeout","0",PGC_SUSET,PGC_S_OVERRIDE);
15801582

15811583
/*
15821584
* Force default_transaction_isolation to READ COMMITTED. We don't want

‎src/backend/storage/ipc/standby.c

Lines changed: 9 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -428,8 +428,15 @@ ResolveRecoveryConflictWithBufferPin(void)
428428
* Wake up at ltime, and check for deadlocks as well if we will be
429429
* waiting longer than deadlock_timeout
430430
*/
431-
enable_timeout_after(STANDBY_DEADLOCK_TIMEOUT,DeadlockTimeout);
432-
enable_timeout_at(STANDBY_TIMEOUT,ltime);
431+
EnableTimeoutParamstimeouts[2];
432+
433+
timeouts[0].id=STANDBY_TIMEOUT;
434+
timeouts[0].type=TMPARAM_AT;
435+
timeouts[0].fin_time=ltime;
436+
timeouts[1].id=STANDBY_DEADLOCK_TIMEOUT;
437+
timeouts[1].type=TMPARAM_AFTER;
438+
timeouts[1].delay_ms=DeadlockTimeout;
439+
enable_timeouts(timeouts,2);
433440
}
434441

435442
/* Wait to be signaled by UnpinBuffer() */

‎src/backend/storage/lmgr/proc.c

Lines changed: 45 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -55,6 +55,7 @@
5555
/* GUC variables */
5656
intDeadlockTimeout=1000;
5757
intStatementTimeout=0;
58+
intLockTimeout=0;
5859
boollog_lock_waits= false;
5960

6061
/* Pointer to this process's PGPROC and PGXACT structs, if any */
@@ -665,15 +666,27 @@ void
665666
LockErrorCleanup(void)
666667
{
667668
LWLockIdpartitionLock;
669+
DisableTimeoutParamstimeouts[2];
668670

669671
AbortStrongLockAcquire();
670672

671673
/* Nothing to do if we weren't waiting for a lock */
672674
if (lockAwaited==NULL)
673675
return;
674676

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);
677690

678691
/* Unlink myself from the wait queue, if on it (might not be anymore!) */
679692
partitionLock=LockHashPartitionLock(lockAwaited->hashcode);
@@ -1072,8 +1085,24 @@ ProcSleep(LOCALLOCK *locallock, LockMethod lockMethodTable)
10721085
*
10731086
* By delaying the check until we've waited for a bit, we can avoid
10741087
* 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.
10751091
*/
1076-
enable_timeout_after(DEADLOCK_TIMEOUT,DeadlockTimeout);
1092+
if (LockTimeout>0)
1093+
{
1094+
EnableTimeoutParamstimeouts[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);
10771106

10781107
/*
10791108
* If someone wakes us between LWLockRelease and PGSemaphoreLock,
@@ -1240,9 +1269,20 @@ ProcSleep(LOCALLOCK *locallock, LockMethod lockMethodTable)
12401269
}while (myWaitStatus==STATUS_WAITING);
12411270

12421271
/*
1243-
* Disable thetimer, ifit's still running
1272+
* Disable thetimers, ifthey are still running
12441273
*/
1245-
disable_timeout(DEADLOCK_TIMEOUT, false);
1274+
if (LockTimeout>0)
1275+
{
1276+
DisableTimeoutParamstimeouts[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);
12461286

12471287
/*
12481288
* Re-acquire the lock table's partition lock. We have to do this to hold

‎src/backend/tcop/postgres.c

Lines changed: 16 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -2883,7 +2883,22 @@ ProcessInterrupts(void)
28832883
(errcode(ERRCODE_QUERY_CANCELED),
28842884
errmsg("canceling authentication due to timeout")));
28852885
}
2886-
if (get_timeout_indicator(STATEMENT_TIMEOUT))
2886+
2887+
/*
2888+
* If LOCK_TIMEOUT and STATEMENT_TIMEOUT indicators are both set, we
2889+
* prefer to report the former; but be sure to clear both.
2890+
*/
2891+
if (get_timeout_indicator(LOCK_TIMEOUT, true))
2892+
{
2893+
ImmediateInterruptOK= false;/* not idle anymore */
2894+
(void)get_timeout_indicator(STATEMENT_TIMEOUT, true);
2895+
DisableNotifyInterrupt();
2896+
DisableCatchupInterrupt();
2897+
ereport(ERROR,
2898+
(errcode(ERRCODE_QUERY_CANCELED),
2899+
errmsg("canceling statement due to lock timeout")));
2900+
}
2901+
if (get_timeout_indicator(STATEMENT_TIMEOUT, true))
28872902
{
28882903
ImmediateInterruptOK= false;/* not idle anymore */
28892904
DisableNotifyInterrupt();

‎src/backend/utils/init/postinit.c

Lines changed: 18 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -67,6 +67,7 @@ static void CheckMyDatabase(const char *name, bool am_superuser);
6767
staticvoidInitCommunication(void);
6868
staticvoidShutdownPostgres(intcode,Datumarg);
6969
staticvoidStatementTimeoutHandler(void);
70+
staticvoidLockTimeoutHandler(void);
7071
staticboolThereIsAtLeastOneRole(void);
7172
staticvoidprocess_startup_options(Port*port,boolam_superuser);
7273
staticvoidprocess_settings(Oiddatabaseid,Oidroleid);
@@ -535,6 +536,7 @@ InitPostgres(const char *in_dbname, Oid dboid, const char *username,
535536
{
536537
RegisterTimeout(DEADLOCK_TIMEOUT,CheckDeadLock);
537538
RegisterTimeout(STATEMENT_TIMEOUT,StatementTimeoutHandler);
539+
RegisterTimeout(LOCK_TIMEOUT,LockTimeoutHandler);
538540
}
539541

540542
/*
@@ -1052,6 +1054,22 @@ StatementTimeoutHandler(void)
10521054
kill(MyProcPid,SIGINT);
10531055
}
10541056

1057+
/*
1058+
* LOCK_TIMEOUT handler: trigger a query-cancel interrupt.
1059+
*
1060+
* This is identical to StatementTimeoutHandler, but since it's so short,
1061+
* we might as well keep the two functions separate for clarity.
1062+
*/
1063+
staticvoid
1064+
LockTimeoutHandler(void)
1065+
{
1066+
#ifdefHAVE_SETSID
1067+
/* try to signal whole process group */
1068+
kill(-MyProcPid,SIGINT);
1069+
#endif
1070+
kill(MyProcPid,SIGINT);
1071+
}
1072+
10551073

10561074
/*
10571075
* Returns true if at least one role is defined in this database cluster.

‎src/backend/utils/misc/guc.c

Lines changed: 11 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1861,6 +1861,17 @@ static struct config_int ConfigureNamesInt[] =
18611861
NULL,NULL,NULL
18621862
},
18631863

1864+
{
1865+
{"lock_timeout",PGC_USERSET,CLIENT_CONN_STATEMENT,
1866+
gettext_noop("Sets the maximum allowed duration of any wait for a lock."),
1867+
gettext_noop("A value of 0 turns off the timeout."),
1868+
GUC_UNIT_MS
1869+
},
1870+
&LockTimeout,
1871+
0,0,INT_MAX,
1872+
NULL,NULL,NULL
1873+
},
1874+
18641875
{
18651876
{"vacuum_freeze_min_age",PGC_USERSET,CLIENT_CONN_STATEMENT,
18661877
gettext_noop("Minimum age at which VACUUM should freeze a table row."),

‎src/backend/utils/misc/postgresql.conf.sample

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -489,6 +489,7 @@
489489
#default_transaction_deferrable = off
490490
#session_replication_role = 'origin'
491491
#statement_timeout = 0# in milliseconds, 0 is disabled
492+
#lock_timeout = 0# in milliseconds, 0 is disabled
492493
#vacuum_freeze_min_age = 50000000
493494
#vacuum_freeze_table_age = 150000000
494495
#bytea_output = 'hex'# hex, escape

0 commit comments

Comments
 (0)

[8]ページ先頭

©2009-2025 Movatter.jp