From: Tatsuo Ishii
Format: -pcp_detach_node _timeout_ _host_ _port_ _userid_ _passwd_ _nodeid_ +pcp_detach_node [-g] _timeout_ _host_ _port_ _userid_ _passwd_ _nodeid_
Detaches the given node from pgpool-II. +If -g is given, wait until all clients are disconnected (unless +client_idle_limit_in_recovery is -1 or recovery_timeout is expired).
diff --git a/doc/pgpool-ja.html b/doc/pgpool-ja.html index 691f16306..b3153815a 100644 --- a/doc/pgpool-ja.html +++ b/doc/pgpool-ja.html @@ -8,7 +8,7 @@ -Last modified: Thu Aug 5 11:40:10 JST 2010 +Last modified: Thu Aug 5 16:59:41 JST 2010 @@ -3085,9 +3085,11 @@ configure に失敗します。必ず libpq 3.0 (PostgreSQL 7.4) をリンクするよ
$B書式:
- pcp_detach_node _timeout_ _host_ _port_ _userid_ _passwd_ _nodeid_
+ pcp_detach_node [-g] _timeout_ _host_ _port_ _userid_ _passwd_ _nodeid_
pgpool-IIのノードを切り離します。
+-gを指定すると、すべてのクライアントが接続を終了するまでノードを復帰しません。
+(ただし、client_idle_limit_in_recovery が -1 あるいは、recovery_timeout が設定されている場合を除く)
diff --git a/pcp/pcp.c b/pcp/pcp.c
index 49bbb845d..1955155b3 100644
--- a/pcp/pcp.c
+++ b/pcp/pcp.c
@@ -8,7 +8,7 @@
* pgpool: a language independent connection pool server for PostgreSQL
* written by Tatsuo Ishii
*
- * Copyright (c) 2003-2008 PgPool Global Development Group
+ * Copyright (c) 2003-2010 PgPool Global Development Group
*
* Permission to use, copy, modify, and distribute this software and
* its documentation for any purpose and without fee is hereby
@@ -49,6 +49,8 @@ static int debug = 0;
#endif
static int pcp_authorize(char *username, char *password);
+static int _pcp_detach_node(int nid, bool gracefully);
+
/* --------------------------------
* pcp_connect - open connection to pgpool using given arguments
*
@@ -1078,12 +1080,31 @@ free_systemdb_info(SystemDBInfo * si)
*/
int
pcp_detach_node(int nid)
+{
+ return _pcp_detach_node(nid, FALSE);
+}
+
+/* --------------------------------
+
+ * and dettach a node given by the argument from pgpool's control
+ *
+ * return 0 on success, -1 otherwise
+ * --------------------------------
+ */
+int
+pcp_detach_node_gracefully(int nid)
+{
+ return _pcp_detach_node(nid, TRUE);
+}
+
+static int _pcp_detach_node(int nid, bool gracefully)
{
int wsize;
char node_id[16];
char tos;
char *buf = NULL;
int rsize;
+ char *sendchar;
if (pc == NULL)
{
@@ -1094,7 +1115,12 @@ pcp_detach_node(int nid)
snprintf(node_id, sizeof(node_id), "%d", nid);
- pcp_write(pc, "D", 1);
+ if (gracefully)
+ sendchar = "d";
+ else
+ sendchar = "D";
+
+ pcp_write(pc, sendchar, 1);
wsize = htonl(strlen(node_id)+1 + sizeof(int));
pcp_write(pc, &wsize, sizeof(int));
pcp_write(pc, node_id, strlen(node_id)+1);
diff --git a/pcp/pcp.h b/pcp/pcp.h
index 71d25d3ad..e18f08383 100644
--- a/pcp/pcp.h
+++ b/pcp/pcp.h
@@ -59,6 +59,7 @@ extern ProcessInfo *pcp_process_info(int pid, int *array_size);
extern SystemDBInfo *pcp_systemdb_info(void);
extern void free_systemdb_info(SystemDBInfo * si);
extern int pcp_detach_node(int nid);
+extern int pcp_detach_node_gracefully(int nid);
extern int pcp_attach_node(int nid);
extern void pcp_set_timeout(long sec);
extern int pcp_recovery_node(int nid);
diff --git a/pcp/pcp_detach_node.c b/pcp/pcp_detach_node.c
index 3be3c1bc8..b8d56d54c 100644
--- a/pcp/pcp_detach_node.c
+++ b/pcp/pcp_detach_node.c
@@ -4,7 +4,7 @@
* pgpool: a language independent connection pool server for PostgreSQL
* written by Tatsuo Ishii
*
- * Copyright (c) 2003-2008 PgPool Global Development Group
+ * Copyright (c) 2003-2010 PgPool Global Development Group
*
* Permission to use, copy, modify, and distribute this software and
* its documentation for any purpose and without fee is hereby
@@ -42,19 +42,26 @@ main(int argc, char **argv)
int nodeID;
int ch;
int optindex;
+ bool gracefully = false;
+ int sts;
static struct option long_options[] = {
{"debug", no_argument, NULL, 'd'},
+ {"gracefully", no_argument, NULL, 'g'},
{"help", no_argument, NULL, 'h'},
{NULL, 0, NULL, 0}
};
- while ((ch = getopt_long(argc, argv, "hd", long_options, &optindex)) != -1) {
+ while ((ch = getopt_long(argc, argv, "hdg", long_options, &optindex)) != -1) {
switch (ch) {
case 'd':
pcp_enable_debug();
break;
+ case 'g':
+ gracefully = true;
+ break;
+
case 'h':
case '?':
default:
@@ -127,7 +134,12 @@ main(int argc, char **argv)
myexit(errorcode);
}
- if (pcp_detach_node(nodeID))
+ if (gracefully)
+ sts = pcp_detach_node_gracefully(nodeID);
+ else
+ sts = pcp_detach_node(nodeID);
+
+ if (sts)
{
pcp_errorstr(errorcode);
pcp_disconnect();
@@ -143,9 +155,10 @@ static void
usage(void)
{
fprintf(stderr, "pcp_detach_node - detach a node from pgpool-II\n\n");
- fprintf(stderr, "Usage: pcp_detach_node [-d] timeout hostname port# username password nodeID\n");
+ fprintf(stderr, "Usage: pcp_detach_node [-d][-g] timeout hostname port# username password nodeID\n");
fprintf(stderr, "Usage: pcp_detach_node -h\n\n");
fprintf(stderr, " -d - enable debug message (optional)\n");
+ fprintf(stderr, " -g - detach gracefully(optional)\n");
fprintf(stderr, " timeout - connection timeout value in seconds. command exits on timeout\n");
fprintf(stderr, " hostname - pgpool-II hostname\n");
fprintf(stderr, " port# - PCP port number\n");
diff --git a/pcp_child.c b/pcp_child.c
index 8c4291733..1b0d4fd9f 100644
--- a/pcp_child.c
+++ b/pcp_child.c
@@ -68,6 +68,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 int pool_detach_node(int node_id, bool gracefully);
extern int myargc;
extern char **myargv;
@@ -683,14 +684,21 @@ pcp_do_child(int unix_fd, int inet_fd, char *pcp_conf_file)
}
case 'D': /* detach node */
+ case 'd': /* detach node gracefully */
{
int node_id;
int wsize;
char code[] = "CommandComplete";
+ bool gracefully;
+
+ if (tos == 'D')
+ gracefully = false;
+ else
+ gracefully = true;
node_id = atoi(buf);
pool_debug("pcp_child: detaching Node ID %d", node_id);
- notice_backend_error(node_id);
+ pool_detach_node(node_id, gracefully);
pcp_write(frontend, "d", 1);
wsize = htonl(sizeof(code) + sizeof(int));
@@ -1087,3 +1095,53 @@ static RETSIGTYPE reload_config_handler(int sig)
{
pcp_got_sighup = 1;
}
+
+/* Dedatch a node */
+static int pool_detach_node(int node_id, bool gracefully)
+{
+ pool_log("gracefully: %d", gracefully);
+
+ if (!gracefully)
+ {
+ notice_backend_error(node_id); /* send failover request */
+ return 0;
+ }
+
+ /*
+ * Wait until all frontends exit
+ */
+ *InRecovery = 1; /* This wiil ensure that new incoming
+ * connection requests are blocked */
+
+ if (wait_connection_closed())
+ {
+ /* wait timed out */
+ finish_recovery();
+ return -1;
+ }
+
+ /*
+ * Now all frontends have gone. Let's do failover.
+ */
+ notice_backend_error(node_id); /* send failover request */
+
+ /*
+ * Wait for failover completed.
+ */
+ pcp_wakeup_request = 0;
+
+ while (!pcp_wakeup_request)
+ {
+ struct timeval t = {1, 0};
+ select(0, NULL, NULL, NULL, &t);
+ }
+ pcp_wakeup_request = 0;
+
+ /*
+ * Start to accept incoming connections and send SIGUSR2 to pgpool
+ * parent to distribute SIGUSR2 all pgpool children.
+ */
+ finish_recovery();
+
+ return 0;
+}
diff --git a/pool.h b/pool.h
index 61c914b78..5e7dfa70f 100644
--- a/pool.h
+++ b/pool.h
@@ -551,6 +551,7 @@ extern const char *get_ps_display(int *displen);
/* recovery.c */
extern int start_recovery(int recovery_node);
extern void finish_recovery(void);
+extern int wait_connection_closed(void);
/* child.c */
extern void cancel_request(CancelPacket *sp);
diff --git a/recovery.c b/recovery.c
index f5af4920d..5eb41da93 100644
--- a/recovery.c
+++ b/recovery.c
@@ -41,7 +41,6 @@ static int exec_checkpoint(PGconn *conn);
static int exec_recovery(PGconn *conn, BackendInfo *backend, char stage);
static int exec_remote_start(PGconn *conn, BackendInfo *backend);
static PGconn *connect_backend_libpq(BackendInfo *backend);
-static int wait_connection_closed(void);
static int check_postmaster_started(BackendInfo *backend);
static char recovery_command[1024];
@@ -347,7 +346,7 @@ static PGconn *connect_backend_libpq(BackendInfo *backend)
/*
* Wait all connections are closed.
*/
-static int wait_connection_closed(void)
+int wait_connection_closed(void)
{
int i = 0;