i.e. wait until all clients disconnected.
</head>
<!-- hhmts start -->
-Last modified: Thu Aug 5 12:08:51 JST 2010
+Last modified: Thu Aug 5 16:59:08 JST 2010
<!-- hhmts end -->
<body bgcolor="#ffffff">
<h3>pcp_detach_node</h3>
<pre>
Format:
-pcp_detach_node _timeout_ _host_ _port_ _userid_ _passwd_ _nodeid_
+pcp_detach_node [-g] _timeout_ _host_ _port_ _userid_ _passwd_ _nodeid_
</pre>
<p>
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).
</p>
<body>
<!-- hhmts start -->
-Last modified: Thu Aug 5 11:40:10 JST 2010
+Last modified: Thu Aug 5 16:59:41 JST 2010
<!-- hhmts end -->
<body bgcolor="#ffffff">
<p>
<pre>
\e$B=q<0!'\e(B
- pcp_detach_node _timeout_ _host_ _port_ _userid_ _passwd_ _nodeid_
+ pcp_detach_node [-g] _timeout_ _host_ _port_ _userid_ _passwd_ _nodeid_
pgpool-II\e$B$N%N!<%I$r@Z$jN%$7$^$9!#\e(B
+-g\e$B$r;XDj$9$k$H!"$9$Y$F$N%/%i%$%"%s%H$,@\B3$r=*N;$9$k$^$G%N!<%I$rI|5"$7$^$;$s!#\e(B
+(\e$B$?$@$7!"\e(Bclient_idle_limit_in_recovery \e$B$,\e(B -1 \e$B$"$k$$$O!"\e(Brecovery_timeout \e$B$,@_Dj$5$l$F$$$k>l9g$r=|$/\e(B)
</pre>
</p>
* 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
#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
*
*/
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)
{
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);
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);
* 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
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:
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();
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");
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;
}
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));
{
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;
+}
/* 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);
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];
/*
* Wait all connections are closed.
*/
-static int wait_connection_closed(void)
+int wait_connection_closed(void)
{
int i = 0;