Fix errors/hung up when load_balance_mode is off.
authorTatsuo Ishii <ishii@sraoss.co.jp>
Tue, 2 Apr 2024 10:30:27 +0000 (19:30 +0900)
committerTatsuo Ishii <ishii@sraoss.co.jp>
Tue, 2 Apr 2024 10:30:27 +0000 (19:30 +0900)
Commit: 3f3c1656 Fix statement_level_load_balance with BEGIN etc.

brought errors/hung up when load_balance_mode is off, primary node id
is not 0 and queries are BEGIN etc.

pool_setall_node_to_be_sent() checked if the node is primary. If not,
just returned with empty where_to_send map which makes
set_vrtual_main_node() not to set
query_context->virtual_main_node_id. As a result, MAIN_NODE macro
(it's actually pool_virtual_main_db_node_id()) returns
REAL_MAIN_NODE_ID, which is 0 if node 0 is alive (this should have
been primary node id).

Following simple test reveals the bug.

(1) create a two-node cluster using pgpool_setup

(2) shutdown node 0 and recover node 1 (pcp_recovery_node 0). This
makes node 0 to be standby, node 1 to be primary.

(3) add followings to pgpool.conf and restart whole cluster.

load_balance_mode = off
backend_weight1 = 0

(4) type "begin" from psql. It gets stuck.

Bug found and analyzed by Emond Papegaaij.
Discussion: https://www.pgpool.net/pipermail/pgpool-general/2024-March/009113.html
Backpatch-through: v4.1

src/context/pool_query_context.c

index 3381fb42a8df9a7b9c3e237b95952ff4fed221d3..eea355425e70b95a260b99d3a52f4b67595d8ea2 100644 (file)
@@ -244,20 +244,23 @@ pool_setall_node_to_be_sent(POOL_QUERY_CONTEXT * query_context)
                        {
                                /*
                                 * If load balance mode is disabled, only send to the primary node.
-                                * or send to the main node if primary node does not exist.
+                                * If primary node does not exist, send to the main node.
                                 */
                                if (!pool_config->load_balance_mode)
                                {
                                        if (i == PRIMARY_NODE_ID ||
                                                (PRIMARY_NODE_ID < 0 && MAIN_NODE_ID == i))
+                                       {
                                                query_context->where_to_send[i] = true;
-                                       break;
+                                               break;
+                                       }
+                                       continue;
                                }
                                else
                                        /*
                                         * If the node is not primary node nor load balance node,
-                                        * there's no point to send query except statement load
-                                        * balance is enabled.
+                                        * there's no point to send query except statement level
+                                        * load balance is enabled.
                                         */
                                        if (!pool_config->statement_level_load_balance &&
                                                i != PRIMARY_NODE_ID && i != sc->load_balance_node_id)