diff options
author | Tom Lane <tgl@sss.pgh.pa.us> | 2021-01-06 18:28:42 -0500 |
---|---|---|
committer | Tom Lane <tgl@sss.pgh.pa.us> | 2021-01-06 18:28:52 -0500 |
commit | 9877374bef76ef03923f6aa8b955f2dbcbe6c2c7 (patch) | |
tree | 9255038d282a07de135530578d5b365a4aaa18dd /src | |
parent | 09cf1d52267644cdbdb734294012cf1228745aaa (diff) | |
download | postgresql-9877374bef76ef03923f6aa8b955f2dbcbe6c2c7.tar.gz postgresql-9877374bef76ef03923f6aa8b955f2dbcbe6c2c7.zip |
Add idle_session_timeout.
This GUC variable works much like idle_in_transaction_session_timeout,
in that it kills sessions that have waited too long for a new client
query. But it applies when we're not in a transaction, rather than
when we are.
Li Japin, reviewed by David Johnston and Hayato Kuroda, some
fixes by me
Discussion: https://postgr.es/m/763A0689-F189-459E-946F-F0EC4458980B@hotmail.com
Diffstat (limited to 'src')
-rw-r--r-- | src/backend/storage/lmgr/proc.c | 1 | ||||
-rw-r--r-- | src/backend/tcop/postgres.c | 48 | ||||
-rw-r--r-- | src/backend/utils/errcodes.txt | 1 | ||||
-rw-r--r-- | src/backend/utils/init/globals.c | 1 | ||||
-rw-r--r-- | src/backend/utils/init/postinit.c | 10 | ||||
-rw-r--r-- | src/backend/utils/misc/guc.c | 13 | ||||
-rw-r--r-- | src/backend/utils/misc/postgresql.conf.sample | 1 | ||||
-rw-r--r-- | src/include/miscadmin.h | 1 | ||||
-rw-r--r-- | src/include/storage/proc.h | 1 | ||||
-rw-r--r-- | src/include/utils/timeout.h | 3 |
10 files changed, 71 insertions, 9 deletions
diff --git a/src/backend/storage/lmgr/proc.c b/src/backend/storage/lmgr/proc.c index 9b6aa2fe0de..0366a7cc004 100644 --- a/src/backend/storage/lmgr/proc.c +++ b/src/backend/storage/lmgr/proc.c @@ -61,6 +61,7 @@ int DeadlockTimeout = 1000; int StatementTimeout = 0; int LockTimeout = 0; int IdleInTransactionSessionTimeout = 0; +int IdleSessionTimeout = 0; bool log_lock_waits = false; /* Pointer to this process's PGPROC struct, if any */ diff --git a/src/backend/tcop/postgres.c b/src/backend/tcop/postgres.c index 9d98c028a2d..2b53ebf97dc 100644 --- a/src/backend/tcop/postgres.c +++ b/src/backend/tcop/postgres.c @@ -3242,14 +3242,28 @@ ProcessInterrupts(void) if (IdleInTransactionSessionTimeoutPending) { - /* Has the timeout setting changed since last we looked? */ + /* + * If the GUC has been reset to zero, ignore the signal. This is + * important because the GUC update itself won't disable any pending + * interrupt. + */ if (IdleInTransactionSessionTimeout > 0) ereport(FATAL, (errcode(ERRCODE_IDLE_IN_TRANSACTION_SESSION_TIMEOUT), errmsg("terminating connection due to idle-in-transaction timeout"))); else IdleInTransactionSessionTimeoutPending = false; + } + if (IdleSessionTimeoutPending) + { + /* As above, ignore the signal if the GUC has been reset to zero. */ + if (IdleSessionTimeout > 0) + ereport(FATAL, + (errcode(ERRCODE_IDLE_SESSION_TIMEOUT), + errmsg("terminating connection due to idle-session timeout"))); + else + IdleSessionTimeoutPending = false; } if (ProcSignalBarrierPending) @@ -3826,7 +3840,8 @@ PostgresMain(int argc, char *argv[], StringInfoData input_message; sigjmp_buf local_sigjmp_buf; volatile bool send_ready_for_query = true; - bool disable_idle_in_transaction_timeout = false; + bool idle_in_transaction_timeout_enabled = false; + bool idle_session_timeout_enabled = false; /* Initialize startup process environment if necessary. */ if (!IsUnderPostmaster) @@ -4228,6 +4243,8 @@ PostgresMain(int argc, char *argv[], * processing of batched messages, and because we don't want to report * uncommitted updates (that confuses autovacuum). The notification * processor wants a call too, if we are not in a transaction block. + * + * Also, if an idle timeout is enabled, start the timer for that. */ if (send_ready_for_query) { @@ -4239,7 +4256,7 @@ PostgresMain(int argc, char *argv[], /* Start the idle-in-transaction timer */ if (IdleInTransactionSessionTimeout > 0) { - disable_idle_in_transaction_timeout = true; + idle_in_transaction_timeout_enabled = true; enable_timeout_after(IDLE_IN_TRANSACTION_SESSION_TIMEOUT, IdleInTransactionSessionTimeout); } @@ -4252,7 +4269,7 @@ PostgresMain(int argc, char *argv[], /* Start the idle-in-transaction timer */ if (IdleInTransactionSessionTimeout > 0) { - disable_idle_in_transaction_timeout = true; + idle_in_transaction_timeout_enabled = true; enable_timeout_after(IDLE_IN_TRANSACTION_SESSION_TIMEOUT, IdleInTransactionSessionTimeout); } @@ -4275,6 +4292,14 @@ PostgresMain(int argc, char *argv[], set_ps_display("idle"); pgstat_report_activity(STATE_IDLE, NULL); + + /* Start the idle-session timer */ + if (IdleSessionTimeout > 0) + { + idle_session_timeout_enabled = true; + enable_timeout_after(IDLE_SESSION_TIMEOUT, + IdleSessionTimeout); + } } /* Report any recently-changed GUC options */ @@ -4310,12 +4335,21 @@ PostgresMain(int argc, char *argv[], DoingCommandRead = false; /* - * (5) turn off the idle-in-transaction timeout + * (5) turn off the idle-in-transaction and idle-session timeouts, if + * active. + * + * At most one of these two will be active, so there's no need to + * worry about combining the timeout.c calls into one. */ - if (disable_idle_in_transaction_timeout) + if (idle_in_transaction_timeout_enabled) { disable_timeout(IDLE_IN_TRANSACTION_SESSION_TIMEOUT, false); - disable_idle_in_transaction_timeout = false; + idle_in_transaction_timeout_enabled = false; + } + if (idle_session_timeout_enabled) + { + disable_timeout(IDLE_SESSION_TIMEOUT, false); + idle_session_timeout_enabled = false; } /* diff --git a/src/backend/utils/errcodes.txt b/src/backend/utils/errcodes.txt index 64ca2deec99..1d5a78e73d6 100644 --- a/src/backend/utils/errcodes.txt +++ b/src/backend/utils/errcodes.txt @@ -109,6 +109,7 @@ Section: Class 08 - Connection Exception 08004 E ERRCODE_SQLSERVER_REJECTED_ESTABLISHMENT_OF_SQLCONNECTION sqlserver_rejected_establishment_of_sqlconnection 08007 E ERRCODE_TRANSACTION_RESOLUTION_UNKNOWN transaction_resolution_unknown 08P01 E ERRCODE_PROTOCOL_VIOLATION protocol_violation +08P02 E ERRCODE_IDLE_SESSION_TIMEOUT idle_session_timeout Section: Class 09 - Triggered Action Exception diff --git a/src/backend/utils/init/globals.c b/src/backend/utils/init/globals.c index 3d5d6cc033c..ea28769d6a3 100644 --- a/src/backend/utils/init/globals.c +++ b/src/backend/utils/init/globals.c @@ -32,6 +32,7 @@ volatile sig_atomic_t QueryCancelPending = false; volatile sig_atomic_t ProcDiePending = false; volatile sig_atomic_t ClientConnectionLost = false; volatile sig_atomic_t IdleInTransactionSessionTimeoutPending = false; +volatile sig_atomic_t IdleSessionTimeoutPending = false; volatile sig_atomic_t ProcSignalBarrierPending = false; volatile uint32 InterruptHoldoffCount = 0; volatile uint32 QueryCancelHoldoffCount = 0; diff --git a/src/backend/utils/init/postinit.c b/src/backend/utils/init/postinit.c index 59b3f4b1359..e5965bc517d 100644 --- a/src/backend/utils/init/postinit.c +++ b/src/backend/utils/init/postinit.c @@ -72,6 +72,7 @@ static void ShutdownPostgres(int code, Datum arg); static void StatementTimeoutHandler(void); static void LockTimeoutHandler(void); static void IdleInTransactionSessionTimeoutHandler(void); +static void IdleSessionTimeoutHandler(void); static bool ThereIsAtLeastOneRole(void); static void process_startup_options(Port *port, bool am_superuser); static void process_settings(Oid databaseid, Oid roleid); @@ -619,6 +620,7 @@ InitPostgres(const char *in_dbname, Oid dboid, const char *username, RegisterTimeout(LOCK_TIMEOUT, LockTimeoutHandler); RegisterTimeout(IDLE_IN_TRANSACTION_SESSION_TIMEOUT, IdleInTransactionSessionTimeoutHandler); + RegisterTimeout(IDLE_SESSION_TIMEOUT, IdleSessionTimeoutHandler); } /* @@ -1233,6 +1235,14 @@ IdleInTransactionSessionTimeoutHandler(void) SetLatch(MyLatch); } +static void +IdleSessionTimeoutHandler(void) +{ + IdleSessionTimeoutPending = true; + InterruptPending = true; + SetLatch(MyLatch); +} + /* * Returns true if at least one role is defined in this database cluster. */ diff --git a/src/backend/utils/misc/guc.c b/src/backend/utils/misc/guc.c index 1ccf7593eea..daf9c127cde 100644 --- a/src/backend/utils/misc/guc.c +++ b/src/backend/utils/misc/guc.c @@ -2509,7 +2509,7 @@ static struct config_int ConfigureNamesInt[] = { {"idle_in_transaction_session_timeout", PGC_USERSET, CLIENT_CONN_STATEMENT, - gettext_noop("Sets the maximum allowed duration of any idling transaction."), + gettext_noop("Sets the maximum allowed idle time between queries, when in a transaction."), gettext_noop("A value of 0 turns off the timeout."), GUC_UNIT_MS }, @@ -2519,6 +2519,17 @@ static struct config_int ConfigureNamesInt[] = }, { + {"idle_session_timeout", PGC_USERSET, CLIENT_CONN_STATEMENT, + gettext_noop("Sets the maximum allowed idle time between queries, when not in a transaction."), + gettext_noop("A value of 0 turns off the timeout."), + GUC_UNIT_MS + }, + &IdleSessionTimeout, + 0, 0, INT_MAX, + NULL, NULL, NULL + }, + + { {"vacuum_freeze_min_age", PGC_USERSET, CLIENT_CONN_STATEMENT, gettext_noop("Minimum age at which VACUUM should freeze a table row."), NULL diff --git a/src/backend/utils/misc/postgresql.conf.sample b/src/backend/utils/misc/postgresql.conf.sample index 5298e18ecd5..033aa335a01 100644 --- a/src/backend/utils/misc/postgresql.conf.sample +++ b/src/backend/utils/misc/postgresql.conf.sample @@ -663,6 +663,7 @@ #statement_timeout = 0 # in milliseconds, 0 is disabled #lock_timeout = 0 # in milliseconds, 0 is disabled #idle_in_transaction_session_timeout = 0 # in milliseconds, 0 is disabled +#idle_session_timeout = 0 # in milliseconds, 0 is disabled #vacuum_freeze_min_age = 50000000 #vacuum_freeze_table_age = 150000000 #vacuum_multixact_freeze_min_age = 5000000 diff --git a/src/include/miscadmin.h b/src/include/miscadmin.h index 2c71db79c0a..1bdc97e3082 100644 --- a/src/include/miscadmin.h +++ b/src/include/miscadmin.h @@ -82,6 +82,7 @@ extern PGDLLIMPORT volatile sig_atomic_t InterruptPending; extern PGDLLIMPORT volatile sig_atomic_t QueryCancelPending; extern PGDLLIMPORT volatile sig_atomic_t ProcDiePending; extern PGDLLIMPORT volatile sig_atomic_t IdleInTransactionSessionTimeoutPending; +extern PGDLLIMPORT volatile sig_atomic_t IdleSessionTimeoutPending; extern PGDLLIMPORT volatile sig_atomic_t ProcSignalBarrierPending; extern PGDLLIMPORT volatile sig_atomic_t ClientConnectionLost; diff --git a/src/include/storage/proc.h b/src/include/storage/proc.h index 989c5849d45..0786fcf103a 100644 --- a/src/include/storage/proc.h +++ b/src/include/storage/proc.h @@ -378,6 +378,7 @@ extern PGDLLIMPORT int DeadlockTimeout; extern PGDLLIMPORT int StatementTimeout; extern PGDLLIMPORT int LockTimeout; extern PGDLLIMPORT int IdleInTransactionSessionTimeout; +extern PGDLLIMPORT int IdleSessionTimeout; extern bool log_lock_waits; diff --git a/src/include/utils/timeout.h b/src/include/utils/timeout.h index 8adb4e14cac..ecb2a366a5f 100644 --- a/src/include/utils/timeout.h +++ b/src/include/utils/timeout.h @@ -31,10 +31,11 @@ typedef enum TimeoutId STANDBY_TIMEOUT, STANDBY_LOCK_TIMEOUT, IDLE_IN_TRANSACTION_SESSION_TIMEOUT, + IDLE_SESSION_TIMEOUT, /* First user-definable timeout reason */ USER_TIMEOUT, /* Maximum number of timeout reasons */ - MAX_TIMEOUTS = 16 + MAX_TIMEOUTS = USER_TIMEOUT + 10 } TimeoutId; /* callback function signature */ |