Deal with idle_session_timeout.
authorTatsuo Ishii <ishii@sraoss.co.jp>
Wed, 26 Oct 2022 23:45:17 +0000 (08:45 +0900)
committerTatsuo Ishii <ishii@sraoss.co.jp>
Thu, 27 Oct 2022 00:01:32 +0000 (09:01 +0900)
If idle_session_timeout (added in PostgreSQL 14) is enabled and the
timeout fires, followings happen:

- If failover_on_backend_error is on (the default), Pgpool-II will
  trigger failover.

- If only one of PostgreSQL servers enables idle_session_timeout,
  Pgpool-II could hang.

To deal with idle_session_timeout detect_idle_session_timeout_error()
is added to detect the error code for idle_session_timeout. If the
error is detected, Pgpool-II returns the error code to frondend as a
fatal error and disconnects the session.  This is a similar fix
implemented for idle_in_transaction_session_timeout.

https://git.postgresql.org/gitweb/?p=pgpool2.git;a=commit;h=3f5986eee360f12e6a0bb77aa46f95abf5f6bc10

Discussion: https://www.pgpool.net/pipermail/pgpool-hackers/2022-October/004209.html
Back-path-through: 4.0

src/include/protocol/pool_proto_modules.h
src/protocol/pool_process_query.c

index 1feb19d733fb00abd052dd0a796e2d428b4ed088..1fd6f8c68663c52bb28c5c0db8f08bf6d59ffe90 100644 (file)
@@ -6,7 +6,7 @@
  * pgpool: a language independent connection pool server for PostgreSQL
  * written by Tatsuo Ishii
  *
- * Copyright (c) 2003-2017     PgPool Global Development Group
+ * Copyright (c) 2003-2022     PgPool Global Development Group
  *
  * Permission to use, copy, modify, and distribute this software and
  * its documentation for any purpose and without fee is hereby
@@ -168,6 +168,7 @@ extern int  detect_serialization_error(POOL_CONNECTION * backend, int major, bool
 extern int     detect_active_sql_transaction_error(POOL_CONNECTION * backend, int major);
 extern int     detect_query_cancel_error(POOL_CONNECTION * backend, int major);
 extern int     detect_idle_in_transaction_session_timeout_error(POOL_CONNECTION * backend, int major);
+extern int     detect_idle_session_timeout_error(POOL_CONNECTION * backend, int major);
 extern bool is_partition_table(POOL_CONNECTION_POOL * backend, Node *node);
 extern POOL_STATUS pool_discard_packet(POOL_CONNECTION_POOL * cp);
 extern void query_cache_register(char kind, POOL_CONNECTION * frontend, char *database, char *data, int data_len);
index 2d4ad6eba5d57cc44146e93189242acc2bb8934c..8d1c0c819c074f97c6410454dcbc07590cce2f61 100644 (file)
@@ -77,6 +77,7 @@
 #define ADMIN_SHUTDOWN_ERROR_CODE "57P01"
 #define CRASH_SHUTDOWN_ERROR_CODE "57P02"
 #define IDLE_IN_TRANSACTION_SESSION_TIMEOUT_ERROR_CODE "25P03"
+#define IDLE_SESSION_TIMEOUT_ERROR_CODE "57P05"
 
 static int     reset_backend(POOL_CONNECTION_POOL * backend, int qcnt);
 static char *get_insert_command_table_name(InsertStmt *node);
@@ -4398,6 +4399,18 @@ detect_idle_in_transaction_session_timeout_error(POOL_CONNECTION * backend, int
        return r;
 }
 
+int
+detect_idle_session_timeout_error(POOL_CONNECTION * backend, int major)
+{
+       int                     r = extract_message(backend, IDLE_SESSION_TIMEOUT_ERROR_CODE, major, 'E', true);
+
+       if (r == SPECIFIED_ERROR)
+               ereport(DEBUG1,
+                               (errmsg("detecting idle session timeout error"),
+                                errdetail("idle session timeout error message from backend")));
+       return r;
+}
+
 /*
  * extract_message: extract specified error by an error code.
  * returns 0 in case of success or 1 in case of specified error.
@@ -4927,7 +4940,18 @@ SELECT_RETRY:
                                {
                                        ereport(FATAL,
                                                        (pool_error_code(IDLE_IN_TRANSACTION_SESSION_TIMEOUT_ERROR_CODE),
-                                                        errmsg("terminating connection due to idle-in-transaction timeout")));
+                                                        errmsg("terminating connection due to idle-in-transaction session timeout")));
+                               }
+
+                               /*
+                                * connection was terminated due to idle_session_timeout expired
+                                */
+                               r = detect_idle_session_timeout_error(CONNECTION(backend, i), MAJOR(backend));
+                               if (r == SPECIFIED_ERROR)
+                               {
+                                       ereport(FATAL,
+                                                       (pool_error_code(IDLE_SESSION_TIMEOUT_ERROR_CODE),
+                                                        errmsg("terminating connection due to idle session timeout")));
                                }
 
                                /*