Skip to content

Commit 7c8d062

Browse files
committed
Merge branch 'REL9_5_STABLE' into PGPRO9_5
2 parents 7951d67 + 73f5acc commit 7c8d062

File tree

7 files changed

+439
-322
lines changed

7 files changed

+439
-322
lines changed

src/backend/tcop/postgres.c

Lines changed: 19 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -2920,6 +2920,9 @@ ProcessInterrupts(void)
29202920

29212921
if (QueryCancelPending)
29222922
{
2923+
bool lock_timeout_occurred;
2924+
bool stmt_timeout_occurred;
2925+
29232926
/*
29242927
* Don't allow query cancel interrupts while reading input from the
29252928
* client, because we might lose sync in the FE/BE protocol. (Die
@@ -2940,17 +2943,29 @@ ProcessInterrupts(void)
29402943

29412944
/*
29422945
* If LOCK_TIMEOUT and STATEMENT_TIMEOUT indicators are both set, we
2943-
* prefer to report the former; but be sure to clear both.
2946+
* need to clear both, so always fetch both.
29442947
*/
2945-
if (get_timeout_indicator(LOCK_TIMEOUT, true))
2948+
lock_timeout_occurred = get_timeout_indicator(LOCK_TIMEOUT, true);
2949+
stmt_timeout_occurred = get_timeout_indicator(STATEMENT_TIMEOUT, true);
2950+
2951+
/*
2952+
* If both were set, we want to report whichever timeout completed
2953+
* earlier; this ensures consistent behavior if the machine is slow
2954+
* enough that the second timeout triggers before we get here. A tie
2955+
* is arbitrarily broken in favor of reporting a lock timeout.
2956+
*/
2957+
if (lock_timeout_occurred && stmt_timeout_occurred &&
2958+
get_timeout_finish_time(STATEMENT_TIMEOUT) < get_timeout_finish_time(LOCK_TIMEOUT))
2959+
lock_timeout_occurred = false; /* report stmt timeout */
2960+
2961+
if (lock_timeout_occurred)
29462962
{
2947-
(void) get_timeout_indicator(STATEMENT_TIMEOUT, true);
29482963
LockErrorCleanup();
29492964
ereport(ERROR,
29502965
(errcode(ERRCODE_LOCK_NOT_AVAILABLE),
29512966
errmsg("canceling statement due to lock timeout")));
29522967
}
2953-
if (get_timeout_indicator(STATEMENT_TIMEOUT, true))
2968+
if (stmt_timeout_occurred)
29542969
{
29552970
LockErrorCleanup();
29562971
ereport(ERROR,

src/backend/utils/misc/timeout.c

Lines changed: 15 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -34,7 +34,7 @@ typedef struct timeout_params
3434
timeout_handler_proc timeout_handler;
3535

3636
TimestampTz start_time; /* time that timeout was last activated */
37-
TimestampTz fin_time; /* if active, time it is due to fire */
37+
TimestampTz fin_time; /* time it is, or was last, due to fire */
3838
} timeout_params;
3939

4040
/*
@@ -654,3 +654,17 @@ get_timeout_start_time(TimeoutId id)
654654
{
655655
return all_timeouts[id].start_time;
656656
}
657+
658+
/*
659+
* Return the time when the timeout is, or most recently was, due to fire
660+
*
661+
* Note: will return 0 if timeout has never been activated in this process.
662+
* However, we do *not* reset the fin_time when a timeout occurs, so as
663+
* not to create a race condition if SIGALRM fires just as some code is
664+
* about to fetch the value.
665+
*/
666+
TimestampTz
667+
get_timeout_finish_time(TimeoutId id)
668+
{
669+
return all_timeouts[id].fin_time;
670+
}

0 commit comments

Comments
 (0)