pgpool2.git / summary / log / commit / refs
commit ed66f36d2c274f041018098484790e855d00c0cf
Author: Tatsuo Ishii <ishii@postgresql.org>
Date: Thu May 31 02:39:09 2018 +0000
Fix pgpool hung when query cache enabled in extended query mode.
If replication delay is too much, load balancing is
disabled. Unfortunately query cache module tried to access the backend
even if the target node was already changed to primary even if load
balancing was disabled. To fix this, the target backend is identified
by using pending message data which reflects the fact that load
balancing is disabled.
Bug reported in [pgpool-general-jp: 1534].
To reproduce the bug, following steps are required.
1) create a 2 node streaming replication setting (just running
pgpool_setup will do this),
2) set backend weight 0 to 0 to force the load balance node to node 1.
3) break recovery.conf on node 1 (for example modify conninfo)
4) start the whole cluster.
5) run massive DDL. pgbench -i is convenient for this.
6) make sure that replication delay is too much by using "show
pool_nodes".
7) run following data using pgproto. (you need to adjust lines
including "#" so that # starts beginning of the line)
# Test for disable_load_balance_on_write feature.
#
# Force load balance node to 1.
##backend_weight0 = 0
##backend_weight1 = 1
# Start a transaction
'P' "" "BEGIN" 0
'B' "" "" 0 0 0
'E' "" 0
# Issue SELECT.
'P' "" "SELECT 1"
'B' "" "" 0 0 0
'E' "" 0
# Issue COMMIT
'P' "" "COMMIT" 0
'B' "" "" 0 0 0
'E' "" 0
'S'
'Y'
# Issue same SELECT.
'P' "" "SELECT 1"
'B' "" "" 0 0 0
'E' "" 0
'S'
'Y'
'X'
8) next "SELECT 1" will be hung.
src/context/pool_session_context.c | 19 +++++++++++++++++++
src/include/context/pool_session_context.h | 5 +++--
src/query_cache/pool_memqcache.c | 11 ++++++++++-
3 files changed, 32 insertions(+), 3 deletions(-)
diff --git a/src/context/pool_session_context.c b/src/context/pool_session_context.c
index b63b8ca84..79384d3f3 100644
--- a/src/context/pool_session_context.c
+++ b/src/context/pool_session_context.c
@@ -1499,6 +1499,25 @@ POOL_PENDING_MESSAGE *pool_pending_message_find_lastest_by_query_context(POOL_QU
return NULL;
}
+/*
+ * Get target backend id from pending message assuming that the destination for
+ * the pending message is one of primary or standby node.
+ */
+int pool_pending_message_get_target_backend_id(POOL_PENDING_MESSAGE *msg)
+{
+ int backend_id = -1;
+
+ if (msg->node_ids[0] != -1)
+ backend_id = msg->node_ids[0];
+ else if (msg->node_ids[1] != -1)
+ backend_id = msg->node_ids[1];
+ else
+ ereport(ERROR,
+ (errmsg("pool_pending_message_get_target_backend_id: no target backend id found")));
+
+ return backend_id;
+}
+
/*
* Dump whole pending message list
*/
diff --git a/src/include/context/pool_session_context.h b/src/include/context/pool_session_context.h
index 2956b1d15..b0bec425c 100644
--- a/src/include/context/pool_session_context.h
+++ b/src/include/context/pool_session_context.h
@@ -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-2018 PgPool Global Development Group
*
* Permission to use, copy, modify, and distribute this software and
* its documentation for any purpose and without fee is hereby
@@ -288,7 +288,7 @@ extern void pool_pending_messages_destroy(void);
extern POOL_PENDING_MESSAGE *pool_pending_message_create(char kind, int len, char *contents);
extern void pool_pending_message_free_pending_message(POOL_PENDING_MESSAGE *message);
extern void pool_pending_message_dest_set(POOL_PENDING_MESSAGE* message, POOL_QUERY_CONTEXT *query_context);
-void pool_pending_message_query_context_dest_set(POOL_PENDING_MESSAGE* message, POOL_QUERY_CONTEXT *query_context);
+extern void pool_pending_message_query_context_dest_set(POOL_PENDING_MESSAGE* message, POOL_QUERY_CONTEXT *query_context);
extern void pool_pending_message_query_set(POOL_PENDING_MESSAGE* message, POOL_QUERY_CONTEXT *query_context);
extern void pool_pending_message_add(POOL_PENDING_MESSAGE* message);
extern POOL_PENDING_MESSAGE *pool_pending_message_head_message(void);
@@ -303,6 +303,7 @@ extern bool pool_pending_message_exists(void);
extern const char *pool_pending_message_type_to_string(POOL_MESSAGE_TYPE type);
extern void pool_check_pending_message_and_reply(POOL_MESSAGE_TYPE type, char kind);
extern POOL_PENDING_MESSAGE *pool_pending_message_find_lastest_by_query_context(POOL_QUERY_CONTEXT *qc);
+extern int pool_pending_message_get_target_backend_id(POOL_PENDING_MESSAGE *msg);
extern void dump_pending_message(void);
extern void pool_set_major_version(int major);
extern void pool_set_minor_version(int minor);
diff --git a/src/query_cache/pool_memqcache.c b/src/query_cache/pool_memqcache.c
index ce91f2b99..fbf2f655a 100644
--- a/src/query_cache/pool_memqcache.c
+++ b/src/query_cache/pool_memqcache.c
@@ -3,7 +3,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-2018 PgPool Global Development Group
*
* Permission to use, copy, modify, and distribute this software and
* its documentation for any purpose and without fee is hereby
@@ -3980,7 +3980,16 @@ static void inject_cached_message(POOL_CONNECTION *backend, char *qcache, int qc
msg = pool_pending_message_find_lastest_by_query_context(query_context);
if (msg)
+ {
+ /*
+ * If pending message found, we should extract target backend from it
+ */
+ int backend_id;
+
+ backend_id = pool_pending_message_get_target_backend_id(msg);
+ backend = CONNECTION(session_context->backend, backend_id);
timeout = -1;
+ }
else
timeout = 0;
[parent: f7466f143785]