pgpool2.git / summary / log / commit / refs

commit    ab3d0ea047e0c2afe01090141da7d4e828cedb51
Author:   Tatsuo Ishii <ishii at sraoss.co.jp>
Date:     Tue Aug 23 04:36:57 2011 +0000

    Fix segfault in following scenario:
    - Add new node in pgpool.conf.
    - Reload pgpool.conf. At this point new is in down status.
    - Connect using psql and do some query.
    - Failback the new node.
    - Do another query and pgpool child segfaults.
    - Worker child segfaults
    
    To fix this,
    
    - Initialize private_backend_status with MAX_NUM_BACKENDS, rather than
      NUM_BACKENDS.
    
    - Add signal handler to worker process and pcp child process. When a
      failback event occurs, pgpool main sends SIGUSR1 to those processes.
    
    - Those processes set restart request flag and restart whenever
      convenient.
    
    Fix suggested by Gurjeet Singh.


child.c | 21 ++++++++------------- main.c | 19 ++++++++++++++++++- pcp_child.c | 24 +++++++++++++++++++++++- pool.h | 3 +++ pool_worker_child.c | 17 ++++++++++++++++- 5 files changed, 68 insertions(+), 16 deletions(-) diff --git a/child.c b/child.c index b9e62bb69..2aacea4e9 100644 --- a/child.c +++ b/child.c @@ -74,8 +74,6 @@ static void init_system_db_connection(void); static bool connect_using_existing_connection(POOL_CONNECTION *frontend, POOL_CONNECTION_POOL *backend, StartupPacket *sp); -static void initialize_private_backend_status(void); - /* * non 0 means SIGTERM(smart shutdown) or SIGINT(fast shutdown) has arrived */ @@ -91,11 +89,6 @@ char remote_ps_data[NI_MAXHOST]; /* used for set_ps_display */ volatile sig_atomic_t got_sighup = 0; -/* - * Private copy of backend status - */ -static BACKEND_STATUS private_backend_status[MAX_NUM_BACKENDS]; - /* * child main loop */ @@ -137,7 +130,7 @@ void do_child(int unix_fd, int inet_fd) #endif /* Initialize my backend status */ - initialize_private_backend_status(); + pool_initialize_private_backend_status(); /* Initialize per process context */ pool_init_process_context(); @@ -273,15 +266,15 @@ void do_child(int unix_fd, int inet_fd) */ /* Check if restart request is set because of failback event - * happend. If so, exit myself with exit code 1 to be - * restarted by pgpool parent. + * happend. If so, close idle connections to backend and make + * a new copy of backend status. */ if (pool_get_my_process_info()->need_to_restart) { pool_log("do_child: failback event found. discard existing connections"); pool_get_my_process_info()->need_to_restart = 0; close_idle_connection(0); - initialize_private_backend_status(); + pool_initialize_private_backend_status(); } /* @@ -1961,11 +1954,13 @@ static void init_system_db_connection(void) * We copy the backend status to private area so that * they are not changed while I am alive. */ -static void initialize_private_backend_status(void) +void pool_initialize_private_backend_status(void) { int i; - for (i=0;i<NUM_BACKENDS;i++) + pool_debug("pool_initialize_private_backend_status: initialize backend status"); + + for (i=0;i<MAX_NUM_BACKENDS;i++) { private_backend_status[i] = BACKEND_INFO(i).backend_status; /* my_backend_status is referred to by VALID_BACKEND macro. */ diff --git a/main.c b/main.c index b1164d193..a90121b05 100644 --- a/main.c +++ b/main.c @@ -130,6 +130,11 @@ static struct sockaddr_un pcp_un_addr; /* unix domain socket path for PCP */ ProcessInfo *process_info; /* Per child info table on shmem */ +/* + * Private copy of backend status + */ +BACKEND_STATUS private_backend_status[MAX_NUM_BACKENDS]; + /* * shmem connection info table * this is a three dimension array. i.e.: @@ -510,7 +515,7 @@ int main(int argc, char **argv) * (get_next_master_node() uses VALID_BACKEND) */ - for (i=0;i<NUM_BACKENDS;i++) + for (i=0;i<MAX_NUM_BACKENDS;i++) { my_backend_status[i] = &(BACKEND_INFO(i).backend_status); } @@ -1798,6 +1803,11 @@ static void failover(void) { process_info[i].need_to_restart = 1; } + + /* + * Send restart request to worker child. + */ + kill(worker_pid, SIGUSR1); } if (Req_info->kind == NODE_UP_REQUEST) @@ -1826,6 +1836,13 @@ static void failover(void) * failover/failback done */ kill(pcp_pid, SIGUSR2); + + sleep(1); + + /* + * Send restart request to pcp child. + */ + kill(pcp_pid, SIGUSR1); } /* diff --git a/pcp_child.c b/pcp_child.c index 6a3eb3f4c..621cbf93f 100644 --- a/pcp_child.c +++ b/pcp_child.c @@ -69,6 +69,7 @@ static void unset_nonblock(int fd); static int user_authenticate(char *buf, char *passwd_file, char *salt, int salt_len); static RETSIGTYPE wakeup_handler(int sig); static RETSIGTYPE reload_config_handler(int sig); +static RETSIGTYPE restart_handler(int sig); static int pool_detach_node(int node_id, bool gracefully); static int pool_promote_node(int node_id, bool gracefully); @@ -77,6 +78,16 @@ extern char **myargv; static volatile sig_atomic_t pcp_got_sighup = 0; volatile sig_atomic_t pcp_wakeup_request = 0; +static volatile sig_atomic_t pcp_restart_request = 0; + +#define CHECK_RESTART_REQUEST \ + do { \ + if (pcp_restart_request) \ + { \ + pool_log("pcp child process received restart request"); \ + exit(1); \ + } \ + } while (0) void pcp_do_child(int unix_fd, int inet_fd, char *pcp_conf_file) @@ -108,11 +119,14 @@ pcp_do_child(int unix_fd, int inet_fd, char *pcp_conf_file) signal(SIGHUP, reload_config_handler); signal(SIGQUIT, die); signal(SIGCHLD, SIG_DFL); - signal(SIGUSR1, SIG_DFL); + signal(SIGUSR1, restart_handler); signal(SIGUSR2, wakeup_handler); signal(SIGPIPE, SIG_IGN); signal(SIGALRM, SIG_IGN); + /* Initialize my backend status */ + pool_initialize_private_backend_status(); + /* Initialize process context */ pool_init_process_context(); @@ -120,6 +134,8 @@ pcp_do_child(int unix_fd, int inet_fd, char *pcp_conf_file) { errno = 0; + CHECK_RESTART_REQUEST; + if (frontend == NULL) { frontend = pcp_do_accept(unix_fd, inet_fd); @@ -1056,6 +1072,12 @@ wakeup_handler(int sig) pcp_wakeup_request = 1; } +static RETSIGTYPE +restart_handler(int sig) +{ + pcp_restart_request = 1; +} + static PCP_CONNECTION * pcp_do_accept(int unix_fd, int inet_fd) { diff --git a/pool.h b/pool.h index 05201c368..6ea09df9e 100644 --- a/pool.h +++ b/pool.h @@ -407,6 +407,8 @@ extern volatile sig_atomic_t exit_request; #define QUERY_STRING_BUFFER_LEN 1024 extern char query_string_buffer[]; /* last query string sent to simpleQuery() */ +extern BACKEND_STATUS private_backend_status[MAX_NUM_BACKENDS]; + /* * public functions */ @@ -569,6 +571,7 @@ extern int wait_connection_closed(void); /* child.c */ extern void cancel_request(CancelPacket *sp); extern void check_stop_request(void); +extern void pool_initialize_private_backend_status(void); /* pool_process_query.c */ extern void reset_variables(void); diff --git a/pool_worker_child.c b/pool_worker_child.c index eade54338..0d084f373 100644 --- a/pool_worker_child.c +++ b/pool_worker_child.c @@ -63,6 +63,7 @@ extern char **myargv; char remote_ps_data[NI_MAXHOST]; /* used for set_ps_display */ static POOL_CONNECTION_POOL_SLOT *slots[MAX_NUM_BACKENDS]; static volatile sig_atomic_t reload_config_request = 0; +static volatile sig_atomic_t restart_request = 0; static void establish_persistent_connection(void); static void discard_persistent_connection(void); @@ -78,6 +79,10 @@ static void reload_config(void); { \ reload_config(); \ reload_config_request = 0; \ + } else if (restart_request) \ + { \ + pool_log("worker process received restart request"); \ + exit(1); \ } \ } while (0) @@ -99,10 +104,13 @@ void do_worker_child(void) signal(SIGHUP, reload_config_handler); signal(SIGQUIT, my_signal_handler); signal(SIGCHLD, SIG_IGN); - signal(SIGUSR1, SIG_IGN); + signal(SIGUSR1, my_signal_handler); signal(SIGUSR2, SIG_IGN); signal(SIGPIPE, SIG_IGN); + /* Initialize my backend status */ + pool_initialize_private_backend_status(); + /* Initialize per process context */ pool_init_process_context(); @@ -341,6 +349,13 @@ static RETSIGTYPE my_signal_handler(int sig) case SIGINT: case SIGQUIT: exit(0); + break; + + /* Failback or new node added */ + case SIGUSR1: + restart_request = 1; + break; + default: exit(1); break; [parent: e2af315e8394]