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]