Skip to content

Commit f8e5f15

Browse files
committed
Rearm statement_timeout after each executed query.
Previously statement_timeout, in the extended protocol, affected all messages till a Sync message. For clients that pipeline/batch query execution that's problematic. Instead disable timeout after each Execute message, and enable, if necessary, the timer in start_xact_command(). As that's done only for Execute and not Parse / Bind, pipelining the latter two could still cause undesirable timeouts. But a survey of protocol implementations shows that all drivers issue Sync messages when preparing, and adding timeout rearming to both is fairly expensive for the common parse / bind / execute sequence. Author: Tatsuo Ishii, editorialized by Andres Freund Reviewed-By: Takayuki Tsunakawa, Andres Freund Discussion: https://postgr.es/m/20170222.115044.1665674502985097185.t-ishii@sraoss.co.jp
1 parent 0fb9e4a commit f8e5f15

File tree

1 file changed

+65
-12
lines changed

1 file changed

+65
-12
lines changed

src/backend/tcop/postgres.c

Lines changed: 65 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -143,6 +143,11 @@ static bool DoingCommandRead = false;
143143
static bool doing_extended_query_message = false;
144144
static bool ignore_till_sync = false;
145145

146+
/*
147+
* Flag to keep track of whether statement timeout timer is active.
148+
*/
149+
static bool stmt_timeout_active = false;
150+
146151
/*
147152
* If an unnamed prepared statement exists, it's stored here.
148153
* We keep it separate from the hashtable kept by commands/prepare.c
@@ -182,6 +187,8 @@ static bool IsTransactionExitStmtList(List *pstmts);
182187
static bool IsTransactionStmtList(List *pstmts);
183188
static void drop_unnamed_stmt(void);
184189
static void log_disconnections(int code, Datum arg);
190+
static void enable_statement_timeout(void);
191+
static void disable_statement_timeout(void);
185192

186193

187194
/* ----------------------------------------------------------------
@@ -1241,7 +1248,8 @@ exec_parse_message(const char *query_string, /* string to execute */
12411248
/*
12421249
* Start up a transaction command so we can run parse analysis etc. (Note
12431250
* that this will normally change current memory context.) Nothing happens
1244-
* if we are already in one.
1251+
* if we are already in one. This also arms the statement timeout if
1252+
* necessary.
12451253
*/
12461254
start_xact_command();
12471255

@@ -1529,7 +1537,8 @@ exec_bind_message(StringInfo input_message)
15291537
/*
15301538
* Start up a transaction command so we can call functions etc. (Note that
15311539
* this will normally change current memory context.) Nothing happens if
1532-
* we are already in one.
1540+
* we are already in one. This also arms the statement timeout if
1541+
* necessary.
15331542
*/
15341543
start_xact_command();
15351544

@@ -2021,6 +2030,9 @@ exec_execute_message(const char *portal_name, long max_rows)
20212030
* those that start or end a transaction block.
20222031
*/
20232032
CommandCounterIncrement();
2033+
2034+
/* full command has been executed, reset timeout */
2035+
disable_statement_timeout();
20242036
}
20252037

20262038
/* Send appropriate CommandComplete to client */
@@ -2450,25 +2462,27 @@ start_xact_command(void)
24502462
{
24512463
StartTransactionCommand();
24522464

2453-
/* Set statement timeout running, if any */
2454-
/* NB: this mustn't be enabled until we are within an xact */
2455-
if (StatementTimeout > 0)
2456-
enable_timeout_after(STATEMENT_TIMEOUT, StatementTimeout);
2457-
else
2458-
disable_timeout(STATEMENT_TIMEOUT, false);
2459-
24602465
xact_started = true;
24612466
}
2467+
2468+
/*
2469+
* Start statement timeout if necessary. Note that this'll intentionally
2470+
* not reset the clock on an already started timeout, to avoid the timing
2471+
* overhead when start_xact_command() is invoked repeatedly, without an
2472+
* interceding finish_xact_command() (e.g. parse/bind/execute). If that's
2473+
* not desired, the timeout has to be disabled explicitly.
2474+
*/
2475+
enable_statement_timeout();
24622476
}
24632477

24642478
static void
24652479
finish_xact_command(void)
24662480
{
2481+
/* cancel active statement timeout after each command */
2482+
disable_statement_timeout();
2483+
24672484
if (xact_started)
24682485
{
2469-
/* Cancel any active statement timeout before committing */
2470-
disable_timeout(STATEMENT_TIMEOUT, false);
2471-
24722486
CommitTransactionCommand();
24732487

24742488
#ifdef MEMORY_CONTEXT_CHECKING
@@ -4537,3 +4551,42 @@ log_disconnections(int code, Datum arg)
45374551
port->user_name, port->database_name, port->remote_host,
45384552
port->remote_port[0] ? " port=" : "", port->remote_port)));
45394553
}
4554+
4555+
/*
4556+
* Start statement timeout timer, if enabled.
4557+
*
4558+
* If there's already a timeout running, don't restart the timer. That
4559+
* enables compromises between accuracy of timeouts and cost of starting a
4560+
* timeout.
4561+
*/
4562+
static void
4563+
enable_statement_timeout(void)
4564+
{
4565+
/* must be within an xact */
4566+
Assert(xact_started);
4567+
4568+
if (StatementTimeout > 0)
4569+
{
4570+
if (!stmt_timeout_active)
4571+
{
4572+
enable_timeout_after(STATEMENT_TIMEOUT, StatementTimeout);
4573+
stmt_timeout_active = true;
4574+
}
4575+
}
4576+
else
4577+
disable_timeout(STATEMENT_TIMEOUT, false);
4578+
}
4579+
4580+
/*
4581+
* Disable statement timeout, if active.
4582+
*/
4583+
static void
4584+
disable_statement_timeout(void)
4585+
{
4586+
if (stmt_timeout_active)
4587+
{
4588+
disable_timeout(STATEMENT_TIMEOUT, false);
4589+
4590+
stmt_timeout_active = false;
4591+
}
4592+
}

0 commit comments

Comments
 (0)
pFad - Phonifier reborn

Pfad - The Proxy pFad of © 2024 Garber Painting. All rights reserved.

Note: This service is not intended for secure transactions such as banking, social media, email, or purchasing. Use at your own risk. We assume no liability whatsoever for broken pages.


Alternative Proxies:

Alternative Proxy

pFad Proxy

pFad v3 Proxy

pFad v4 Proxy