mirror of
https://github.com/postgres/postgres.git
synced 2025-04-25 21:42:33 +03:00
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
This commit is contained in:
parent
09cf1d5226
commit
9877374bef
@ -8310,15 +8310,52 @@ COPY postgres_log FROM '/full/path/to/logfile.csv' WITH csv;
|
||||
</term>
|
||||
<listitem>
|
||||
<para>
|
||||
Terminate any session with an open transaction that has been idle for
|
||||
longer than the specified amount of time. This allows any
|
||||
locks held by that session to be released and the connection slot to be reused;
|
||||
it also allows tuples visible only to this transaction to be vacuumed. See
|
||||
<xref linkend="routine-vacuuming"/> for more details about this.
|
||||
Terminate any session that has been idle (that is, waiting for a
|
||||
client query) within an open transaction 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.
|
||||
</para>
|
||||
|
||||
<para>
|
||||
If this value is specified without units, it is taken as milliseconds.
|
||||
A value of zero (the default) disables the timeout.
|
||||
This option can be used to ensure that idle sessions do not hold
|
||||
locks for an unreasonable amount of time. Even when no significant
|
||||
locks are held, an open transaction prevents vacuuming away
|
||||
recently-dead tuples that may be visible only to this transaction;
|
||||
so remaining idle for a long time can contribute to table bloat.
|
||||
See <xref linkend="routine-vacuuming"/> for more details.
|
||||
</para>
|
||||
</listitem>
|
||||
</varlistentry>
|
||||
|
||||
<varlistentry id="guc-idle-session-timeout" xreflabel="idle_session_timeout">
|
||||
<term><varname>idle_session_timeout</varname> (<type>integer</type>)
|
||||
<indexterm>
|
||||
<primary><varname>idle_session_timeout</varname> configuration parameter</primary>
|
||||
</indexterm>
|
||||
</term>
|
||||
<listitem>
|
||||
<para>
|
||||
Terminate any session that has been idle (that is, waiting for a
|
||||
client query), but not within an open transaction, 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.
|
||||
</para>
|
||||
|
||||
<para>
|
||||
Unlike the case with an open transaction, an idle session without a
|
||||
transaction imposes no large costs on the server, so there is less
|
||||
need to enable this timeout
|
||||
than <varname>idle_in_transaction_session_timeout</varname>.
|
||||
</para>
|
||||
|
||||
<para>
|
||||
Be wary of enforcing this timeout on connections made through
|
||||
connection-pooling software or other middleware, as such a layer
|
||||
may not react well to unexpected connection closure. It may be
|
||||
helpful to enable this timeout only for interactive sessions,
|
||||
perhaps by applying it only to particular users.
|
||||
</para>
|
||||
</listitem>
|
||||
</varlistentry>
|
||||
|
@ -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 */
|
||||
|
@ -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;
|
||||
}
|
||||
|
||||
/*
|
||||
|
@ -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
|
||||
|
||||
|
@ -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;
|
||||
|
@ -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.
|
||||
*/
|
||||
|
@ -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
|
||||
},
|
||||
@ -2518,6 +2518,17 @@ static struct config_int ConfigureNamesInt[] =
|
||||
NULL, NULL, NULL
|
||||
},
|
||||
|
||||
{
|
||||
{"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."),
|
||||
|
@ -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
|
||||
|
@ -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;
|
||||
|
@ -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;
|
||||
|
||||
|
||||
|
@ -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 */
|
||||
|
Loading…
x
Reference in New Issue
Block a user