pgpool2.git / summary / log / commit / refs

commit    9afbc173a986a1957344a1084df0524bf0b3cd2f
Author:   Yoshiyuki Asaba <y-asaba at pgfoundry.org>
Date:     Mon Oct 29 05:50:11 2007 +0000

    Add new directives "recovery_1st_stage_command" and
    "recovery_2nd_stage_command".
    
    pgpool don't block client connections and data update operations while
    executing recovery_1st_stage_command. In recovery_2nd_stage_command,
    pgpool block them.
    
    If you recover by PITR, the first stage command get a base
    backup. Then you switch XLOG in the second stage command.


pgpool.conf.sample | 6 ++++++ pool.h | 2 ++ pool_config.l | 44 ++++++++++++++++++++++++++++++++++++++++++++ pool_process_query.c | 24 ++++++++++++++++++++++++ recovery.c | 32 ++++++++++++++++++++------------ 5 files changed, 96 insertions(+), 12 deletions(-) diff --git a/pgpool.conf.sample b/pgpool.conf.sample index df660c9c6..4c28cbf2b 100644 --- a/pgpool.conf.sample +++ b/pgpool.conf.sample @@ -186,3 +186,9 @@ recovery_user = 'nobody' # online recovery password recovery_password = '' + +# execute a command in first stage. +recovery_1st_stage_command = '' + +# execute a command in second stage. +recovery_2nd_stage_command = '' diff --git a/pool.h b/pool.h index f1833afa2..386159ab4 100644 --- a/pool.h +++ b/pool.h @@ -173,6 +173,8 @@ typedef struct { char *failback_command; /* execute command when failback happens */ char *recovery_user; /* PostgreSQL user name for online recovery */ char *recovery_password; /* PostgreSQL user password for online recovery */ + char *recovery_1st_stage_command; /* Online recovery command in 1st stage */ + char *recovery_2nd_stage_command; /* Online recovery command in 2nd stage */ int insert_lock; /* if non 0, automatically lock table with INSERT to keep SERIAL data consistency */ int ignore_leading_white_space; /* ignore leading white spaces of each query */ diff --git a/pool_config.l b/pool_config.l index 94b2ee587..772c2c1ea 100644 --- a/pool_config.l +++ b/pool_config.l @@ -168,6 +168,10 @@ int pool_init_config(void) pool_config->system_db_user = "pgpool"; pool_config->system_db_password = ""; pool_config->backend_desc->num_backends = 0; + pool_config->recovery_user = ""; + pool_config->recovery_password = ""; + pool_config->recovery_1st_stage_command = ""; + pool_config->recovery_2nd_stage_command = ""; res = gethostname(localhostname,sizeof(localhostname)); if(res !=0 ) @@ -776,6 +780,46 @@ int pool_get_config(char *confpath, POOL_CONFIG_CONTEXT context) pool_config->recovery_password = str; } + else if (!strcmp(key, "recovery_1st_stage_command") && + CHECK_CONTEXT(INIT_CONFIG|RELOAD_CONFIG, context)) + { + char *str; + + if (token != POOL_STRING && token != POOL_UNQUOTED_STRING && token != POOL_KEY) + { + PARSE_ERROR(); + fclose(fd); + return(-1); + } + str = extract_string(yytext, token); + if (str == NULL) + { + fclose(fd); + return(-1); + } + pool_config->recovery_1st_stage_command = str; + } + + else if (!strcmp(key, "recovery_2nd_stage_command") && + CHECK_CONTEXT(INIT_CONFIG|RELOAD_CONFIG, context)) + { + char *str; + + if (token != POOL_STRING && token != POOL_UNQUOTED_STRING && token != POOL_KEY) + { + PARSE_ERROR(); + fclose(fd); + return(-1); + } + str = extract_string(yytext, token); + if (str == NULL) + { + fclose(fd); + return(-1); + } + pool_config->recovery_2nd_stage_command = str; + } + else if (!strcmp(key, "insert_lock") && CHECK_CONTEXT(INIT_CONFIG|RELOAD_CONFIG, context)) { diff --git a/pool_process_query.c b/pool_process_query.c index 7b2598962..a8fb62d0c 100644 --- a/pool_process_query.c +++ b/pool_process_query.c @@ -3275,6 +3275,26 @@ static void process_reporting(POOL_CONNECTION *frontend, POOL_CONNECTION_POOL *b 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, "%d", pool_config->recovery_user); + strncpy(status[i].desc, "online recovery user", POOLCONFIG_MAXDESCLEN); + i++; + + strncpy(status[i].name, "recovery_password", POOLCONFIG_MAXNAMELEN); + snprintf(status[i].value, POOLCONFIG_MAXVALLEN, "%d", pool_config->recovery_password); + strncpy(status[i].desc, "online recovery password", POOLCONFIG_MAXDESCLEN); + i++; + + strncpy(status[i].name, "recovery_1st_stage_command", POOLCONFIG_MAXNAMELEN); + snprintf(status[i].value, POOLCONFIG_MAXVALLEN, "%d", 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, "%d", pool_config->recovery_2nd_stage_command); + strncpy(status[i].desc, "execute a command in second stage.", 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); @@ -5231,6 +5251,10 @@ static POOL_STATUS end_internal_transaction(POOL_CONNECTION_POOL *backend) int oldmask; #endif + /* + * We must block all signals. If pgpool SIGTERM, SIGINT or SIGQUIT + * is delivered, it possibly causes data consistensy. + */ POOL_SETMASK2(&BlockSig, &oldmask); /* We need to commit from secondary to master. */ diff --git a/recovery.c b/recovery.c index ead56d4ec..1e57acf37 100644 --- a/recovery.c +++ b/recovery.c @@ -33,7 +33,7 @@ #define WAIT_RETRY_COUNT 30 static int exec_checkpoint(PGconn *conn); -static int exec_recovery(PGconn *conn, BackendInfo *backend); +static int exec_recovery(PGconn *conn, BackendInfo *backend, char first_stage); static int exec_remote_start(PGconn *conn, BackendInfo *backend); static PGconn *connect_backend_libpq(BackendInfo *backend); static int wait_connection_closed(void); @@ -73,10 +73,9 @@ int start_recovery(int recovery_node) pool_error("start_recovery: CHECKPOINT failed"); return 1; } - if (exec_recovery(conn, recovery_backend) != 0) + if (exec_recovery(conn, recovery_backend, 1) != 0) { PQfinish(conn); - pool_error("start_recovery: rsync failed"); return 1; } @@ -95,10 +94,9 @@ int start_recovery(int recovery_node) pool_error("start_recovery: CHECKPOINT failed"); return 1; } - if (exec_recovery(conn, recovery_backend) != 0) + if (exec_recovery(conn, recovery_backend, 0) != 0) { PQfinish(conn); - pool_error("start_recovery: recovery failed"); return 1; } if (exec_remote_start(conn, recovery_backend) != 0) @@ -151,10 +149,11 @@ static int exec_checkpoint(PGconn *conn) /* * Call pgpool_recovery() function. */ -static int exec_recovery(PGconn *conn, BackendInfo *backend) +static int exec_recovery(PGconn *conn, BackendInfo *backend, char first_stage) { PGresult *result; char *hostname; + char *script; int r; if (strlen(backend->backend_hostname) == 0) @@ -162,17 +161,26 @@ static int exec_recovery(PGconn *conn, BackendInfo *backend) else hostname = backend->backend_hostname; - sprintf(recovery_command, "SELECT pgpool_recovery('%s', '%s')", - hostname, - backend->backend_data_directory); + script = first_stage ? pool_config->recovery_1st_stage_command : pool_config->recovery_2nd_stage_command; - pool_debug("exec_rsync: start recovery"); + if (script == NULL || strlen(script) == 0) + { + /* do not execute script */ + return 0; + } + + sprintf(recovery_command, "SELECT pgpool_recovery('%s', '%s', '%s')", + script, + hostname, + backend->backend_data_directory); + + pool_debug("exec_recovery: start recovery"); result = PQexec(conn, recovery_command); r = (PQresultStatus(result) != PGRES_TUPLES_OK); if (r != 0) - pool_error("exec_rsync: pgpool_recovery failed: %s", PQresultErrorMessage(result)); + pool_error("exec_recovery: pgpool_recovery failed: %s", PQresultErrorMessage(result)); PQclear(result); - pool_debug("exec_rsync: finish recovery"); + pool_debug("exec_recovery: finish recovery"); return r; } [parent: 66add488352f]