pgpool2.git / summary / log / commit / refs

commit    da6dda57edcd8ab062deae122a50576ffa58fde6
Author:   Tatsuo Ishii <ishii at sraoss.co.jp>
Date:     Mon May 02 13:31:25 2011 +0000

    Enhance online recovery in streaming replication mode.
    Now restarting pgpool-II children is avoided when recovery finished.
    So existing sessions can be continued while doing online recovery.
    For this VALID_BACKEND macro is modified. pgpool-II main looks into
    status in shared memory are as it were. pgpool-II child now looks
    into local cache space. Pgpool-II child recognizes same number of
    backends before failback util existing session ends. Then the
    process exits with status 1, so that new process starts, which will
    recognizes failback node. For this purpose "need_to_restart" flag
    added to ProcessInfo structure.


child.c | 50 +++++++++++++++++++++++++++++++++++ main.c | 80 ++++++++++++++++++++++++++++++++++++++++++++++---------- pcp/libpcp_ext.h | 8 +++++- pool.h | 9 ++++--- 4 files changed, 128 insertions(+), 19 deletions(-) diff --git a/child.c b/child.c index 367fe67fd..d74c96368 100644 --- a/child.c +++ b/child.c @@ -74,6 +74,8 @@ 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 */ @@ -89,6 +91,11 @@ 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 */ @@ -129,6 +136,9 @@ void do_child(int unix_fd, int inet_fd) } #endif + /* Initialize my backend status */ + initialize_private_backend_status(); + /* Initialize per process context */ pool_init_process_context(); @@ -157,6 +167,17 @@ void do_child(int unix_fd, int inet_fd) /* pgpool stop request already sent? */ check_stop_request(); + /* 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. + */ + if (pool_get_my_process_info()->need_to_restart) + { + pool_log("do_child: failback event found. restart myself."); + pool_get_my_process_info()->need_to_restart = 0; + child_exit(1); + } + accepted = 0; /* perform accept() */ @@ -251,6 +272,18 @@ void do_child(int unix_fd, int inet_fd) * Authentication is also done in this step. */ + /* 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. + */ + 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(); + } + /* * if there's no connection associated with user and database, * we need to connect to the backend and send the startup packet. @@ -1922,3 +1955,20 @@ static void init_system_db_connection(void) } } } + +/* + * Initialize my backend status. + * 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) +{ + int i; + + for (i=0;i<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]; + } +} diff --git a/main.c b/main.c index 2b2f02933..8e64a4f53 100644 --- a/main.c +++ b/main.c @@ -173,6 +173,8 @@ static BackendStatusRecord backend_rec; /* Backend status record */ static pid_t worker_pid; /* pid of worker process */ +BACKEND_STATUS* my_backend_status[MAX_NUM_BACKENDS]; /* Backend status buffer */ + int myargc; char **myargv; @@ -503,6 +505,17 @@ int main(int argc, char **argv) myexit(1); } + /* + * Initialize backend status area. + * From now on, VALID_BACKEND macro can be used. + * (get_next_master_node() uses VALID_BACKEND) + */ + + for (i=0;i<NUM_BACKENDS;i++) + { + my_backend_status[i] = &(BACKEND_INFO(i).backend_status); + } + /* initialize Req_info */ Req_info->kind = NODE_UP_REQUEST; memset(Req_info->node_id, -1, sizeof(int) * MAX_NUM_BACKENDS); @@ -1440,6 +1453,7 @@ static void failover(void) int new_master; int new_primary; int nodes[MAX_NUM_BACKENDS]; + bool need_to_restart_children; pool_debug("failover_handler called"); @@ -1583,7 +1597,6 @@ static void failover(void) * "TCP connections are *not* closed when a backend timeout" on Jul 13 * 2008 for more details. */ - #ifdef NOT_USED else { @@ -1618,18 +1631,42 @@ static void failover(void) } } #endif - /* kill all children */ - for (i = 0; i < pool_config->num_init_children; i++) + + + /* On 2011/5/2 Tatsuo Ishii says: if mode is streaming replication + * and request is NODE_UP_REQUEST(failback case) we don't need to + * restart all children. Existing session will not use newly + * attached node, but load balanced node is not changed util this + * session ends, so it's not harmless anyway. + */ + if (MASTER_SLAVE && !strcmp(pool_config->master_slave_sub_mode, MODE_STREAMREP) && + Req_info->kind == NODE_UP_REQUEST) { - pid_t pid = process_info[i].pid; - if (pid) + pool_log("Do not restart children because we are failbacking node id %d host%s port:%d and we are in streaming replication mode", node_id, + BACKEND_INFO(node_id).backend_hostname, + BACKEND_INFO(node_id).backend_port); + + need_to_restart_children = false; + } + else + { + pool_log("Restart all children"); + + /* kill all children */ + for (i = 0; i < pool_config->num_init_children; i++) { - kill(pid, SIGQUIT); - pool_debug("failover_handler: kill %d", pid); + pid_t pid = process_info[i].pid; + if (pid) + { + kill(pid, SIGQUIT); + pool_debug("failover_handler: kill %d", pid); + } } + + need_to_restart_children = true; } - /* exec failover_command */ + /* Exec failover_command if needed */ for (i = 0; i < pool_config->backend_desc->num_backends; i++) { if (nodes[i]) @@ -1652,8 +1689,9 @@ static void failover(void) new_primary = find_primary_node_repeatedly(); /* - * In master/slave streaming replication we start degenerating - * all backends as they are not replicated anymore + * If follow_master_command is provided and in master/slave + * streaming replication mode, we start degenerating all backends + * as they are not replicated anymore. */ int follow_cnt = 0; if (MASTER_SLAVE && !strcmp(pool_config->master_slave_sub_mode, MODE_STREAMREP)) @@ -1715,11 +1753,25 @@ static void failover(void) pool_log("failover: set new master node: %d", Req_info->master_node_id); } - /* fork the children */ - for (i=0;i<pool_config->num_init_children;i++) + + /* Fork the children if needed */ + if (need_to_restart_children) { - process_info[i].pid = fork_a_child(unix_fd, inet_fd, i); - process_info[i].start_time = time(NULL); + for (i=0;i<pool_config->num_init_children;i++) + { + process_info[i].pid = fork_a_child(unix_fd, inet_fd, i); + process_info[i].start_time = time(NULL); + } + } + else + { + /* Set restart request to each child. Children will exit(1) + * whenever they are idle to restart. + */ + for (i=0;i<pool_config->num_init_children;i++) + { + process_info[i].need_to_restart = 1; + } } if (Req_info->kind == NODE_UP_REQUEST) diff --git a/pcp/libpcp_ext.h b/pcp/libpcp_ext.h index 2394ec361..27bc90702 100644 --- a/pcp/libpcp_ext.h +++ b/pcp/libpcp_ext.h @@ -77,7 +77,7 @@ typedef struct { int counter; /* used counter */ time_t create_time; /* connection creation time */ int load_balancing_node; /* load balancing node */ - char connected; /* true if frontend connected Please note + char connected; /* True if frontend connected. Please note * that we use "char" instead of "bool". * Since 3.1, we need to export this * structure so that PostgreSQL C @@ -97,6 +97,12 @@ typedef struct { pid_t pid; /* OS's process id */ time_t start_time; /* fork() time */ ConnectionInfo *connection_info; /* head of the connection info for this process */ + char need_to_restart; /* If non 0, exit this child process + * as soon as current session ends. + * Typical case this flag being set is + * failback a node in streaming + * replication mode. + */ } ProcessInfo; /* diff --git a/pool.h b/pool.h index c04b5ce0f..30aaef2ea 100644 --- a/pool.h +++ b/pool.h @@ -266,12 +266,13 @@ typedef struct { */ extern bool pool_is_node_to_be_sent_in_current_query(int node_id); extern int pool_virtual_master_db_node_id(void); +extern BACKEND_STATUS* my_backend_status[]; #define VALID_BACKEND(backend_id) \ - ((RAW_MODE && (backend_id) == REAL_MASTER_NODE_ID) || \ - (pool_is_node_to_be_sent_in_current_query((backend_id)) && \ - ((BACKEND_INFO((backend_id)).backend_status == CON_UP) || \ - (BACKEND_INFO((backend_id)).backend_status == CON_CONNECT_WAIT)))) + ((RAW_MODE && (backend_id) == REAL_MASTER_NODE_ID) || \ + (pool_is_node_to_be_sent_in_current_query((backend_id)) && \ + ((*(my_backend_status[(backend_id)]) == CON_UP) || \ + (*(my_backend_status[(backend_id)]) == CON_CONNECT_WAIT)))) #define CONNECTION_SLOT(p, slot) ((p)->slots[(slot)]) #define CONNECTION(p, slot) (CONNECTION_SLOT(p, slot)->con) [parent: 2ce08c51323c]