1
0
mirror of https://github.com/postgres/postgres.git synced 2025-04-21 12:05:57 +03:00

Add idle_in_transaction_session_timeout.

Vik Fearing, reviewed by Stéphane Schildknecht and me, and revised
slightly by me.
This commit is contained in:
Robert Haas 2016-03-16 11:30:45 -04:00
parent 5871b88487
commit c6dda1f48e
12 changed files with 91 additions and 3 deletions

View File

@ -6063,6 +6063,26 @@ COPY postgres_log FROM '/full/path/to/logfile.csv' WITH csv;
</listitem> </listitem>
</varlistentry> </varlistentry>
<varlistentry id="guc-idle-in-transaction-session-timeout" xreflabel="idle_in_transaction_session_timeout">
<term><varname>idle_in_transaction_session_timeout</varname> (<type>integer</type>)
<indexterm>
<primary><varname>idle_in_transaction_session_timeout</> configuration parameter</primary>
</indexterm>
</term>
<listitem>
<para>
Terminate any session with an open transaction that has been idle for
longer than the specified duration in milliseconds. 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.
</para>
<para>
The default value of 0 disables this feature.
</para>
</listitem>
</varlistentry>
<varlistentry id="guc-vacuum-freeze-table-age" xreflabel="vacuum_freeze_table_age"> <varlistentry id="guc-vacuum-freeze-table-age" xreflabel="vacuum_freeze_table_age">
<term><varname>vacuum_freeze_table_age</varname> (<type>integer</type>) <term><varname>vacuum_freeze_table_age</varname> (<type>integer</type>)
<indexterm> <indexterm>

View File

@ -725,7 +725,9 @@ ERROR: could not serialize access due to read/write dependencies among transact
<listitem> <listitem>
<para> <para>
Don't leave connections dangling <quote>idle in transaction</quote> Don't leave connections dangling <quote>idle in transaction</quote>
longer than necessary. longer than necessary. The configuration parameter
<xref linkend="guc-idle-in-transaction-session-timeout"> may be used to
automatically disconnect lingering sessions.
</para> </para>
</listitem> </listitem>
<listitem> <listitem>

View File

@ -58,6 +58,7 @@
int DeadlockTimeout = 1000; int DeadlockTimeout = 1000;
int StatementTimeout = 0; int StatementTimeout = 0;
int LockTimeout = 0; int LockTimeout = 0;
int IdleInTransactionSessionTimeout = 0;
bool log_lock_waits = false; bool log_lock_waits = false;
/* Pointer to this process's PGPROC and PGXACT structs, if any */ /* Pointer to this process's PGPROC and PGXACT structs, if any */

View File

@ -2978,6 +2978,18 @@ ProcessInterrupts(void)
} }
} }
if (IdleInTransactionSessionTimeoutPending)
{
/* Has the timeout setting changed since last we looked? */
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 (ParallelMessagePending) if (ParallelMessagePending)
HandleParallelMessages(); HandleParallelMessages();
} }
@ -3553,6 +3565,7 @@ PostgresMain(int argc, char *argv[],
StringInfoData input_message; StringInfoData input_message;
sigjmp_buf local_sigjmp_buf; sigjmp_buf local_sigjmp_buf;
volatile bool send_ready_for_query = true; volatile bool send_ready_for_query = true;
bool disable_idle_in_transaction_timeout = false;
/* Initialize startup process environment if necessary. */ /* Initialize startup process environment if necessary. */
if (!IsUnderPostmaster) if (!IsUnderPostmaster)
@ -3942,11 +3955,27 @@ PostgresMain(int argc, char *argv[],
{ {
set_ps_display("idle in transaction (aborted)", false); set_ps_display("idle in transaction (aborted)", false);
pgstat_report_activity(STATE_IDLEINTRANSACTION_ABORTED, NULL); pgstat_report_activity(STATE_IDLEINTRANSACTION_ABORTED, NULL);
/* Start the idle-in-transaction timer */
if (IdleInTransactionSessionTimeout > 0)
{
disable_idle_in_transaction_timeout = true;
enable_timeout_after(IDLE_IN_TRANSACTION_SESSION_TIMEOUT,
IdleInTransactionSessionTimeout);
}
} }
else if (IsTransactionOrTransactionBlock()) else if (IsTransactionOrTransactionBlock())
{ {
set_ps_display("idle in transaction", false); set_ps_display("idle in transaction", false);
pgstat_report_activity(STATE_IDLEINTRANSACTION, NULL); pgstat_report_activity(STATE_IDLEINTRANSACTION, NULL);
/* Start the idle-in-transaction timer */
if (IdleInTransactionSessionTimeout > 0)
{
disable_idle_in_transaction_timeout = true;
enable_timeout_after(IDLE_IN_TRANSACTION_SESSION_TIMEOUT,
IdleInTransactionSessionTimeout);
}
} }
else else
{ {
@ -3987,7 +4016,16 @@ PostgresMain(int argc, char *argv[],
DoingCommandRead = false; DoingCommandRead = false;
/* /*
* (5) check for any other interesting events that happened while we * (5) turn off the idle-in-transaction timeout
*/
if (disable_idle_in_transaction_timeout)
{
disable_timeout(IDLE_IN_TRANSACTION_SESSION_TIMEOUT, false);
disable_idle_in_transaction_timeout = false;
}
/*
* (6) check for any other interesting events that happened while we
* slept. * slept.
*/ */
if (got_SIGHUP) if (got_SIGHUP)
@ -3997,7 +4035,7 @@ PostgresMain(int argc, char *argv[],
} }
/* /*
* (6) process the command. But ignore it if we're skipping till * (7) process the command. But ignore it if we're skipping till
* Sync. * Sync.
*/ */
if (ignore_till_sync && firstchar != EOF) if (ignore_till_sync && firstchar != EOF)

View File

@ -229,6 +229,7 @@ Section: Class 25 - Invalid Transaction State
25007 E ERRCODE_SCHEMA_AND_DATA_STATEMENT_MIXING_NOT_SUPPORTED schema_and_data_statement_mixing_not_supported 25007 E ERRCODE_SCHEMA_AND_DATA_STATEMENT_MIXING_NOT_SUPPORTED schema_and_data_statement_mixing_not_supported
25P01 E ERRCODE_NO_ACTIVE_SQL_TRANSACTION no_active_sql_transaction 25P01 E ERRCODE_NO_ACTIVE_SQL_TRANSACTION no_active_sql_transaction
25P02 E ERRCODE_IN_FAILED_SQL_TRANSACTION in_failed_sql_transaction 25P02 E ERRCODE_IN_FAILED_SQL_TRANSACTION in_failed_sql_transaction
25P03 E ERRCODE_IDLE_IN_TRANSACTION_SESSION_TIMEOUT idle_in_transaction_session_timeout
Section: Class 26 - Invalid SQL Statement Name Section: Class 26 - Invalid SQL Statement Name

View File

@ -30,6 +30,7 @@ volatile bool InterruptPending = false;
volatile bool QueryCancelPending = false; volatile bool QueryCancelPending = false;
volatile bool ProcDiePending = false; volatile bool ProcDiePending = false;
volatile bool ClientConnectionLost = false; volatile bool ClientConnectionLost = false;
volatile bool IdleInTransactionSessionTimeoutPending = false;
volatile uint32 InterruptHoldoffCount = 0; volatile uint32 InterruptHoldoffCount = 0;
volatile uint32 QueryCancelHoldoffCount = 0; volatile uint32 QueryCancelHoldoffCount = 0;
volatile uint32 CritSectionCount = 0; volatile uint32 CritSectionCount = 0;

View File

@ -70,6 +70,7 @@ static void InitCommunication(void);
static void ShutdownPostgres(int code, Datum arg); static void ShutdownPostgres(int code, Datum arg);
static void StatementTimeoutHandler(void); static void StatementTimeoutHandler(void);
static void LockTimeoutHandler(void); static void LockTimeoutHandler(void);
static void IdleInTransactionSessionTimeoutHandler(void);
static bool ThereIsAtLeastOneRole(void); static bool ThereIsAtLeastOneRole(void);
static void process_startup_options(Port *port, bool am_superuser); static void process_startup_options(Port *port, bool am_superuser);
static void process_settings(Oid databaseid, Oid roleid); static void process_settings(Oid databaseid, Oid roleid);
@ -597,6 +598,8 @@ InitPostgres(const char *in_dbname, Oid dboid, const char *username,
RegisterTimeout(DEADLOCK_TIMEOUT, CheckDeadLockAlert); RegisterTimeout(DEADLOCK_TIMEOUT, CheckDeadLockAlert);
RegisterTimeout(STATEMENT_TIMEOUT, StatementTimeoutHandler); RegisterTimeout(STATEMENT_TIMEOUT, StatementTimeoutHandler);
RegisterTimeout(LOCK_TIMEOUT, LockTimeoutHandler); RegisterTimeout(LOCK_TIMEOUT, LockTimeoutHandler);
RegisterTimeout(IDLE_IN_TRANSACTION_SESSION_TIMEOUT,
IdleInTransactionSessionTimeoutHandler);
} }
/* /*
@ -1178,6 +1181,13 @@ LockTimeoutHandler(void)
kill(MyProcPid, SIGINT); kill(MyProcPid, SIGINT);
} }
static void
IdleInTransactionSessionTimeoutHandler(void)
{
IdleInTransactionSessionTimeoutPending = true;
InterruptPending = true;
SetLatch(MyLatch);
}
/* /*
* Returns true if at least one role is defined in this database cluster. * Returns true if at least one role is defined in this database cluster.

View File

@ -2065,6 +2065,17 @@ static struct config_int ConfigureNamesInt[] =
NULL, NULL, NULL NULL, NULL, NULL
}, },
{
{"idle_in_transaction_session_timeout", PGC_USERSET, CLIENT_CONN_STATEMENT,
gettext_noop("Sets the maximum allowed duration of any idling transaction."),
gettext_noop("A value of 0 turns off the timeout."),
GUC_UNIT_MS
},
&IdleInTransactionSessionTimeout,
0, 0, INT_MAX,
NULL, NULL, NULL
},
{ {
{"vacuum_freeze_min_age", PGC_USERSET, CLIENT_CONN_STATEMENT, {"vacuum_freeze_min_age", PGC_USERSET, CLIENT_CONN_STATEMENT,
gettext_noop("Minimum age at which VACUUM should freeze a table row."), gettext_noop("Minimum age at which VACUUM should freeze a table row."),

View File

@ -529,6 +529,7 @@
#session_replication_role = 'origin' #session_replication_role = 'origin'
#statement_timeout = 0 # in milliseconds, 0 is disabled #statement_timeout = 0 # in milliseconds, 0 is disabled
#lock_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
#vacuum_freeze_min_age = 50000000 #vacuum_freeze_min_age = 50000000
#vacuum_freeze_table_age = 150000000 #vacuum_freeze_table_age = 150000000
#vacuum_multixact_freeze_min_age = 5000000 #vacuum_multixact_freeze_min_age = 5000000

View File

@ -80,6 +80,7 @@
extern PGDLLIMPORT volatile bool InterruptPending; extern PGDLLIMPORT volatile bool InterruptPending;
extern PGDLLIMPORT volatile bool QueryCancelPending; extern PGDLLIMPORT volatile bool QueryCancelPending;
extern PGDLLIMPORT volatile bool ProcDiePending; extern PGDLLIMPORT volatile bool ProcDiePending;
extern PGDLLIMPORT volatile bool IdleInTransactionSessionTimeoutPending;
extern volatile bool ClientConnectionLost; extern volatile bool ClientConnectionLost;

View File

@ -257,6 +257,7 @@ extern PGPROC *PreparedXactProcs;
extern int DeadlockTimeout; extern int DeadlockTimeout;
extern int StatementTimeout; extern int StatementTimeout;
extern int LockTimeout; extern int LockTimeout;
extern int IdleInTransactionSessionTimeout;
extern bool log_lock_waits; extern bool log_lock_waits;

View File

@ -30,6 +30,7 @@ typedef enum TimeoutId
STANDBY_DEADLOCK_TIMEOUT, STANDBY_DEADLOCK_TIMEOUT,
STANDBY_TIMEOUT, STANDBY_TIMEOUT,
STANDBY_LOCK_TIMEOUT, STANDBY_LOCK_TIMEOUT,
IDLE_IN_TRANSACTION_SESSION_TIMEOUT,
/* First user-definable timeout reason */ /* First user-definable timeout reason */
USER_TIMEOUT, USER_TIMEOUT,
/* Maximum number of timeout reasons */ /* Maximum number of timeout reasons */