pgpool2.git / summary / log / commit / refs

commit    9c5ab9831158cd6a38271f8db3bee7a505cdcd0f
Author:   Tatsuo Ishii <ishii@sraoss.co.jp>
Date:     Wed Jan 26 23:12:09 2022 +0000

    Fix pcp_node_info hang when pgpool cannot connect to backend.
    
    Since 4.3 pcp_node_info (and show pool_nodes) try to connect to all
    backend to obtain real-time and actual backend status.  In certain
    cases connect(2) fails and keeps on retrying, and the command does not
    complete. To fix this, following modifications are made:
    
    1) db_node_status(), which is responsible for probing backend is alive
    or not, tries to connect backend with "connect_timeout" parameter
    enabled. The timeout is taken from "connect_timeout" parameter of
    pgpool.conf. If connect_timeout in pgpool.conf disabled (i.e. set to
    0), the timeout parameter is not set. In this case the command will
    not complete.
    
    2) db_node_role(), which is responsible for fetching backend role (primary
    or standby), does to not retry in connecting to backend using
    make_persistent_db_connection_noerror().
    
    3) inform_node_info(), which is the workhorse of pcp_node_info, tries
    to fetch info (thus calling db_node_status() and db_node_role()) only
    for specified backend. Before it unconditionally access all backend.
    
    Problem reported and patch reviewed by Emond Papegaaij.
    
    Discussion: https://www.pgpool.net/pipermail/pgpool-general/2022-January/008042.html


src/include/utils/pool_process_reporting.h | 4 ++-- src/pcp_con/pcp_worker.c | 6 ++--- src/utils/pool_process_reporting.c | 37 +++++++++++++++++++++++------- 3 files changed, 34 insertions(+), 13 deletions(-) diff --git a/src/include/utils/pool_process_reporting.h b/src/include/utils/pool_process_reporting.h index 511ae72d7..daed4e62d 100644 --- a/src/include/utils/pool_process_reporting.h +++ b/src/include/utils/pool_process_reporting.h @@ -6,7 +6,7 @@ * pgpool: a language independent connection pool server for PostgreSQL * written by Tatsuo Ishii * - * Copyright (c) 2003-2021 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 @@ -32,7 +32,7 @@ extern void send_complete_and_ready(POOL_CONNECTION * frontend, POOL_CONNECTION_ extern POOL_REPORT_CONFIG * get_config(int *nrows); extern POOL_REPORT_POOLS * get_pools(int *nrows); extern POOL_REPORT_PROCESSES * get_processes(int *nrows); -extern POOL_REPORT_NODES * get_nodes(int *nrows); +extern POOL_REPORT_NODES * get_nodes(int *nrows, int node_id); extern POOL_REPORT_VERSION * get_version(void); extern POOL_HEALTH_CHECK_STATS *get_health_check_stats(int *nrows); extern POOL_BACKEND_STATS *get_backend_stats(int *nrows); diff --git a/src/pcp_con/pcp_worker.c b/src/pcp_con/pcp_worker.c index 832884aef..f15a3878a 100644 --- a/src/pcp_con/pcp_worker.c +++ b/src/pcp_con/pcp_worker.c @@ -4,7 +4,7 @@ * pgpool: a language independent connection pool server for PostgreSQL * written by Tatsuo Ishii * - * Copyright (c) 2003-2021 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 @@ -854,7 +854,7 @@ inform_node_info(PCP_CONNECTION * frontend, char *buf) /* Finally, indicate that all data is sent */ char fin_code[] = "CommandComplete"; - nodes = get_nodes(&nrows); + nodes = get_nodes(&nrows, node_id); if (node_id == -1) { @@ -887,7 +887,7 @@ inform_node_info(PCP_CONNECTION * frontend, char *buf) BackendInfo *bi = NULL; SERVER_ROLE role; - if (node_id != -1 && node_id != atoi(nodes[i].node_id)) + if (node_id != -1 && node_id != i) continue; bi = pool_get_node_info(i); diff --git a/src/utils/pool_process_reporting.c b/src/utils/pool_process_reporting.c index c1df7683f..a085963b5 100644 --- a/src/utils/pool_process_reporting.c +++ b/src/utils/pool_process_reporting.c @@ -5,7 +5,7 @@ * pgpool: a language independent connection pool server for PostgreSQL * written by Tatsuo Ishii * - * Copyright (c) 2003-2021 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 @@ -1291,9 +1291,10 @@ config_reporting(POOL_CONNECTION * frontend, POOL_CONNECTION_POOL * backend) /* * for SHOW pool_nodes + * If node_id is -1, get all node info. */ POOL_REPORT_NODES * -get_nodes(int *nrows) +get_nodes(int *nrows, int node_id) { int i; POOL_REPORT_NODES *nodes = palloc(NUM_BACKENDS * sizeof(POOL_REPORT_NODES)); @@ -1303,6 +1304,9 @@ get_nodes(int *nrows) for (i = 0; i < NUM_BACKENDS; i++) { + if (node_id != -1 && node_id != i) + continue; + bi = pool_get_node_info(i); snprintf(nodes[i].node_id, POOLCONFIG_MAXIDLEN, "%d", i); @@ -1319,6 +1323,8 @@ get_nodes(int *nrows) snprintf(nodes[i].delay, POOLCONFIG_MAXWEIGHTLEN, "%d", 0); + snprintf(nodes[i].pg_status, POOLCONFIG_MAXSTATLEN, "%s", db_node_status(i)); + if (STREAM) { if (i == REAL_PRIMARY_NODE_ID) @@ -1330,7 +1336,15 @@ get_nodes(int *nrows) snprintf(nodes[i].role, POOLCONFIG_MAXWEIGHTLEN, "%s", "standby"); snprintf(nodes[i].delay, POOLCONFIG_MAXWEIGHTLEN, UINT64_FORMAT, bi->standby_delay); } - snprintf(nodes[i].pg_role, POOLCONFIG_MAXWEIGHTLEN, "%s", db_node_role(i)); + + if (!strcmp(nodes[i].pg_status, "up")) + { + snprintf(nodes[i].pg_role, POOLCONFIG_MAXWEIGHTLEN, "%s", db_node_role(i)); + } + else + { + snprintf(nodes[i].pg_role, POOLCONFIG_MAXWEIGHTLEN, "unknown"); + } } else { @@ -1342,8 +1356,6 @@ get_nodes(int *nrows) snprintf(nodes[i].pg_role, POOLCONFIG_MAXWEIGHTLEN, "%s", nodes[i].role); } - snprintf(nodes[i].pg_status, POOLCONFIG_MAXSTATLEN, "%s", db_node_status(i)); - /* status last changed */ localtime_r(&bi->status_changed_time, &tm); strftime(nodes[i].last_status_change, POOLCONFIG_MAXDATELEN, "%F %T", &tm); @@ -1390,7 +1402,7 @@ nodes_reporting(POOL_CONNECTION * frontend, POOL_CONNECTION_POOL * backend) POOL_REPORT_NODES *nodes; num_fields = sizeof(field_names) / sizeof(char *); - nodes = get_nodes(&nrows); + nodes = get_nodes(&nrows, -1); send_row_description_and_data_rows(frontend, backend, num_fields, field_names, offsettbl, (char *)nodes, sizeof(POOL_REPORT_NODES), nrows); @@ -2222,7 +2234,8 @@ char *db_node_status(int node) BackendInfo *bkinfo; int i; char portstr[32]; -#define PARAMS_ARRAY_SIZE 7 + char timeoutstr[32]; +#define PARAMS_ARRAY_SIZE 8 const char *keywords[PARAMS_ARRAY_SIZE]; const char *values[PARAMS_ARRAY_SIZE]; PGPing ret; @@ -2263,6 +2276,14 @@ char *db_node_status(int node) values[i] = portstr; i++; + if (pool_config->connect_timeout > 0) + { + keywords[i] = "connect_timeout"; + snprintf(timeoutstr, sizeof(timeoutstr), "%d", pool_config->connect_timeout / 1000); + values[i] = timeoutstr; + i++; + } + keywords[i] = NULL; values[i] = NULL; @@ -2313,7 +2334,7 @@ char *db_node_role(int node) * Establish connection to backend. */ slots[node] = make_persistent_db_connection_noerror(node, host, port, dbname, user, - password ? password : "", true); + password ? password : "", false); if (slots[node] == NULL) return "unknown"; [parent: 6b49152fd7ca]