backend_setQueryTimeout_02.patch
text/plain
Filename: backend_setQueryTimeout_02.patch
Type: text/plain
Part: 0
Patch
Same data as JSON:
GET /api/v1/attachments/:id/patch
the parsed metadata as JSON — format, series position, per-file stats; never the diff bytes.
API reference →
Format: unified
| File | + | − |
|---|---|---|
| src/backend/storage/lmgr/proc.c | 6 | 0 |
| src/backend/tcop/postgres.c | 25 | 10 |
| src/backend/utils/adt/timestamp.c | 47 | 0 |
| src/include/catalog/catversion.h | 1 | 1 |
| src/include/catalog/pg_proc.h | 2 | 0 |
| src/include/utils/timestamp.h | 5 | 0 |
diff --git a/src/backend/storage/lmgr/proc.c b/src/backend/storage/lmgr/proc.c
index e4a7dd9..06c8fce 100644
--- a/src/backend/storage/lmgr/proc.c
+++ b/src/backend/storage/lmgr/proc.c
@@ -51,6 +51,8 @@
/* GUC variables */
int DeadlockTimeout = 1000;
int StatementTimeout = 0;
+int SessionTimerTarget = 0;
+
bool log_lock_waits = false;
/* Pointer to this process's PGPROC struct, if any */
@@ -1550,6 +1552,10 @@ CheckStatementTimeout(void)
/* Time to die */
statement_timeout_active = false;
cancel_from_timeout = true;
+
+ /* reset session timer. Never fire twice. */
+ set_session_timer_ms(0);
+
#ifdef HAVE_SETSID
/* try to signal whole process group */
kill(-MyProcPid, SIGINT);
diff --git a/src/backend/tcop/postgres.c b/src/backend/tcop/postgres.c
index cba90a9..769ac2c 100644
--- a/src/backend/tcop/postgres.c
+++ b/src/backend/tcop/postgres.c
@@ -2445,28 +2445,43 @@ exec_describe_portal_message(const char *portal_name)
pq_putemptymessage('n'); /* NoData */
}
-
/*
* Convenience routines for starting/committing a single command.
*/
static void
start_xact_command(void)
{
+ int64 timeout = 0;
+
if (!xact_started)
{
- ereport(DEBUG3,
- (errmsg_internal("StartTransactionCommand")));
+ ereport(DEBUG3, (errmsg_internal("StartTransactionCommand")));
StartTransactionCommand();
- /* Set statement timeout running, if any */
- /* NB: this mustn't be enabled until we are within an xact */
- if (StatementTimeout > 0)
- enable_sig_alarm(StatementTimeout, true);
- else
- cancel_from_timeout = false;
+ if (timeout == 0 ||
+ (StatementTimeout > 0 && timeout > StatementTimeout)) {
+ timeout = StatementTimeout;
+ }
+
+ /* Set statement timeout running, if any */
+ /* NB: this mustn't be enabled until we are within an xact */
+ if (StatementTimeout > 0)
+ enable_sig_alarm(StatementTimeout, true);
+ else
+ cancel_from_timeout = false;
xact_started = true;
- }
+ }
+
+ timeout = get_session_timer_ms();
+ if (timeout > 0) {
+ if (StatementTimeout == 0 || timeout < StatementTimeout) {
+ ereport(DEBUG3, (errmsg_internal("Enable an once session timer")));
+ enable_sig_alarm(timeout, true);
+ } else {
+ cancel_from_timeout = false;
+ }
+ }
}
static void
diff --git a/src/backend/utils/adt/timestamp.c b/src/backend/utils/adt/timestamp.c
index c6e1d13..d998df6 100644
--- a/src/backend/utils/adt/timestamp.c
+++ b/src/backend/utils/adt/timestamp.c
@@ -4824,3 +4824,50 @@ generate_series_timestamptz(PG_FUNCTION_ARGS)
SRF_RETURN_DONE(funcctx);
}
}
+
+/* Session timer target, in ms */
+static int64 sessionTimerTarget;
+
+Datum set_session_timer(PG_FUNCTION_ARGS)
+{
+ int64 ms = PG_GETARG_INT64(0);
+ set_session_timer_ms(ms);
+ PG_RETURN_DATUM(0);
+}
+
+#ifndef HAVE_INT64_TIMESTAMP
+#error Assumes int64 impl of timestamp
+#endif
+
+void set_session_timer_ms(int64 ms)
+{
+ if (ms == 0) {
+ sessionTimerTarget = 0;
+ } else {
+ /* GetCurrentTimestamp is in us */
+ int64 time_now = GetCurrentTimestamp() / 1000;
+ sessionTimerTarget = time_now + ms;
+ }
+}
+
+int64 get_session_timer_ms()
+{
+ int64 ret = 0;
+ if (sessionTimerTarget != 0) {
+ int64 time_now = GetCurrentTimestamp() / 1000;
+ ret = sessionTimerTarget - time_now;
+
+ if (ret <= 0) {
+ /* Timer already passed. This maybe possible if some statement
+ * set the timer, finished so the timer is disabled, next statement
+ * set the timer again, but too late. We want to go through the
+ * same routine and fire the timer. Return 1 ms.
+ */
+ ret = 1;
+ }
+
+ sessionTimerTarget = 0;
+ }
+
+ return ret;
+}
diff --git a/src/include/catalog/catversion.h b/src/include/catalog/catversion.h
index 910474c..904a821 100644
--- a/src/include/catalog/catversion.h
+++ b/src/include/catalog/catversion.h
@@ -53,6 +53,6 @@
*/
/* yyyymmddN */
-#define CATALOG_VERSION_NO 201010101
+#define CATALOG_VERSION_NO 201010102
#endif
diff --git a/src/include/catalog/pg_proc.h b/src/include/catalog/pg_proc.h
index 61c6b27..308f014 100644
--- a/src/include/catalog/pg_proc.h
+++ b/src/include/catalog/pg_proc.h
@@ -4849,6 +4849,8 @@ DATA(insert OID = 3113 ( last_value PGNSP PGUID 12 1 0 0 f t f t f i 1 0 2283 "
DESCR("fetch the last row value");
DATA(insert OID = 3114 ( nth_value PGNSP PGUID 12 1 0 0 f t f t f i 2 0 2283 "2283 23" _null_ _null_ _null_ _null_ window_nth_value _null_ _null_ _null_ ));
DESCR("fetch the Nth row value");
+DATA(insert OID = 3115 ( set_session_timer PGNSP PGUID 12 1 0 0 f f f t f i 1 0 20 "20" _null_ _null_ _null_ _null_ set_session_timer _null_ _null_ _null_ ));
+DESCR("Set a timer for the session");
/*
diff --git a/src/include/utils/timestamp.h b/src/include/utils/timestamp.h
index db7b729..c60d109 100644
--- a/src/include/utils/timestamp.h
+++ b/src/include/utils/timestamp.h
@@ -310,6 +310,11 @@ extern Datum pg_conf_load_time(PG_FUNCTION_ARGS);
extern Datum generate_series_timestamp(PG_FUNCTION_ARGS);
extern Datum generate_series_timestamptz(PG_FUNCTION_ARGS);
+/* session timer, for jdbc setQueryTimeout and like */
+extern Datum set_session_timer(PG_FUNCTION_ARGS);
+extern void set_session_timer_ms(int64 ms);
+extern int64 get_session_timer_ms(void);
+
/* Internal routines (not fmgr-callable) */
extern TimestampTz GetCurrentTimestamp(void);