/* * Read the status file */ static int read_status_file(void) { FILE *fd; char fnamebuf[POOLMAXPATHLEN]; int i; snprintf(fnamebuf, sizeof(fnamebuf), "%s/%s", pool_config->logdir, STATUS_FILE_NAME); fd = fopen(fnamebuf, "r"); if (!fd) { pool_log("Backend status file %s does not exist", fnamebuf); return -1; } if (fread(&backend_rec, 1, sizeof(backend_rec), fd) <= 0) { pool_error("Could not read backend status file as %s. reason: %s", fnamebuf, strerror(errno)); fclose(fd); return -1; } fclose(fd); for (i=0;i< pool_config->backend_desc->num_backends;i++) { if (backend_rec.status[i] == CON_DOWN) BACKEND_INFO(i).backend_status = CON_DOWN; else BACKEND_INFO(i).backend_status = CON_CONNECT_WAIT; } return 0; }
/* * Return true if multiple nodes are targets */ bool pool_multi_node_to_be_sent(POOL_QUERY_CONTEXT *query_context) { int i; int cnt = 0; if (!query_context) { pool_error("pool_multi_node_to_be_sent: no query context"); return false; } for (i=0;i<NUM_BACKENDS;i++) { if (((BACKEND_INFO(i)).backend_status == CON_UP || BACKEND_INFO((i)).backend_status == CON_CONNECT_WAIT) && query_context->where_to_send[i]) { cnt++; if (cnt > 1) { return true; } } } return false; }
/* * Write the pid file */ static int write_status_file(void) { FILE *fd; char fnamebuf[POOLMAXPATHLEN]; int i; snprintf(fnamebuf, sizeof(fnamebuf), "%s/%s", pool_config->logdir, STATUS_FILE_NAME); fd = fopen(fnamebuf, "w"); if (!fd) { pool_error("Could not open status file %s", fnamebuf); return -1; } memset(&backend_rec, 0, sizeof(backend_rec)); for (i=0;i< pool_config->backend_desc->num_backends;i++) { backend_rec.status[i] = BACKEND_INFO(i).backend_status; } if (fwrite(&backend_rec, 1, sizeof(backend_rec), fd) <= 0) { pool_error("Could not write backend status file as %s. reason: %s", fnamebuf, strerror(errno)); fclose(fd); return -1; } fclose(fd); return 0; }
/* * Read the status file */ static int read_status_file(void) { FILE *fd; char fnamebuf[POOLMAXPATHLEN]; int i; bool someone_wakeup = false; snprintf(fnamebuf, sizeof(fnamebuf), "%s/%s", pool_config->logdir, STATUS_FILE_NAME); fd = fopen(fnamebuf, "r"); if (!fd) { pool_log("Backend status file %s does not exist", fnamebuf); return -1; } if (fread(&backend_rec, 1, sizeof(backend_rec), fd) != sizeof(backend_rec)) { pool_error("Could not read backend status file as %s. reason: %s", fnamebuf, strerror(errno)); fclose(fd); return -1; } fclose(fd); for (i=0;i< pool_config->backend_desc->num_backends;i++) { if (backend_rec.status[i] == CON_DOWN) BACKEND_INFO(i).backend_status = CON_DOWN; else { BACKEND_INFO(i).backend_status = CON_CONNECT_WAIT; someone_wakeup = true; } } /* * If no one woke up, we regard the status file bogus */ if (someone_wakeup == false) { for (i=0;i< pool_config->backend_desc->num_backends;i++) { BACKEND_INFO(i).backend_status = CON_CONNECT_WAIT; } } return 0; }
/* * get node information specified by node_number */ BackendInfo * pool_get_node_info(int node_number) { if (node_number >= NUM_BACKENDS) return NULL; return &BACKEND_INFO(node_number); }
/* * Select load balancing node */ int select_load_balancing_node(void) { int selected_slot; double total_weight,r; int i; /* choose a backend in random manner with weight */ selected_slot = MASTER_NODE_ID; total_weight = 0.0; for (i=0;i<NUM_BACKENDS;i++) { if (VALID_BACKEND(i)) { total_weight += BACKEND_INFO(i).backend_weight; } } #if defined(sun) || defined(__sun) r = (((double)rand())/RAND_MAX) * total_weight; #else r = (((double)random())/RAND_MAX) * total_weight; #endif total_weight = 0.0; for (i=0;i<NUM_BACKENDS;i++) { if (VALID_BACKEND(i) && BACKEND_INFO(i).backend_weight > 0.0) { if(r >= total_weight) selected_slot = i; else break; total_weight += BACKEND_INFO(i).backend_weight; } } pool_debug("select_load_balancing_node: selected backend id is %d", selected_slot); return selected_slot; }
/* * Initialize my backend status and master node id. * We copy the backend status to private area so that * they are not changed while I am alive. */ void pool_initialize_private_backend_status(void) { int 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. */ my_backend_status[i] = &private_backend_status[i]; } my_master_node_id = REAL_MASTER_NODE_ID; }
/* * calculate next master node id */ static int get_next_master_node(void) { int i; for (i=0;i<pool_config->backend_desc->num_backends;i++) { /* * Do not use VALID_BACKEND macro in raw mode. * VALID_BACKEND return true only if the argument is master * node id. In other words, standby nodes are false. So need * to check backend status without VALID_BACKEND. */ if (RAW_MODE) { if (BACKEND_INFO(i).backend_status == CON_CONNECT_WAIT) break; } else if (VALID_BACKEND(i)) break; } return i; }
/* * create actual connections to backends */ static POOL_CONNECTION_POOL *new_connection(POOL_CONNECTION_POOL *p) { POOL_CONNECTION_POOL_SLOT *s; int active_backend_count = 0; int i; for (i=0;i<NUM_BACKENDS;i++) { pool_debug("new_connection: connecting %d backend", i); if (!VALID_BACKEND(i)) { pool_debug("new_connection: skipping slot %d because backend_status = %d", i, BACKEND_INFO(i).backend_status); continue; } s = malloc(sizeof(POOL_CONNECTION_POOL_SLOT)); if (s == NULL) { pool_error("new_connection: malloc() failed"); return NULL; } if (create_cp(s, i) == NULL) { /* connection failed. mark this backend down */ pool_error("new_connection: create_cp() failed"); /* If fail_over_on_backend_error is true, do failover. * Otherwise, just exit this session. */ if (pool_config->fail_over_on_backend_error) { notice_backend_error(i); } else { pool_log("new_connection: do not failover because fail_over_on_backend_error is off"); } child_exit(1); } p->info[i].create_time = time(NULL); p->slots[i] = s; if (pool_init_params(&s->con->params)) { return NULL; } BACKEND_INFO(i).backend_status = CON_UP; active_backend_count++; } if (active_backend_count > 0) { return p; } return NULL; }
POOL_REPORT_CONFIG* get_config(int *nrows) { int i, j; int len; /* * Report data buffer. * 128 is the max number of configuration items. * In addition, we need MAX_NUM_BACKENDS*4 * for backend descriptions. */ #define MAXITEMS (256 + MAX_NUM_BACKENDS*4) POOL_REPORT_CONFIG* status = malloc(MAXITEMS * sizeof(POOL_REPORT_CONFIG)); /* we initialize the array with NULL values so when looping * on it, we can use it as stop condition */ memset(status, 0, sizeof(POOL_REPORT_CONFIG) * MAXITEMS); i = 0; strncpy(status[i].name, "listen_addresses", POOLCONFIG_MAXNAMELEN); snprintf(status[i].value, POOLCONFIG_MAXVALLEN, "%s", pool_config->listen_addresses); strncpy(status[i].desc, "host name(s) or IP address(es) to listen to", POOLCONFIG_MAXDESCLEN); i++; strncpy(status[i].name, "port", POOLCONFIG_MAXNAMELEN); snprintf(status[i].value, POOLCONFIG_MAXVALLEN, "%d", pool_config->port); strncpy(status[i].desc, "pgpool accepting port number", POOLCONFIG_MAXDESCLEN); i++; strncpy(status[i].name, "socket_dir", POOLCONFIG_MAXNAMELEN); snprintf(status[i].value, POOLCONFIG_MAXVALLEN, "%s", pool_config->socket_dir); strncpy(status[i].desc, "pgpool socket directory", POOLCONFIG_MAXDESCLEN); i++; strncpy(status[i].name, "num_init_children", POOLCONFIG_MAXNAMELEN); snprintf(status[i].value, POOLCONFIG_MAXVALLEN, "%d", pool_config->num_init_children); strncpy(status[i].desc, "# of children initially pre-forked", POOLCONFIG_MAXDESCLEN); i++; strncpy(status[i].name, "child_life_time", POOLCONFIG_MAXNAMELEN); snprintf(status[i].value, POOLCONFIG_MAXVALLEN, "%d", pool_config->child_life_time); strncpy(status[i].desc, "if idle for this seconds, child exits", POOLCONFIG_MAXDESCLEN); i++; strncpy(status[i].name, "connection_life_time", POOLCONFIG_MAXNAMELEN); snprintf(status[i].value, POOLCONFIG_MAXVALLEN, "%d", pool_config->connection_life_time); strncpy(status[i].desc, "if idle for this seconds, connection closes", POOLCONFIG_MAXDESCLEN); i++; strncpy(status[i].name, "client_idle_limit", POOLCONFIG_MAXNAMELEN); snprintf(status[i].value, POOLCONFIG_MAXVALLEN, "%d", pool_config->client_idle_limit); strncpy(status[i].desc, "if idle for this seconds, child connection closes", POOLCONFIG_MAXDESCLEN); i++; strncpy(status[i].name, "child_max_connections", POOLCONFIG_MAXNAMELEN); snprintf(status[i].value, POOLCONFIG_MAXVALLEN, "%d", pool_config->child_max_connections); strncpy(status[i].desc, "if max_connections received, chile exits", POOLCONFIG_MAXDESCLEN); i++; strncpy(status[i].name, "max_pool", POOLCONFIG_MAXNAMELEN); snprintf(status[i].value, POOLCONFIG_MAXVALLEN, "%d", pool_config->max_pool); strncpy(status[i].desc, "max # of connection pool per child", POOLCONFIG_MAXDESCLEN); i++; strncpy(status[i].name, "authentication_timeout", POOLCONFIG_MAXNAMELEN); snprintf(status[i].value, POOLCONFIG_MAXVALLEN, "%d", pool_config->authentication_timeout); strncpy(status[i].desc, "maximum time in seconds to complete client authentication", POOLCONFIG_MAXNAMELEN); i++; strncpy(status[i].name, "logdir", POOLCONFIG_MAXNAMELEN); snprintf(status[i].value, POOLCONFIG_MAXVALLEN, "%s", pool_config->logdir); strncpy(status[i].desc, "PgPool status file logging directory", POOLCONFIG_MAXDESCLEN); i++; strncpy(status[i].name, "log_destination", POOLCONFIG_MAXNAMELEN); snprintf(status[i].value, POOLCONFIG_MAXVALLEN, "%s", pool_config->log_destination); strncpy(status[i].desc, "logging destination", POOLCONFIG_MAXDESCLEN); i++; strncpy(status[i].name, "syslog_facility", POOLCONFIG_MAXNAMELEN); snprintf(status[i].value, POOLCONFIG_MAXVALLEN, "LOCAL%d", (pool_config->syslog_facility/8) - 16); strncpy(status[i].desc, "syslog local faclity", POOLCONFIG_MAXDESCLEN); i++; strncpy(status[i].name, "syslog_ident", POOLCONFIG_MAXNAMELEN); snprintf(status[i].value, POOLCONFIG_MAXVALLEN, "%s", pool_config->syslog_ident); strncpy(status[i].desc, "syslog program ident string", POOLCONFIG_MAXDESCLEN); i++; strncpy(status[i].name, "pid_file_name", POOLCONFIG_MAXNAMELEN); snprintf(status[i].value, POOLCONFIG_MAXVALLEN, "%s", pool_config->pid_file_name); strncpy(status[i].desc, "path to pid file", POOLCONFIG_MAXDESCLEN); i++; /* backend_socket_dir is deprecated. backend_hostname should be used instead */ if (pool_config->backend_socket_dir != NULL) { strncpy(status[i].name, "backend_socket_dir", POOLCONFIG_MAXNAMELEN); snprintf(status[i].value, POOLCONFIG_MAXVALLEN, "%s", pool_config->backend_socket_dir); strncpy(status[i].desc, "DEPRECATED, use backend_hostname parameter instead", POOLCONFIG_MAXDESCLEN); i++; } strncpy(status[i].name, "replication_mode", POOLCONFIG_MAXNAMELEN); snprintf(status[i].value, POOLCONFIG_MAXVALLEN, "%d", pool_config->replication_mode); strncpy(status[i].desc, "non 0 if operating in replication mode", POOLCONFIG_MAXDESCLEN); i++; strncpy(status[i].name, "load_balance_mode", POOLCONFIG_MAXNAMELEN); snprintf(status[i].value, POOLCONFIG_MAXVALLEN, "%d", pool_config->load_balance_mode); strncpy(status[i].desc, "non 0 if operating in load balancing mode", POOLCONFIG_MAXDESCLEN); i++; strncpy(status[i].name, "replication_stop_on_mismatch", POOLCONFIG_MAXNAMELEN); snprintf(status[i].value, POOLCONFIG_MAXVALLEN, "%d", pool_config->replication_stop_on_mismatch); strncpy(status[i].desc, "stop replication mode on fatal error", POOLCONFIG_MAXDESCLEN); i++; strncpy(status[i].name, "failover_if_affected_tuples_mismatch", POOLCONFIG_MAXNAMELEN); snprintf(status[i].value, POOLCONFIG_MAXVALLEN, "%d", pool_config->failover_if_affected_tuples_mismatch); strncpy(status[i].desc, "failover if affected tuples are mismatch", POOLCONFIG_MAXDESCLEN); i++; strncpy(status[i].name, "replicate_select", POOLCONFIG_MAXNAMELEN); snprintf(status[i].value, POOLCONFIG_MAXVALLEN, "%d", pool_config->replicate_select); strncpy(status[i].desc, "non 0 if SELECT statement is replicated", POOLCONFIG_MAXDESCLEN); i++; strncpy(status[i].name, "reset_query_list", POOLCONFIG_MAXNAMELEN); *(status[i].value) = '\0'; for (j=0;j<pool_config->num_reset_queries;j++) { len = POOLCONFIG_MAXVALLEN - strlen(status[i].value); strncat(status[i].value, pool_config->reset_query_list[j], len); len = POOLCONFIG_MAXVALLEN - strlen(status[i].value); if (j != pool_config->num_reset_queries-1) strncat(status[i].value, ";", len); } strncpy(status[i].desc, "queries issued at the end of session", POOLCONFIG_MAXDESCLEN); i++; strncpy(status[i].name, "white_function_list", POOLCONFIG_MAXNAMELEN); *(status[i].value) = '\0'; for (j=0;j<pool_config->num_white_function_list;j++) { len = POOLCONFIG_MAXVALLEN - strlen(status[i].value); strncat(status[i].value, pool_config->white_function_list[j], len); len = POOLCONFIG_MAXVALLEN - strlen(status[i].value); if (j != pool_config->num_white_function_list-1) strncat(status[i].value, ",", len); } strncpy(status[i].desc, "functions those do not write to database", POOLCONFIG_MAXDESCLEN); i++; strncpy(status[i].name, "black_function_list", POOLCONFIG_MAXNAMELEN); *(status[i].value) = '\0'; for (j=0;j<pool_config->num_black_function_list;j++) { len = POOLCONFIG_MAXVALLEN - strlen(status[i].value); strncat(status[i].value, pool_config->black_function_list[j], len); len = POOLCONFIG_MAXVALLEN - strlen(status[i].value); if (j != pool_config->num_black_function_list-1) strncat(status[i].value, ",", len); } strncpy(status[i].desc, "functions those write to database", POOLCONFIG_MAXDESCLEN); i++; strncpy(status[i].name, "print_timestamp", POOLCONFIG_MAXNAMELEN); snprintf(status[i].value, POOLCONFIG_MAXVALLEN, "%d", pool_config->print_timestamp); strncpy(status[i].desc, "if true print time stamp to each log line", POOLCONFIG_MAXDESCLEN); i++; strncpy(status[i].name, "master_slave_mode", POOLCONFIG_MAXNAMELEN); snprintf(status[i].value, POOLCONFIG_MAXVALLEN, "%d", pool_config->master_slave_mode); strncpy(status[i].desc, "if true, operate in master/slave mode", POOLCONFIG_MAXDESCLEN); i++; strncpy(status[i].name, "master_slave_sub_mode", POOLCONFIG_MAXNAMELEN); snprintf(status[i].value, POOLCONFIG_MAXVALLEN, "%s", pool_config->master_slave_sub_mode); strncpy(status[i].desc, "master/slave sub mode", POOLCONFIG_MAXDESCLEN); i++; strncpy(status[i].name, "sr_check_period", POOLCONFIG_MAXNAMELEN); snprintf(status[i].value, POOLCONFIG_MAXVALLEN, "%d", pool_config->sr_check_period); strncpy(status[i].desc, "sr check period", POOLCONFIG_MAXDESCLEN); i++; strncpy(status[i].name, "sr_check_user", POOLCONFIG_MAXNAMELEN); snprintf(status[i].value, POOLCONFIG_MAXVALLEN, "%s", pool_config->sr_check_user); strncpy(status[i].desc, "sr check user", POOLCONFIG_MAXDESCLEN); i++; #ifdef NOT_USED /* for security reason */ strncpy(status[i].name, "sr_check_password", POOLCONFIG_MAXNAMELEN); snprintf(status[i].value, POOLCONFIG_MAXVALLEN, "%s", pool_config->sr_check_password); strncpy(status[i].desc, "sr check password", POOLCONFIG_MAXDESCLEN); i++; #endif strncpy(status[i].name, "delay_threshold", POOLCONFIG_MAXNAMELEN); snprintf(status[i].value, POOLCONFIG_MAXVALLEN, "%lld", pool_config->delay_threshold); strncpy(status[i].desc, "standby delay threshold", POOLCONFIG_MAXDESCLEN); i++; strncpy(status[i].name, "log_standby_delay", POOLCONFIG_MAXNAMELEN); snprintf(status[i].value, POOLCONFIG_MAXVALLEN, "%s", pool_config->log_standby_delay); strncpy(status[i].desc, "how to log standby delay", POOLCONFIG_MAXDESCLEN); i++; strncpy(status[i].name, "connection_cache", POOLCONFIG_MAXNAMELEN); snprintf(status[i].value, POOLCONFIG_MAXVALLEN, "%d", pool_config->connection_cache); strncpy(status[i].desc, "if true, cache connection pool", POOLCONFIG_MAXDESCLEN); i++; strncpy(status[i].name, "health_check_timeout", POOLCONFIG_MAXNAMELEN); snprintf(status[i].value, POOLCONFIG_MAXVALLEN, "%d", pool_config->health_check_timeout); strncpy(status[i].desc, "health check timeout", POOLCONFIG_MAXDESCLEN); i++; strncpy(status[i].name, "health_check_period", POOLCONFIG_MAXNAMELEN); snprintf(status[i].value, POOLCONFIG_MAXVALLEN, "%d", pool_config->health_check_period); strncpy(status[i].desc, "health check period", POOLCONFIG_MAXDESCLEN); i++; strncpy(status[i].name, "health_check_user", POOLCONFIG_MAXNAMELEN); snprintf(status[i].value, POOLCONFIG_MAXVALLEN, "%s", pool_config->health_check_user); strncpy(status[i].desc, "health check user", POOLCONFIG_MAXDESCLEN); i++; #ifdef NOT_USED /* for security reason */ strncpy(status[i].name, "health_check_password", POOLCONFIG_MAXNAMELEN); snprintf(status[i].value, POOLCONFIG_MAXVALLEN, "%s", pool_config->health_check_password); strncpy(status[i].desc, "health check password", POOLCONFIG_MAXDESCLEN); i++; #endif strncpy(status[i].name, "failover_command", POOLCONFIG_MAXNAMELEN); snprintf(status[i].value, POOLCONFIG_MAXVALLEN, "%s", pool_config->failover_command); strncpy(status[i].desc, "failover command", POOLCONFIG_MAXDESCLEN); i++; strncpy(status[i].name, "follow_master_command", POOLCONFIG_MAXNAMELEN); snprintf(status[i].value, POOLCONFIG_MAXVALLEN, "%s", pool_config->follow_master_command); strncpy(status[i].desc, "follow master command", POOLCONFIG_MAXDESCLEN); i++; strncpy(status[i].name, "failback_command", POOLCONFIG_MAXNAMELEN); snprintf(status[i].value, POOLCONFIG_MAXVALLEN, "%s", pool_config->failback_command); strncpy(status[i].desc, "failback command", POOLCONFIG_MAXDESCLEN); i++; strncpy(status[i].name, "fail_over_on_backend_error", POOLCONFIG_MAXNAMELEN); snprintf(status[i].value, POOLCONFIG_MAXVALLEN, "%d", pool_config->fail_over_on_backend_error); strncpy(status[i].desc, "fail over on backend error", POOLCONFIG_MAXDESCLEN); i++; strncpy(status[i].name, "insert_lock", POOLCONFIG_MAXNAMELEN); snprintf(status[i].value, POOLCONFIG_MAXVALLEN, "%d", pool_config->insert_lock); strncpy(status[i].desc, "insert lock", POOLCONFIG_MAXDESCLEN); i++; strncpy(status[i].name, "ignore_leading_white_space", POOLCONFIG_MAXNAMELEN); snprintf(status[i].value, POOLCONFIG_MAXVALLEN, "%d", pool_config->ignore_leading_white_space); strncpy(status[i].desc, "ignore leading white spaces", POOLCONFIG_MAXDESCLEN); i++; strncpy(status[i].name, "num_reset_queries", POOLCONFIG_MAXNAMELEN); snprintf(status[i].value, POOLCONFIG_MAXVALLEN, "%d", pool_config->num_reset_queries); strncpy(status[i].desc, "number of queries in reset_query_list", POOLCONFIG_MAXDESCLEN); i++; strncpy(status[i].name, "pcp_port", POOLCONFIG_MAXNAMELEN); snprintf(status[i].value, POOLCONFIG_MAXVALLEN, "%d", pool_config->pcp_port); strncpy(status[i].desc, "PCP port # to bind", POOLCONFIG_MAXDESCLEN); i++; strncpy(status[i].name, "pcp_socket_dir", POOLCONFIG_MAXNAMELEN); snprintf(status[i].value, POOLCONFIG_MAXVALLEN, "%s", pool_config->pcp_socket_dir); strncpy(status[i].desc, "PCP socket directory", POOLCONFIG_MAXDESCLEN); i++; strncpy(status[i].name, "pcp_timeout", POOLCONFIG_MAXNAMELEN); snprintf(status[i].value, POOLCONFIG_MAXVALLEN, "%d", pool_config->pcp_timeout); strncpy(status[i].desc, "PCP timeout for an idle client", POOLCONFIG_MAXDESCLEN); i++; strncpy(status[i].name, "log_statement", POOLCONFIG_MAXNAMELEN); snprintf(status[i].value, POOLCONFIG_MAXVALLEN, "%d", pool_config->log_statement); strncpy(status[i].desc, "if non 0, logs all SQL statements", POOLCONFIG_MAXDESCLEN); i++; strncpy(status[i].name, "log_per_node_statement", POOLCONFIG_MAXNAMELEN); snprintf(status[i].value, POOLCONFIG_MAXVALLEN, "%d", pool_config->log_per_node_statement); strncpy(status[i].desc, "if non 0, logs all SQL statements on each node", POOLCONFIG_MAXDESCLEN); i++; strncpy(status[i].name, "log_connections", POOLCONFIG_MAXNAMELEN); snprintf(status[i].value, POOLCONFIG_MAXVALLEN, "%d", pool_config->log_connections); strncpy(status[i].desc, "if true, print incoming connections to the log", POOLCONFIG_MAXDESCLEN); i++; strncpy(status[i].name, "log_hostname", POOLCONFIG_MAXNAMELEN); snprintf(status[i].value, POOLCONFIG_MAXVALLEN, "%d", pool_config->log_hostname); strncpy(status[i].desc, "if true, resolve hostname for ps and log print", POOLCONFIG_MAXDESCLEN); i++; strncpy(status[i].name, "enable_pool_hba", POOLCONFIG_MAXNAMELEN); snprintf(status[i].value, POOLCONFIG_MAXVALLEN, "%d", pool_config->enable_pool_hba); strncpy(status[i].desc, "if true, use pool_hba.conf for client authentication", POOLCONFIG_MAXDESCLEN); i++; strncpy(status[i].name, "recovery_user", POOLCONFIG_MAXNAMELEN); snprintf(status[i].value, POOLCONFIG_MAXVALLEN, "%s", pool_config->recovery_user); strncpy(status[i].desc, "online recovery user", POOLCONFIG_MAXDESCLEN); i++; strncpy(status[i].name, "recovery_1st_stage_command", POOLCONFIG_MAXNAMELEN); snprintf(status[i].value, POOLCONFIG_MAXVALLEN, "%s", pool_config->recovery_1st_stage_command); strncpy(status[i].desc, "execute a command in first stage.", POOLCONFIG_MAXDESCLEN); i++; strncpy(status[i].name, "recovery_2nd_stage_command", POOLCONFIG_MAXNAMELEN); snprintf(status[i].value, POOLCONFIG_MAXVALLEN, "%s", pool_config->recovery_2nd_stage_command); strncpy(status[i].desc, "execute a command in second stage.", POOLCONFIG_MAXDESCLEN); i++; strncpy(status[i].name, "recovery_timeout", POOLCONFIG_MAXNAMELEN); snprintf(status[i].value, POOLCONFIG_MAXVALLEN, "%d", pool_config->recovery_timeout); strncpy(status[i].desc, "max time in seconds to wait for the recovering node's postmaster", POOLCONFIG_MAXDESCLEN); i++; strncpy(status[i].name, "client_idle_limit_in_recovery", POOLCONFIG_MAXNAMELEN); snprintf(status[i].value, POOLCONFIG_MAXVALLEN, "%d", pool_config->client_idle_limit_in_recovery); strncpy(status[i].desc, "if idle for this seconds, child connection closes in recovery 2nd statge", POOLCONFIG_MAXDESCLEN); i++; strncpy(status[i].name, "lobj_lock_table", POOLCONFIG_MAXNAMELEN); snprintf(status[i].value, POOLCONFIG_MAXVALLEN, "%s", pool_config->lobj_lock_table); strncpy(status[i].desc, "table name used for large object replication control", POOLCONFIG_MAXDESCLEN); i++; strncpy(status[i].name, "ssl", POOLCONFIG_MAXNAMELEN); snprintf(status[i].value, POOLCONFIG_MAXVALLEN, "%d", pool_config->ssl); strncpy(status[i].desc, "SSL support", POOLCONFIG_MAXDESCLEN); i++; strncpy(status[i].name, "ssl_key", POOLCONFIG_MAXNAMELEN); snprintf(status[i].value, POOLCONFIG_MAXVALLEN, "%s", pool_config->ssl_key); strncpy(status[i].desc, "path to the SSL private key file", POOLCONFIG_MAXDESCLEN); i++; strncpy(status[i].name, "ssl_cert", POOLCONFIG_MAXNAMELEN); snprintf(status[i].value, POOLCONFIG_MAXVALLEN, "%s", pool_config->ssl_cert); strncpy(status[i].desc, "path to the SSL public certificate file", POOLCONFIG_MAXDESCLEN); i++; strncpy(status[i].name, "ssl_ca_cert", POOLCONFIG_MAXNAMELEN); snprintf(status[i].value, POOLCONFIG_MAXVALLEN, "%s", pool_config->ssl_ca_cert); strncpy(status[i].desc, "aath to a single PEM format file", POOLCONFIG_MAXDESCLEN); i++; strncpy(status[i].name, "ssl_ca_cert_dir", POOLCONFIG_MAXNAMELEN); snprintf(status[i].value, POOLCONFIG_MAXVALLEN, "%s", pool_config->ssl_ca_cert_dir); strncpy(status[i].desc, "Directory containing CA root certificate(s)", POOLCONFIG_MAXDESCLEN); i++; strncpy(status[i].name, "debug_level", POOLCONFIG_MAXNAMELEN); snprintf(status[i].value, POOLCONFIG_MAXVALLEN, "%d", pool_config->debug_level); strncpy(status[i].desc, "debug message level", POOLCONFIG_MAXDESCLEN); i++; strncpy(status[i].name, "relcache_expire", POOLCONFIG_MAXNAMELEN); snprintf(status[i].value, POOLCONFIG_MAXVALLEN, "%ld", pool_config->relcache_expire); strncpy(status[i].desc, "relation cache expiration time in seconds", POOLCONFIG_MAXDESCLEN); i++; strncpy(status[i].name, "parallel_mode", POOLCONFIG_MAXNAMELEN); snprintf(status[i].value, POOLCONFIG_MAXVALLEN, "%d", pool_config->parallel_mode); strncpy(status[i].desc, "if non 0, run in parallel query mode", POOLCONFIG_MAXDESCLEN); i++; strncpy(status[i].name, "enable_query_cache", POOLCONFIG_MAXNAMELEN); snprintf(status[i].value, POOLCONFIG_MAXVALLEN, "%d", pool_config->enable_query_cache); strncpy(status[i].desc, "if non 0, use query cache", POOLCONFIG_MAXDESCLEN); i++; strncpy(status[i].name, "pgpool2_hostname", POOLCONFIG_MAXNAMELEN); snprintf(status[i].value, POOLCONFIG_MAXVALLEN, "%s", pool_config->pgpool2_hostname); strncpy(status[i].desc, "pgpool2 hostname", POOLCONFIG_MAXDESCLEN); i++; strncpy(status[i].name, "system_db_hostname", POOLCONFIG_MAXNAMELEN); snprintf(status[i].value, POOLCONFIG_MAXVALLEN, "%s", pool_config->system_db_hostname); strncpy(status[i].desc, "system DB hostname", POOLCONFIG_MAXDESCLEN); i++; strncpy(status[i].name, "system_db_port", POOLCONFIG_MAXNAMELEN); snprintf(status[i].value, POOLCONFIG_MAXVALLEN, "%d", pool_config->system_db_port); strncpy(status[i].desc, "system DB port number", POOLCONFIG_MAXDESCLEN); i++; strncpy(status[i].name, "system_db_dbname", POOLCONFIG_MAXNAMELEN); snprintf(status[i].value, POOLCONFIG_MAXVALLEN, "%s", pool_config->system_db_dbname); strncpy(status[i].desc, "system DB name", POOLCONFIG_MAXDESCLEN); i++; strncpy(status[i].name, "system_db_schema", POOLCONFIG_MAXNAMELEN); snprintf(status[i].value, POOLCONFIG_MAXVALLEN, "%s", pool_config->system_db_schema); strncpy(status[i].desc, "system DB schema name", POOLCONFIG_MAXDESCLEN); i++; strncpy(status[i].name, "system_db_user", POOLCONFIG_MAXNAMELEN); snprintf(status[i].value, POOLCONFIG_MAXVALLEN, "%s", pool_config->system_db_user); strncpy(status[i].desc, "user name to access system DB", POOLCONFIG_MAXDESCLEN); i++; for (j = 0; j < NUM_BACKENDS; j++) { if (BACKEND_INFO(j).backend_port == 0) continue; snprintf(status[i].name, POOLCONFIG_MAXNAMELEN, "backend_hostname%d", j); snprintf(status[i].value, POOLCONFIG_MAXVALLEN, "%s", BACKEND_INFO(j).backend_hostname); snprintf(status[i].desc, POOLCONFIG_MAXDESCLEN, "backend #%d hostname", j); i++; snprintf(status[i].name, POOLCONFIG_MAXNAMELEN, "backend_port%d", j); snprintf(status[i].value, POOLCONFIG_MAXVALLEN, "%d", BACKEND_INFO(j).backend_port); snprintf(status[i].desc, POOLCONFIG_MAXDESCLEN, "backend #%d port number", j); i++; snprintf(status[i].name, POOLCONFIG_MAXNAMELEN, "backend_weight%d", j); snprintf(status[i].value, POOLCONFIG_MAXVALLEN, "%f", BACKEND_INFO(j).backend_weight/RAND_MAX); snprintf(status[i].desc, POOLCONFIG_MAXDESCLEN, "weight of backend #%d", j); i++; snprintf(status[i].name, POOLCONFIG_MAXNAMELEN, "backend_data_directory%d", j); snprintf(status[i].value, POOLCONFIG_MAXVALLEN, "%s", BACKEND_INFO(j).backend_data_directory); snprintf(status[i].desc, POOLCONFIG_MAXDESCLEN, "data directory of backend #%d", j); i++; snprintf(status[i].name, POOLCONFIG_MAXNAMELEN, "backend_status%d", j); snprintf(status[i].value, POOLCONFIG_MAXVALLEN, "%d", BACKEND_INFO(j).backend_status); snprintf(status[i].desc, POOLCONFIG_MAXDESCLEN, "status of backend #%d", j); i++; snprintf(status[i].name, POOLCONFIG_MAXNAMELEN, "standby_delay%d", j); snprintf(status[i].value, POOLCONFIG_MAXVALLEN, "%lld", BACKEND_INFO(j).standby_delay); snprintf(status[i].desc, POOLCONFIG_MAXDESCLEN, "standby delay of backend #%d", j); i++; snprintf(status[i].name, POOLCONFIG_MAXNAMELEN, "backend_flag%d", j); snprintf(status[i].value, POOLCONFIG_MAXVALLEN, "%s", pool_flag_to_str(BACKEND_INFO(j).flag)); snprintf(status[i].desc, POOLCONFIG_MAXDESCLEN, "backend #%d flag", j); i++; } *nrows = i; return status; }
/* * perform accept() and return new fd */ static POOL_CONNECTION *do_accept(int unix_fd, int inet_fd, struct timeval *timeout) { fd_set readmask; int fds; int save_errno; SockAddr saddr; int fd = 0; int afd; int inet = 0; POOL_CONNECTION *cp; #ifdef ACCEPT_PERFORMANCE struct timeval now1, now2; static long atime; static int cnt; #endif struct timeval *timeoutval; struct timeval tv1, tv2, tmback = {0, 0}; set_ps_display("wait for connection request", false); /* Destroy session context for just in case... */ pool_session_context_destroy(); FD_ZERO(&readmask); FD_SET(unix_fd, &readmask); if (inet_fd) FD_SET(inet_fd, &readmask); if (timeout->tv_sec == 0 && timeout->tv_usec == 0) timeoutval = NULL; else { timeoutval = timeout; tmback.tv_sec = timeout->tv_sec; tmback.tv_usec = timeout->tv_usec; gettimeofday(&tv1, NULL); #ifdef DEBUG pool_log("before select = {%d, %d}", timeoutval->tv_sec, timeoutval->tv_usec); pool_log("g:before select = {%d, %d}", tv1.tv_sec, tv1.tv_usec); #endif } fds = select(Max(unix_fd, inet_fd)+1, &readmask, NULL, NULL, timeoutval); save_errno = errno; /* check backend timer is expired */ if (backend_timer_expired) { pool_backend_timer(); backend_timer_expired = 0; } /* * following code fragment computes remaining timeout val in a * portable way. Linux does this automatically but other platforms do not. */ if (timeoutval) { gettimeofday(&tv2, NULL); tmback.tv_usec -= tv2.tv_usec - tv1.tv_usec; tmback.tv_sec -= tv2.tv_sec - tv1.tv_sec; if (tmback.tv_usec < 0) { tmback.tv_sec--; if (tmback.tv_sec < 0) { timeout->tv_sec = 0; timeout->tv_usec = 0; } else { tmback.tv_usec += 1000000; timeout->tv_sec = tmback.tv_sec; timeout->tv_usec = tmback.tv_usec; } } #ifdef DEBUG pool_log("g:after select = {%d, %d}", tv2.tv_sec, tv2.tv_usec); pool_log("after select = {%d, %d}", timeout->tv_sec, timeout->tv_usec); #endif } errno = save_errno; if (fds == -1) { if (errno == EAGAIN || errno == EINTR) return NULL; pool_error("select() failed. reason %s", strerror(errno)); return NULL; } /* timeout */ if (fds == 0) { return NULL; } if (FD_ISSET(unix_fd, &readmask)) { fd = unix_fd; } if (FD_ISSET(inet_fd, &readmask)) { fd = inet_fd; inet++; } /* * Note that some SysV systems do not work here. For those * systems, we need some locking mechanism for the fd. */ memset(&saddr, 0, sizeof(saddr)); saddr.salen = sizeof(saddr.addr); #ifdef ACCEPT_PERFORMANCE gettimeofday(&now1,0); #endif retry_accept: /* wait if recovery is started */ while (*InRecovery == 1) { pause(); } afd = accept(fd, (struct sockaddr *)&saddr.addr, &saddr.salen); save_errno = errno; /* check backend timer is expired */ if (backend_timer_expired) { pool_backend_timer(); backend_timer_expired = 0; } errno = save_errno; if (afd < 0) { if (errno == EINTR && *InRecovery) goto retry_accept; /* * "Resource temporarily unavailable" (EAGAIN or EWOULDBLOCK) * can be silently ignored. And EINTR can be ignored. */ if (errno != EAGAIN && errno != EWOULDBLOCK && errno != EINTR) pool_error("accept() failed. reason: %s", strerror(errno)); return NULL; } #ifdef ACCEPT_PERFORMANCE gettimeofday(&now2,0); atime += (now2.tv_sec - now1.tv_sec)*1000000 + (now2.tv_usec - now1.tv_usec); cnt++; if (cnt % 100 == 0) { pool_log("cnt: %d atime: %ld", cnt, atime); } #endif /* reload config file */ if (got_sighup) { pool_get_config(get_config_file_name(), RELOAD_CONFIG); if (pool_config->enable_pool_hba) { load_hba(get_hba_file_name()); if (strcmp("", pool_config->pool_passwd)) pool_reopen_passwd_file(); } if (pool_config->parallel_mode) pool_memset_system_db_info(system_db_info->info); got_sighup = 0; } connection_count_up(); accepted = 1; if (pool_config->parallel_mode) { /* * do not accept new connection if any of DB node or SystemDB is down when operating in * parallel mode */ int i; for (i=0;i<NUM_BACKENDS;i++) { if (BACKEND_INFO(i).backend_status == CON_DOWN || SYSDB_STATUS == CON_DOWN) { StartupPacket *sp; char *msg = "pgpool is not available in parallel query mode"; if (SYSDB_STATUS == CON_DOWN) pool_log("Cannot accept() new connection. SystemDB is down"); else pool_log("Cannot accept() new connection. %d th backend is down", i); if ((cp = pool_open(afd)) == NULL) { close(afd); child_exit(1); } sp = read_startup_packet(cp); if (sp == NULL) { /* failed to read the startup packet. return to the accept() loop */ pool_close(cp); child_exit(1); } pool_debug("do_accept: send error message to frontend"); if (sp->major == PROTO_MAJOR_V3) { char buf[256]; if (SYSDB_STATUS == CON_DOWN) snprintf(buf, sizeof(buf), "SystemDB is down"); else snprintf(buf, sizeof(buf), "%d th backend is down", i); pool_send_error_message(cp, sp->major, "08S01", msg, buf, ((SYSDB_STATUS == CON_DOWN) ? "repair the SystemDB and restart pgpool" : "repair the backend and restart pgpool"), __FILE__, __LINE__); } else { pool_send_error_message(cp, sp->major, 0, msg, "", "", "", 0); } pool_close(cp); child_exit(1); } } } else { /* * do not accept new connection if all DB nodes are down when operating in * non parallel mode */ int i; int found = 0; for (i=0;i<NUM_BACKENDS;i++) { if (VALID_BACKEND(i)) { found = 1; } } if (found == 0) { pool_log("Cannot accept() new connection. all backends are down"); child_exit(1); } } pool_debug("I am %d accept fd %d", getpid(), afd); pool_getnameinfo_all(&saddr, remote_host, remote_port); snprintf(remote_ps_data, sizeof(remote_ps_data), remote_port[0] == '\0' ? "%s" : "%s(%s)", remote_host, remote_port); set_ps_display("accept connection", false); /* log who is connecting */ if (pool_config->log_connections) { pool_log("connection received: host=%s%s%s", remote_host, remote_port[0] ? " port=" : "", remote_port); } /* set NODELAY and KEEPALIVE options if INET connection */ if (inet) { int on = 1; if (setsockopt(afd, IPPROTO_TCP, TCP_NODELAY, (char *) &on, sizeof(on)) < 0) { pool_error("do_accept: setsockopt() failed: %s", strerror(errno)); close(afd); return NULL; } if (setsockopt(afd, SOL_SOCKET, SO_KEEPALIVE, (char *) &on, sizeof(on)) < 0) { pool_error("do_accept: setsockopt() failed: %s", strerror(errno)); close(afd); return NULL; } } if ((cp = pool_open(afd)) == NULL) { close(afd); return NULL; } /* save ip address for hba */ memcpy(&cp->raddr, &saddr, sizeof(SockAddr)); if (cp->raddr.addr.ss_family == 0) cp->raddr.addr.ss_family = AF_UNIX; return cp; }
/* * process cancel request */ void cancel_request(CancelPacket *sp) { int len; int fd; POOL_CONNECTION *con; int i,j,k; ConnectionInfo *c = NULL; CancelPacket cp; bool found = false; pool_debug("Cancel request received"); /* look for cancel key from shmem info */ for (i=0;i<pool_config->num_init_children;i++) { for (j=0;j<pool_config->max_pool;j++) { for (k=0;k<NUM_BACKENDS;k++) { c = pool_coninfo(i, j, k); pool_debug("con_info: address:%p database:%s user:%s pid:%d key:%d i:%d", c, c->database, c->user, ntohl(c->pid), ntohl(c->key),i); if (c->pid == sp->pid && c->key == sp->key) { pool_debug("found pid:%d key:%d i:%d",ntohl(c->pid), ntohl(c->key),i); c = pool_coninfo(i, j, 0); found = true; goto found; } } } } found: if (!found) { pool_error("cancel_request: invalid cancel key: pid:%d key:%d",ntohl(sp->pid), ntohl(sp->key)); return; /* invalid key */ } for (i=0;i<NUM_BACKENDS;i++,c++) { if (!VALID_BACKEND(i)) continue; if (*(BACKEND_INFO(i).backend_hostname) == '/') fd = connect_unix_domain_socket(i, TRUE); else fd = connect_inet_domain_socket(i, TRUE); if (fd < 0) { pool_error("Could not create socket for sending cancel request for backend %d", i); return; } con = pool_open(fd); if (con == NULL) return; len = htonl(sizeof(len) + sizeof(CancelPacket)); pool_write(con, &len, sizeof(len)); cp.protoVersion = sp->protoVersion; cp.pid = c->pid; cp.key = c->key; pool_log("cancel_request: canceling backend pid:%d key: %d", ntohl(cp.pid),ntohl(cp.key)); if (pool_write_and_flush(con, &cp, sizeof(CancelPacket)) < 0) pool_error("Could not send cancel request packet for backend %d", i); pool_close(con); /* * this is needed to ensure that the next DB node executes the * query supposed to be canceled. */ sleep(1); } }
/* * check if we can connect to the backend * returns 0 for ok. otherwise returns backend id + 1 */ int health_check(void) { int fd; int sts; /* V2 startup packet */ typedef struct { int len; /* startup packet length */ StartupPacket_v2 sp; } MySp; MySp mysp; char kind; int i; if (*InRecovery) return 0; memset(&mysp, 0, sizeof(mysp)); mysp.len = htonl(296); mysp.sp.protoVersion = htonl(PROTO_MAJOR_V2 << 16); strcpy(mysp.sp.database, "template1"); strncpy(mysp.sp.user, pool_config->health_check_user, sizeof(mysp.sp.user) - 1); *mysp.sp.options = '\0'; *mysp.sp.unused = '\0'; *mysp.sp.tty = '\0'; for (i=0;i<pool_config->backend_desc->num_backends;i++) { pool_debug("health_check: %d th DB node status: %d", i, BACKEND_INFO(i).backend_status); if (BACKEND_INFO(i).backend_status == CON_UNUSED || BACKEND_INFO(i).backend_status == CON_DOWN) continue; if (*(BACKEND_INFO(i).backend_hostname) == '\0') fd = connect_unix_domain_socket(i); else fd = connect_inet_domain_socket(i); if (fd < 0) { pool_error("health check failed. %d th host %s at port %d is down", i, BACKEND_INFO(i).backend_hostname, BACKEND_INFO(i).backend_port); return i+1; } if (write(fd, &mysp, sizeof(mysp)) < 0) { pool_error("health check failed during write. host %s at port %d is down. reason: %s", BACKEND_INFO(i).backend_hostname, BACKEND_INFO(i).backend_port, strerror(errno)); close(fd); return i+1; } /* * Don't bother to be blocked by read(2). It will be * interrupted by ALRAM anyway. */ sts = read(fd, &kind, 1); if (sts == -1) { pool_error("health check failed during read. host %s at port %d is down. reason: %s", BACKEND_INFO(i).backend_hostname, BACKEND_INFO(i).backend_port, strerror(errno)); close(fd); return i+1; } else if (sts == 0) { pool_error("health check failed. EOF encountered. host %s at port %d is down", BACKEND_INFO(i).backend_hostname, BACKEND_INFO(i).backend_port); close(fd); return i+1; } /* * If a backend raised a FATAL error(max connections error or * starting up error?), do not send a Terminate message. */ if ((kind != 'E') && (write(fd, "X", 1) < 0)) { pool_error("health check failed during write. host %s at port %d is down. reason: %s. Perhaps wrong health check user?", BACKEND_INFO(i).backend_hostname, BACKEND_INFO(i).backend_port, strerror(errno)); close(fd); return i+1; } close(fd); } return 0; }
/* * backend connection error, failover/failback request, if possible * failover() must be called under protecting signals. */ static void failover(void) { int i; int node_id; int new_master; int nodes[MAX_NUM_BACKENDS]; pool_debug("failover_handler called"); memset(nodes, 0, sizeof(int) * MAX_NUM_BACKENDS); /* * this could happen in a child process if a signal has been sent * before resetting signal handler */ if (getpid() != mypid) { pool_debug("failover_handler: I am not parent"); kill(pcp_pid, SIGUSR2); return; } /* * processing SIGTERM, SIGINT or SIGQUIT */ if (exiting) { pool_debug("failover_handler called while exiting"); kill(pcp_pid, SIGUSR2); return; } /* * processing fail over or switch over */ if (switching) { pool_debug("failover_handler called while switching"); kill(pcp_pid, SIGUSR2); return; } pool_semaphore_lock(REQUEST_INFO_SEM); if (Req_info->kind == CLOSE_IDLE_REQUEST) { pool_semaphore_unlock(REQUEST_INFO_SEM); kill_all_children(SIGUSR1); kill(pcp_pid, SIGUSR2); return; } /* * if not in replication mode/master slave mode, we treat this a restart request. * otherwise we need to check if we have already failovered. */ pool_debug("failover_handler: starting to select new master node"); switching = 1; node_id = Req_info->node_id[0]; /* failback request? */ if (Req_info->kind == NODE_UP_REQUEST) { if (node_id >= MAX_NUM_BACKENDS || (Req_info->kind == NODE_UP_REQUEST && VALID_BACKEND(node_id)) || (Req_info->kind == NODE_DOWN_REQUEST && !VALID_BACKEND(node_id))) { pool_semaphore_unlock(REQUEST_INFO_SEM); pool_error("failover_handler: invalid node_id %d status:%d MAX_NUM_BACKENDS: %d", node_id, BACKEND_INFO(node_id).backend_status, MAX_NUM_BACKENDS); kill(pcp_pid, SIGUSR2); switching = 0; return; } pool_log("starting fail back. reconnect host %s(%d)", BACKEND_INFO(node_id).backend_hostname, BACKEND_INFO(node_id).backend_port); BACKEND_INFO(node_id).backend_status = CON_CONNECT_WAIT; /* unset down status */ trigger_failover_command(node_id, pool_config->failback_command); } else { int cnt = 0; for (i = 0; i < MAX_NUM_BACKENDS; i++) { if (Req_info->node_id[i] != -1 && VALID_BACKEND(Req_info->node_id[i])) { pool_log("starting degeneration. shutdown host %s(%d)", BACKEND_INFO(Req_info->node_id[i]).backend_hostname, BACKEND_INFO(Req_info->node_id[i]).backend_port); BACKEND_INFO(Req_info->node_id[i]).backend_status = CON_DOWN; /* set down status */ /* save down node */ nodes[Req_info->node_id[i]] = 1; cnt++; } } if (cnt == 0) { pool_log("failover: no backends are degenerated"); pool_semaphore_unlock(REQUEST_INFO_SEM); kill(pcp_pid, SIGUSR2); switching = 0; return; } } new_master = get_next_master_node(); if (new_master == pool_config->backend_desc->num_backends) { pool_error("failover_handler: no valid DB node found"); } /* * Before we tried to minimize restarting pgpool to protect existing * connections from clients to pgpool children. What we did here was, * if children other than master went down, we did not fail over. * This is wrong. Think about following scenario. If someone * accidentally plugs out the network cable, the TCP/IP stack keeps * retrying for long time (typically 2 hours). The only way to stop * the retry is restarting the process. Bottom line is, we need to * restart all children in any case. See pgpool-general list posting * "TCP connections are *not* closed when a backend timeout" on Jul 13 * 2008 for more details. */ #ifdef NOT_USED else { if (Req_info->master_node_id == new_master && *InRecovery == 0) { pool_log("failover_handler: do not restart pgpool. same master node %d was selected", new_master); if (Req_info->kind == NODE_UP_REQUEST) { pool_log("failback done. reconnect host %s(%d)", BACKEND_INFO(node_id).backend_hostname, BACKEND_INFO(node_id).backend_port); } else { pool_log("failover done. shutdown host %s(%d)", BACKEND_INFO(node_id).backend_hostname, BACKEND_INFO(node_id).backend_port); } /* exec failover_command */ for (i = 0; i < pool_config->backend_desc->num_backends; i++) { if (nodes[i]) trigger_failover_command(i, pool_config->failover_command); } pool_semaphore_unlock(REQUEST_INFO_SEM); switching = 0; kill(pcp_pid, SIGUSR2); switching = 0; return; } } #endif /* kill all children */ for (i = 0; i < pool_config->num_init_children; i++) { pid_t pid = pids[i].pid; if (pid) { kill(pid, SIGQUIT); pool_debug("failover_handler: kill %d", pid); } } /* exec failover_command */ for (i = 0; i < pool_config->backend_desc->num_backends; i++) { if (nodes[i]) trigger_failover_command(i, pool_config->failover_command); } pool_log("failover_handler: set new master node: %d", new_master); Req_info->master_node_id = new_master; /* no need to wait since it will be done in reap_handler */ #ifdef NOT_USED while (wait(NULL) > 0) ; if (errno != ECHILD) pool_error("failover_handler: wait() failed. reason:%s", strerror(errno)); #endif memset(Req_info->node_id, -1, sizeof(int) * MAX_NUM_BACKENDS); pool_semaphore_unlock(REQUEST_INFO_SEM); /* fork the children */ for (i=0;i<pool_config->num_init_children;i++) { pids[i].pid = fork_a_child(unix_fd, inet_fd, i); pids[i].start_time = time(NULL); } if (Req_info->kind == NODE_UP_REQUEST) { pool_log("failback done. reconnect host %s(%d)", BACKEND_INFO(node_id).backend_hostname, BACKEND_INFO(node_id).backend_port); } else { pool_log("failover done. shutdown host %s(%d)", BACKEND_INFO(node_id).backend_hostname, BACKEND_INFO(node_id).backend_port); } switching = 0; /* kick wakeup_handler in pcp_child to notice that * faiover/failback done */ kill(pcp_pid, SIGUSR2); }