From be2e8ff0ef7cfe461a9cbc5ee10b2d1f63443bf8 Mon Sep 17 00:00:00 2001 From: Tatsuo Ishii Date: Thu, 3 Aug 2017 11:52:24 +0900 Subject: [PATCH] Fix bug #303. 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 | 4 ++-- src/include/utils/pool_stream.h | 3 ++- src/main/pgpool_main.c | 4 ++-- src/protocol/child.c | 23 +++++++++++-------- src/streaming_replication/pool_worker_child.c | 2 +- src/utils/pool_stream.c | 10 ++++++++ 6 files changed, 31 insertions(+), 15 deletions(-) diff --git a/src/include/pool.h b/src/include/pool.h index f618435bf..b7dcafb28 100644 --- a/src/include/pool.h +++ b/src/include/pool.h @@ -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 */ diff --git a/src/include/utils/pool_stream.h b/src/include/utils/pool_stream.h index 22380f5be..0c7da1619 100644 --- a/src/include/utils/pool_stream.h +++ b/src/include/utils/pool_stream.h @@ -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 */ diff --git a/src/main/pgpool_main.c b/src/main/pgpool_main.c index b8d1dac6a..e41077adb 100644 --- a/src/main/pgpool_main.c +++ b/src/main/pgpool_main.c @@ -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, diff --git a/src/protocol/child.c b/src/protocol/child.c index 8c164b807..2e6861863 100644 --- a/src/protocol/child.c +++ b/src/protocol/child.c @@ -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, diff --git a/src/streaming_replication/pool_worker_child.c b/src/streaming_replication/pool_worker_child.c index 1f2cc33ae..2b09d6a5f 100644 --- a/src/streaming_replication/pool_worker_child.c +++ b/src/streaming_replication/pool_worker_child.c @@ -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, diff --git a/src/utils/pool_stream.c b/src/utils/pool_stream.c index cf1e5a5a2..af49bcfa2 100644 --- a/src/utils/pool_stream.c +++ b/src/utils/pool_stream.c @@ -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. -- 2.39.5