Fix bug #303.
authorTatsuo Ishii <ishii@postgresql.org>
Thu, 3 Aug 2017 02:52:24 +0000 (11:52 +0900)
committerTatsuo Ishii <ishii@postgresql.org>
Thu, 3 Aug 2017 04:52:07 +0000 (13:52 +0900)
When failover is triggered by worker process, it is possible that
wrong DB node could failover. This is due to the db_node_id member in
the POLL_CONNECTION structure is not initialized in the process (in
child process the member is properly initialized). To solve the
problem, add new function pool_set_db_node_id() to set the structure
member variable and call it inside
make_persistent_db_connection(). For this purpose also the new
parameter "db_node_id" is added to make_persistent_db_connection and
friends.

src/include/pool.h
src/include/utils/pool_stream.h
src/main/pgpool_main.c
src/protocol/child.c
src/streaming_replication/pool_worker_child.c
src/utils/pool_stream.c

index f618435bf25a94b15285de436f9c01ac4413d5c8..b7dcafb28603e278ffa8d3dc9ffe848cf702013d 100644 (file)
@@ -608,9 +608,9 @@ extern POOL_STATUS OneNode_do_command(POOL_CONNECTION *frontend, POOL_CONNECTION
 
 /* child.c */
 extern POOL_CONNECTION_POOL_SLOT *make_persistent_db_connection(
-       char *hostname, int port, char *dbname, char *user, char *password, bool retry);
+       int db_node_id, char *hostname, int port, char *dbname, char *user, char *password, bool retry);
 extern POOL_CONNECTION_POOL_SLOT *make_persistent_db_connection_noerror(
-    char *hostname, int port, char *dbname, char *user, char *password, bool retry);
+    int db_node_id, char *hostname, int port, char *dbname, char *user, char *password, bool retry);
 extern void discard_persistent_db_connection(POOL_CONNECTION_POOL_SLOT *cp);
 
 /* define pool_system.c */
index 22380f5bee2ce9515ce1944d173a96a0a78cb735..0c7da16195e53ef86ad44b89e56f1c6fb38554ad 100644 (file)
@@ -6,7 +6,7 @@
  * pgpool: a language independent connection pool server for PostgreSQL 
  * written by Tatsuo Ishii
  *
- * Copyright (c) 2003-2013     PgPool Global Development Group
+ * Copyright (c) 2003-2017     PgPool Global Development Group
  *
  * Permission to use, copy, modify, and distribute this software and
  * its documentation for any purpose and without fee is hereby
@@ -63,5 +63,6 @@ extern void pool_pop(POOL_CONNECTION *cp, int *len);
 extern int pool_stacklen(POOL_CONNECTION *cp);
 extern void pool_set_nonblock(int fd);
 extern void pool_unset_nonblock(int fd);
+extern void pool_set_db_node_id(POOL_CONNECTION *con, int db_node_id);
 
 #endif /* POOL_STREAM_H */
index b8d1dac6a6bff96f49b64e0ca5c9239776da8163..e41077adb1e0379f56c61a1057ba93f783de91a7 100644 (file)
@@ -2038,7 +2038,7 @@ do_health_check(bool use_template_db, volatile int *health_check_node_id)
                ereport(DEBUG1,
                        (errmsg("Trying to make persistent DB connection to backend node %d having status %d", i, bkinfo->backend_status)));
 
-               slot = make_persistent_db_connection(bkinfo->backend_hostname,
+               slot = make_persistent_db_connection(i, bkinfo->backend_hostname,
                                                                                         bkinfo->backend_port,
                                                                                         dbname,
                                                                                         pool_config->health_check_user,
@@ -2586,7 +2586,7 @@ static bool
 
        *is_standby = false;
 
-       s = make_persistent_db_connection_noerror(bkinfo->backend_hostname,
+       s = make_persistent_db_connection_noerror(backend_no, bkinfo->backend_hostname,
                                                                                  bkinfo->backend_port,
                                                                                  "postgres",
                                                                                  pool_config->sr_check_user,
index 8c164b8071406b365998342910982a470b0b6b66..2e686186348b0c92bcf095e7df692f6a3402b4f8 100644 (file)
@@ -807,6 +807,8 @@ void cancel_request(CancelPacket *sp)
                if (con == NULL)
                        return;
 
+               pool_set_db_node_id(con, i);
+
                len = htonl(sizeof(len) + sizeof(CancelPacket));
                pool_write(con, &len, sizeof(len));
 
@@ -890,7 +892,7 @@ static POOL_CONNECTION_POOL *connect_backend(StartupPacket *sp, POOL_CONNECTION
                        {
 
                                /* set DB node id */
-                               CONNECTION(backend, i)->db_node_id = i;
+                               pool_set_db_node_id(CONNECTION(backend, i), i);
 
                                /* mark this is a backend connection */
                                CONNECTION(backend, i)->isbackend = 1;
@@ -1194,7 +1196,7 @@ void child_exit(int code)
  * create a persistent connection
  */
 POOL_CONNECTION_POOL_SLOT *make_persistent_db_connection(
-       char *hostname, int port, char *dbname, char *user, char *password, bool retry)
+       int db_node_id, char *hostname, int port, char *dbname, char *user, char *password, bool retry)
 {
        POOL_CONNECTION_POOL_SLOT *cp;
        int fd;
@@ -1238,6 +1240,8 @@ POOL_CONNECTION_POOL_SLOT *make_persistent_db_connection(
        cp->con = pool_open(fd,true);
        cp->closetime = 0;
        cp->con->isbackend = 1;
+       pool_set_db_node_id(cp->con, db_node_id);
+
        pool_ssl_negotiate_clientserver(cp->con);
 
        /*
@@ -1314,17 +1318,18 @@ POOL_CONNECTION_POOL_SLOT *make_persistent_db_connection(
  * make_persistent_db_connection() which does not ereports in case of an error
  */
 POOL_CONNECTION_POOL_SLOT *make_persistent_db_connection_noerror(
-                        char *hostname, int port, char *dbname, char *user, char *password, bool retry)
+       int db_node_id, char *hostname, int port, char *dbname, char *user, char *password, bool retry)
 {
     POOL_CONNECTION_POOL_SLOT *slot = NULL;
     MemoryContext oldContext = CurrentMemoryContext;
     PG_TRY();
     {
-        slot = make_persistent_db_connection(hostname,
-                                                 port,
-                                                 dbname,
-                                                 user,
-                                                 password, retry);
+        slot = make_persistent_db_connection(db_node_id,
+                                                                                        hostname,
+                                                                                        port,
+                                                                                        dbname,
+                                                                                        user,
+                                                                                        password, retry);
     }
     PG_CATCH();
     {
@@ -1826,7 +1831,7 @@ static void init_system_db_connection(void)
 
                }
 
-               system_db_info->connection = make_persistent_db_connection(pool_config->system_db_hostname,
+               system_db_info->connection = make_persistent_db_connection(-1, pool_config->system_db_hostname,
                                                                                                                                   pool_config->system_db_port,
                                                                                                                                   pool_config->system_db_dbname,
                                                                                                                                   pool_config->system_db_user,
index 1f2cc33ae9ed1c056e6c5678c22bcaa7dab3bbbc..2b09d6a5fdb1900f62db441856e71751ae5069cb 100644 (file)
@@ -202,7 +202,7 @@ static void establish_persistent_connection(void)
                if (slots[i] == NULL)
                {
                 bkinfo = pool_get_node_info(i);
-                slots[i] = make_persistent_db_connection_noerror(bkinfo->backend_hostname,
+                slots[i] = make_persistent_db_connection_noerror(i, bkinfo->backend_hostname,
                                                                                          bkinfo->backend_port,
                                                                                          "postgres",
                                                                                          pool_config->sr_check_user,
index cf1e5a5a2bc9ef6ac8a9cc002e372582948b0cae..af49bcfa221df09dbed7e2ba73c24049ef44a34b 100644 (file)
@@ -850,6 +850,16 @@ char *pool_read_string(POOL_CONNECTION *cp, int *len, int line)
        return cp->sbuf;
 }
 
+/*
+ * Set db node id to connection.
+ */
+void pool_set_db_node_id(POOL_CONNECTION *con, int db_node_id)
+{
+       if (!con)
+               return;
+       con->db_node_id = db_node_id;
+}
+
 /*
  * returns the byte length of str, including \0, no more than upper.
  * if encountered \0, flag is set to non 0.