Implement pcp_detatch_node gracefull mode.
authorTatsuo Ishii <ishii at sraoss.co.jp>
Thu, 5 Aug 2010 08:08:44 +0000 (08:08 +0000)
committerTatsuo Ishii <ishii at sraoss.co.jp>
Thu, 5 Aug 2010 08:08:44 +0000 (08:08 +0000)
i.e. wait until all clients disconnected.

doc/pgpool-en.html
doc/pgpool-ja.html
pcp/pcp.c
pcp/pcp.h
pcp/pcp_detach_node.c
pcp_child.c
pool.h
recovery.c

index a55b50b993e51ff3e003eff71acac3b8cb37e641..3018e3a518df3f590b2b553585727cb48c8f24f1 100644 (file)
@@ -7,7 +7,7 @@
 </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">
@@ -2383,10 +2383,12 @@ BackendError will be displayed.</p>
 <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>
 
 
index 691f16306a6964886425a8e162417ce96f2107e5..b3153815af4c139b1c86163e570a8e5143e8ba8b 100644 (file)
@@ -8,7 +8,7 @@
 <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">
@@ -3085,9 +3085,11 @@ configure \e$B$K<:GT$7$^$9!#I,$:\e(B libpq 3.0 (PostgreSQL 7.4) \e$B$r%j%s%/$9$k$h\e
 <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>
 
index 49bbb845d9013244deb8a92177866af470412137..1955155b31e4931688e28e1c351f299f825757a6 100644 (file)
--- 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);
index 71d25d3ad579fc563b6995521cb2d679846f42b3..e18f083832e840e73590d26749bc063ea92b0dc1 100644 (file)
--- 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);
index 3be3c1bc8ef2be4cf3049993aaf94817c4428096..b8d56d54c46eb4f4fddf395ff60e035fafc8acfb 100644 (file)
@@ -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");
index 8c429173368a6278efe347851f37ca3fc1f4f588..1b0d4fd9fe8733b539cb50468bfd4d81babeb7f2 100644 (file)
@@ -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 61c914b78ad27d86b581c1670f38bd386531ac2b..5e7dfa70fa4e07865f656f810ad2a9e6a0dcb115 100644 (file)
--- 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);
index f5af4920dd5d66983a05a67a6545e384a1aa70b4..5eb41da93e9b5a71ad4b4d34966d354d7af7aa5b 100644 (file)
@@ -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;