From d49aca925fc7e200343d2ebfaf9b18694662aef0 Mon Sep 17 00:00:00 2001 From: japinli Date: Sun, 15 Nov 2020 17:43:30 +0800 Subject: [PATCH v7 1/2] Allow terminating the idle sessions Terminate any session that has been idle for longer than the specified amount of time. Note that this values should be set to zero if you use some connection-pooling software, or pg servers used by postgres_fdw, because connections might be closed unexpectedly. --- doc/src/sgml/config.sgml | 29 +++++++++++++++++++ src/backend/storage/lmgr/proc.c | 1 + src/backend/tcop/postgres.c | 25 ++++++++++++++++ src/backend/utils/errcodes.txt | 1 + src/backend/utils/init/globals.c | 1 + src/backend/utils/init/postinit.c | 10 +++++++ src/backend/utils/misc/guc.c | 11 +++++++ src/backend/utils/misc/postgresql.conf.sample | 1 + src/include/miscadmin.h | 1 + src/include/storage/proc.h | 1 + src/include/utils/timeout.h | 1 + 11 files changed, 82 insertions(+) diff --git a/doc/src/sgml/config.sgml b/doc/src/sgml/config.sgml index a632cf98ba..b71a116be3 100644 --- a/doc/src/sgml/config.sgml +++ b/doc/src/sgml/config.sgml @@ -8276,6 +8276,35 @@ COPY postgres_log FROM '/full/path/to/logfile.csv' WITH csv; + + idle_session_timeout (integer) + + idle_session_timeout configuration parameter + + + + + Terminate any session that has been idle for longer than the specified amount of time. + + + If this value is specified without units, it is taken as milliseconds. + A value of zero (the default) disables the timeout. + + + + + This parameter should be set to zero if you use some connection-pooling software, + or pg servers used by postgres_fdw, because connections might be closed unexpectedly. + + + Aside from a bit of resource consumption idle sessions do not interfere with the + long-running stability of the server. + + + + + + idle_in_transaction_session_timeout (integer) diff --git a/src/backend/storage/lmgr/proc.c b/src/backend/storage/lmgr/proc.c index d1738c65f5..5fd3e79e72 100644 --- a/src/backend/storage/lmgr/proc.c +++ b/src/backend/storage/lmgr/proc.c @@ -60,6 +60,7 @@ int DeadlockTimeout = 1000; int StatementTimeout = 0; int LockTimeout = 0; +int IdleSessionTimeout = 0; int IdleInTransactionSessionTimeout = 0; bool log_lock_waits = false; diff --git a/src/backend/tcop/postgres.c b/src/backend/tcop/postgres.c index 7c5f7c775b..313900e998 100644 --- a/src/backend/tcop/postgres.c +++ b/src/backend/tcop/postgres.c @@ -3204,6 +3204,16 @@ ProcessInterrupts(void) } + if (IdleSessionTimeoutPending) + { + if (IdleSessionTimeout > 0) + ereport(FATAL, + (errcode(ERRCODE_IDLE_SESSION_TIMEOUT), + errmsg("terminating connection due to idle-session timeout"))); + else + IdleSessionTimeoutPending = false; + } + if (ProcSignalBarrierPending) ProcessProcSignalBarrier(); @@ -3779,6 +3789,7 @@ PostgresMain(int argc, char *argv[], sigjmp_buf local_sigjmp_buf; volatile bool send_ready_for_query = true; bool disable_idle_in_transaction_timeout = false; + bool disable_idle_session_timeout = false; /* Initialize startup process environment if necessary. */ if (!IsUnderPostmaster) @@ -4227,6 +4238,14 @@ PostgresMain(int argc, char *argv[], set_ps_display("idle"); pgstat_report_activity(STATE_IDLE, NULL); + + /* Start the idle-session timer */ + if (IdleSessionTimeout > 0) + { + disable_idle_session_timeout = true; + enable_timeout_after(IDLE_SESSION_TIMEOUT, + IdleSessionTimeout); + } } ReadyForQuery(whereToSendOutput); @@ -4267,6 +4286,12 @@ PostgresMain(int argc, char *argv[], disable_idle_in_transaction_timeout = false; } + if (disable_idle_session_timeout) + { + disable_timeout(IDLE_SESSION_TIMEOUT, false); + disable_idle_session_timeout = false; + } + /* * (6) check for any other interesting events that happened while we * slept. diff --git a/src/backend/utils/errcodes.txt b/src/backend/utils/errcodes.txt index c79312ed03..d5935a2ca9 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 +08008 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 6ab8216839..03bfd88d2c 100644 --- a/src/backend/utils/init/globals.c +++ b/src/backend/utils/init/globals.c @@ -31,6 +31,7 @@ volatile sig_atomic_t InterruptPending = false; volatile sig_atomic_t QueryCancelPending = false; volatile sig_atomic_t ProcDiePending = false; volatile sig_atomic_t ClientConnectionLost = false; +volatile sig_atomic_t IdleSessionTimeoutPending = false; volatile sig_atomic_t IdleInTransactionSessionTimeoutPending = false; volatile sig_atomic_t ProcSignalBarrierPending = false; volatile uint32 InterruptHoldoffCount = 0; diff --git a/src/backend/utils/init/postinit.c b/src/backend/utils/init/postinit.c index f2dd8e4914..fbe758061b 100644 --- a/src/backend/utils/init/postinit.c +++ b/src/backend/utils/init/postinit.c @@ -71,6 +71,7 @@ static void InitCommunication(void); static void ShutdownPostgres(int code, Datum arg); static void StatementTimeoutHandler(void); static void LockTimeoutHandler(void); +static void IdleSessionTimeoutHandler(void); static void IdleInTransactionSessionTimeoutHandler(void); static bool ThereIsAtLeastOneRole(void); static void process_startup_options(Port *port, bool am_superuser); @@ -628,6 +629,7 @@ InitPostgres(const char *in_dbname, Oid dboid, const char *username, RegisterTimeout(DEADLOCK_TIMEOUT, CheckDeadLockAlert); RegisterTimeout(STATEMENT_TIMEOUT, StatementTimeoutHandler); RegisterTimeout(LOCK_TIMEOUT, LockTimeoutHandler); + RegisterTimeout(IDLE_SESSION_TIMEOUT, IdleSessionTimeoutHandler); RegisterTimeout(IDLE_IN_TRANSACTION_SESSION_TIMEOUT, IdleInTransactionSessionTimeoutHandler); } @@ -1236,6 +1238,14 @@ LockTimeoutHandler(void) kill(MyProcPid, SIGINT); } +static void +IdleSessionTimeoutHandler(void) +{ + IdleSessionTimeoutPending = true; + InterruptPending = true; + SetLatch(MyLatch); +} + static void IdleInTransactionSessionTimeoutHandler(void) { diff --git a/src/backend/utils/misc/guc.c b/src/backend/utils/misc/guc.c index bb34630e8e..e6df047b70 100644 --- a/src/backend/utils/misc/guc.c +++ b/src/backend/utils/misc/guc.c @@ -2503,6 +2503,17 @@ static struct config_int ConfigureNamesInt[] = NULL, NULL, NULL }, + { + {"idle_session_timeout", PGC_USERSET, CLIENT_CONN_STATEMENT, + gettext_noop("Sets the maximum allowed duration of any idling session."), + gettext_noop("A value of 0 turns off the timeout."), + GUC_UNIT_MS + }, + &IdleSessionTimeout, + 0, 0, INT_MAX, + NULL, NULL, NULL + }, + { {"idle_in_transaction_session_timeout", PGC_USERSET, CLIENT_CONN_STATEMENT, gettext_noop("Sets the maximum allowed duration of any idling transaction."), diff --git a/src/backend/utils/misc/postgresql.conf.sample b/src/backend/utils/misc/postgresql.conf.sample index 9cb571f7cc..6e3f14f234 100644 --- a/src/backend/utils/misc/postgresql.conf.sample +++ b/src/backend/utils/misc/postgresql.conf.sample @@ -664,6 +664,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 72e3352398..995b603899 100644 --- a/src/include/miscadmin.h +++ b/src/include/miscadmin.h @@ -81,6 +81,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 IdleSessionTimeoutPending; extern PGDLLIMPORT volatile sig_atomic_t IdleInTransactionSessionTimeoutPending; extern PGDLLIMPORT volatile sig_atomic_t ProcSignalBarrierPending; diff --git a/src/include/storage/proc.h b/src/include/storage/proc.h index 1067f58f51..a6f3077b7c 100644 --- a/src/include/storage/proc.h +++ b/src/include/storage/proc.h @@ -369,6 +369,7 @@ extern PGPROC *PreparedXactProcs; extern PGDLLIMPORT int DeadlockTimeout; extern PGDLLIMPORT int StatementTimeout; extern PGDLLIMPORT int LockTimeout; +extern PGDLLIMPORT int IdleSessionTimeout; extern PGDLLIMPORT int IdleInTransactionSessionTimeout; extern bool log_lock_waits; diff --git a/src/include/utils/timeout.h b/src/include/utils/timeout.h index 83a15f6795..15eeb0ed2c 100644 --- a/src/include/utils/timeout.h +++ b/src/include/utils/timeout.h @@ -31,6 +31,7 @@ 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 */ -- 2.28.0