pgpool2.git / summary / log / commit / refs
commit d8d85e10d71d0eb3b774dbe06a4f3dc5b3b80b82
Author: Toshihiro Kitagawa <kitagawa at sraoss.co.jp>
Date: Thu Apr 21 01:02:51 2011 +0000
Add pcp_promote_node command.
Patch contributed by Gilles Darold.
doc/pgpool-en.html | 13 ++++
main.c | 49 ++++++++++++-
pcp/Makefile.am | 4 +-
pcp/Makefile.in | 17 ++++-
pcp/pcp.c | 98 ++++++++++++++++++++++++++
pcp/pcp.h | 2 +
pcp/pcp_promote_node.c | 185 +++++++++++++++++++++++++++++++++++++++++++++++++
pcp_child.c | 126 +++++++++++++++++++++++++++++++++
pool.h | 4 +-
9 files changed, 490 insertions(+), 8 deletions(-)
diff --git a/doc/pgpool-en.html b/doc/pgpool-en.html
index 4f600cc10..4cbd23d41 100644
--- a/doc/pgpool-en.html
+++ b/doc/pgpool-en.html
@@ -3060,6 +3060,7 @@ invalidate old query cache automatically when the data is updated.</p>
* pcp_systemdb_info - retrieves the System DB information
* pcp_detach_node - detaches a node from pgpool-II
* pcp_attach_node - attaches a node to pgpool-II
+* pcp_promote_node - promote a new master node to pgpool-II
* pcp_stop_pgpool - stops pgpool-II
</pre>
</p>
@@ -3294,6 +3295,18 @@ Attaches the given node to pgpool-II.
</pre>
</p>
+<h3>pcp_promote_node</h3>
+<p>
+<pre>
+Format:
+pcp_promote_node [-g] _timeout_ _host_ _port_ _userid_ _passwd_ _nodeid_
+
+Promotes the given node as new master to pgpool-II. In master/slave streaming replication only.
+If -g is given, wait until all clients are disconnected (unless
+client_idle_limit_in_recovery is -1 or recovery_timeout is expired).
+</pre>
+</p>
+
<h3>pcp_stop_pgpool</h3>
<pre>
Format:
diff --git a/main.c b/main.c
index b56aa402b..d4b4805de 100644
--- a/main.c
+++ b/main.c
@@ -1285,6 +1285,24 @@ void degenerate_backend_set(int *node_id_set, int count)
pool_semaphore_unlock(REQUEST_INFO_SEM);
}
+/* send promote node request using SIGUSR1 */
+void promote_backend(int node_id)
+{
+ pid_t parent = getppid();
+
+ if (pool_config->parallel_mode)
+ {
+ return;
+ }
+
+ pool_semaphore_lock(REQUEST_INFO_SEM);
+ Req_info->kind = PROMOTE_NODE_REQUEST;
+ Req_info->node_id[0] = node_id;
+ pool_log("promote_backend: %d promote node request from pid %d", node_id, getpid());
+ kill(parent, SIGUSR1);
+ pool_semaphore_unlock(REQUEST_INFO_SEM);
+}
+
/* send failback request using SIGUSR1 */
void send_failback_request(int node_id)
{
@@ -1491,6 +1509,24 @@ static void failover(void)
trigger_failover_command(node_id, pool_config->failback_command,
MASTER_NODE_ID, get_next_master_node(), PRIMARY_NODE_ID);
}
+ else if (Req_info->kind == PROMOTE_NODE_REQUEST)
+ {
+ if (Req_info->node_id[0] != -1 &&
+ VALID_BACKEND(Req_info->node_id[0]))
+ {
+ pool_log("starting promotion. promotion host %s(%d)",
+ BACKEND_INFO(Req_info->node_id[0]).backend_hostname,
+ BACKEND_INFO(Req_info->node_id[0]).backend_port);
+ }
+ else
+ {
+ pool_log("failover: no backends are promoted");
+ pool_semaphore_unlock(REQUEST_INFO_SEM);
+ kill(pcp_pid, SIGUSR2);
+ switching = 0;
+ return;
+ }
+ }
else
{
int cnt = 0;
@@ -1595,17 +1631,24 @@ static void failover(void)
MASTER_NODE_ID, new_master, PRIMARY_NODE_ID);
}
+ if (Req_info->kind == PROMOTE_NODE_REQUEST &&
+ VALID_BACKEND(Req_info->node_id[0]))
+ new_primary = Req_info->node_id[0];
+ else
+ new_primary = find_primary_node();
+
/*
* In master/slave streaming replication we start degenerating
* all backends as they are not replicated anymore
*/
int follow_cnt = 0;
- new_primary = find_primary_node();
if (MASTER_SLAVE && !strcmp(pool_config->master_slave_sub_mode, MODE_STREAMREP))
{
/* only if the failover is against the current primary */
- if ((Req_info->kind == NODE_DOWN_REQUEST) &&
- (nodes[Req_info->primary_node_id])) {
+ if (((Req_info->kind == NODE_DOWN_REQUEST) &&
+ (nodes[Req_info->primary_node_id])) ||
+ ((Req_info->kind == PROMOTE_NODE_REQUEST) &&
+ (VALID_BACKEND(Req_info->node_id[0])))) {
for (i = 0; i < pool_config->backend_desc->num_backends; i++)
{
diff --git a/pcp/Makefile.am b/pcp/Makefile.am
index bf2ca5892..f9680bcd6 100644
--- a/pcp/Makefile.am
+++ b/pcp/Makefile.am
@@ -11,7 +11,7 @@ md5.h: ../md5.h
rm -f $@ && ln -s $< .
bin_PROGRAMS = pcp_stop_pgpool pcp_node_count pcp_node_info pcp_proc_count pcp_proc_info \
- pcp_systemdb_info pcp_detach_node pcp_attach_node pcp_recovery_node
+ pcp_systemdb_info pcp_detach_node pcp_attach_node pcp_recovery_node pcp_promote_node
pcp_stop_pgpool_SOURCES = pcp_stop_pgpool.c pcp.h
pcp_stop_pgpool_LDADD = libpcp.la
pcp_stop_pgpool_LDFLAGS =
@@ -31,3 +31,5 @@ pcp_attach_node_SOURCES = pcp_attach_node.c pcp.h
pcp_attach_node_LDADD = libpcp.la
pcp_recovery_node_SOURCES = pcp_recovery_node.c pcp.h
pcp_recovery_node_LDADD = libpcp.la
+pcp_promote_node_SOURCES = pcp_promote_node.c pcp.h
+pcp_promote_node_LDADD = libpcp.la
diff --git a/pcp/Makefile.in b/pcp/Makefile.in
index d8e859b9e..2b2de093a 100644
--- a/pcp/Makefile.in
+++ b/pcp/Makefile.in
@@ -38,7 +38,7 @@ bin_PROGRAMS = pcp_stop_pgpool$(EXEEXT) pcp_node_count$(EXEEXT) \
pcp_node_info$(EXEEXT) pcp_proc_count$(EXEEXT) \
pcp_proc_info$(EXEEXT) pcp_systemdb_info$(EXEEXT) \
pcp_detach_node$(EXEEXT) pcp_attach_node$(EXEEXT) \
- pcp_recovery_node$(EXEEXT)
+ pcp_recovery_node$(EXEEXT) pcp_promote_node$(EXEEXT)
subdir = pcp
DIST_COMMON = $(include_HEADERS) $(srcdir)/Makefile.am \
$(srcdir)/Makefile.in
@@ -88,6 +88,9 @@ pcp_proc_info_DEPENDENCIES = libpcp.la
am_pcp_recovery_node_OBJECTS = pcp_recovery_node.$(OBJEXT)
pcp_recovery_node_OBJECTS = $(am_pcp_recovery_node_OBJECTS)
pcp_recovery_node_DEPENDENCIES = libpcp.la
+am_pcp_promote_node_OBJECTS = pcp_promote_node.$(OBJEXT)
+pcp_promote_node_OBJECTS = $(am_pcp_promote_node_OBJECTS)
+pcp_promote_node_DEPENDENCIES = libpcp.la
am_pcp_stop_pgpool_OBJECTS = pcp_stop_pgpool.$(OBJEXT)
pcp_stop_pgpool_OBJECTS = $(am_pcp_stop_pgpool_OBJECTS)
pcp_stop_pgpool_DEPENDENCIES = libpcp.la
@@ -113,12 +116,14 @@ SOURCES = $(libpcp_la_SOURCES) $(pcp_attach_node_SOURCES) \
$(pcp_detach_node_SOURCES) $(pcp_node_count_SOURCES) \
$(pcp_node_info_SOURCES) $(pcp_proc_count_SOURCES) \
$(pcp_proc_info_SOURCES) $(pcp_recovery_node_SOURCES) \
- $(pcp_stop_pgpool_SOURCES) $(pcp_systemdb_info_SOURCES)
+ $(pcp_stop_pgpool_SOURCES) $(pcp_systemdb_info_SOURCES) \
+ $(pcp_promote_node_SOURCES)
DIST_SOURCES = $(libpcp_la_SOURCES) $(pcp_attach_node_SOURCES) \
$(pcp_detach_node_SOURCES) $(pcp_node_count_SOURCES) \
$(pcp_node_info_SOURCES) $(pcp_proc_count_SOURCES) \
$(pcp_proc_info_SOURCES) $(pcp_recovery_node_SOURCES) \
- $(pcp_stop_pgpool_SOURCES) $(pcp_systemdb_info_SOURCES)
+ $(pcp_stop_pgpool_SOURCES) $(pcp_systemdb_info_SOURCES) \
+ $(pcp_promote_node_SOURCES)
includeHEADERS_INSTALL = $(INSTALL_HEADER)
HEADERS = $(include_HEADERS)
ETAGS = etags
@@ -266,6 +271,8 @@ pcp_attach_node_SOURCES = pcp_attach_node.c pcp.h
pcp_attach_node_LDADD = libpcp.la
pcp_recovery_node_SOURCES = pcp_recovery_node.c pcp.h
pcp_recovery_node_LDADD = libpcp.la
+pcp_promote_node_SOURCES = pcp_promote_node.c pcp.h
+pcp_promote_node_LDADD = libpcp.la
all: all-am
.SUFFIXES:
@@ -383,6 +390,9 @@ pcp_stop_pgpool$(EXEEXT): $(pcp_stop_pgpool_OBJECTS) $(pcp_stop_pgpool_DEPENDENC
pcp_systemdb_info$(EXEEXT): $(pcp_systemdb_info_OBJECTS) $(pcp_systemdb_info_DEPENDENCIES)
@rm -f pcp_systemdb_info$(EXEEXT)
$(LINK) $(pcp_systemdb_info_OBJECTS) $(pcp_systemdb_info_LDADD) $(LIBS)
+pcp_promote_node$(EXEEXT): $(pcp_promote_node_OBJECTS) $(pcp_promote_node_DEPENDENCIES)
+ @rm -f pcp_promote_node$(EXEEXT)
+ $(LINK) $(pcp_promote_node_OBJECTS) $(pcp_promote_node_LDADD) $(LIBS)
mostlyclean-compile:
-rm -f *.$(OBJEXT)
@@ -403,6 +413,7 @@ distclean-compile:
@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/pcp_stop_pgpool.Po@am__quote@
@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/pcp_stream.Plo@am__quote@
@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/pcp_systemdb_info.Po@am__quote@
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/pcp_promote_node.Po@am__quote@
.c.o:
@am__fastdepCC_TRUE@ $(COMPILE) -MT $@ -MD -MP -MF $(DEPDIR)/$*.Tpo -c -o $@ $<
diff --git a/pcp/pcp.c b/pcp/pcp.c
index 3bf7502c3..c2f26f423 100644
--- a/pcp/pcp.c
+++ b/pcp/pcp.c
@@ -50,6 +50,7 @@ static int debug = 0;
static int pcp_authorize(char *username, char *password);
static int _pcp_detach_node(int nid, bool gracefully);
+static int _pcp_promote_node(int nid, bool gracefully);
/* --------------------------------
* pcp_connect - open connection to pgpool using given arguments
@@ -1331,3 +1332,100 @@ pcp_disable_debug(void)
{
debug = 0;
}
+
+/* --------------------------------
+ * pcp_promote_node - promote a node given by the argument as new pgpool's master
+ *
+ * return 0 on success, -1 otherwise
+ * --------------------------------
+ */
+int
+pcp_promote_node(int nid)
+{
+ return _pcp_promote_node(nid, FALSE);
+}
+
+/* --------------------------------
+
+ * and promote a node given by the argument as new pgpool's master
+ *
+ * return 0 on success, -1 otherwise
+ * --------------------------------
+ */
+int
+pcp_promote_node_gracefully(int nid)
+{
+ return _pcp_promote_node(nid, TRUE);
+}
+
+static int _pcp_promote_node(int nid, bool gracefully)
+{
+ int wsize;
+ char node_id[16];
+ char tos;
+ char *buf = NULL;
+ int rsize;
+ char *sendchar;
+
+ if (pc == NULL)
+ {
+ if (debug) fprintf(stderr, "DEBUG: connection does not exist\n");
+ errorcode = NOCONNERR;
+ return -1;
+ }
+
+ snprintf(node_id, sizeof(node_id), "%d", nid);
+
+ if (gracefully)
+ sendchar = "j";
+ else
+ sendchar = "J";
+
+ 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);
+ if (pcp_flush(pc) < 0)
+ {
+ if (debug) fprintf(stderr, "DEBUG: could not send data to backend\n");
+ return -1;
+ }
+ if (debug) fprintf(stderr, "DEBUG: send: tos=\"E\", len=%d\n", ntohl(wsize));
+
+ if (pcp_read(pc, &tos, 1))
+ return -1;
+ if (pcp_read(pc, &rsize, sizeof(int)))
+ return -1;
+ rsize = ntohl(rsize);
+ buf = (char *)malloc(rsize);
+ if (buf == NULL)
+ {
+ errorcode = NOMEMERR;
+ return -1;
+ }
+ if (pcp_read(pc, buf, rsize - sizeof(int)))
+ {
+ free(buf);
+ return -1;
+ }
+ if (debug) fprintf(stderr, "DEBUG: recv: tos=\"%c\", len=%d, data=%s\n", tos, rsize, buf);
+
+ if (tos == 'e')
+ {
+ if (debug) fprintf(stderr, "DEBUG: command failed. reason=%s\n", buf);
+ errorcode = BACKENDERR;
+ }
+ else if (tos == 'd')
+ {
+ /* strcmp() for success message, or fail */
+ if(strcmp(buf, "CommandComplete") == 0)
+ {
+ free(buf);
+ return 0;
+ }
+ }
+
+ free(buf);
+ return -1;
+}
+
diff --git a/pcp/pcp.h b/pcp/pcp.h
index e18f08383..164aa6746 100644
--- a/pcp/pcp.h
+++ b/pcp/pcp.h
@@ -65,6 +65,8 @@ extern void pcp_set_timeout(long sec);
extern int pcp_recovery_node(int nid);
extern void pcp_enable_debug(void);
extern void pcp_disable_debug(void);
+extern int pcp_promote_node(int nid);
+extern int pcp_promote_node_gracefully(int nid);
/* ------------------------------
* pcp_error.c
diff --git a/pcp/pcp_promote_node.c b/pcp/pcp_promote_node.c
new file mode 100644
index 000000000..9a09376ce
--- /dev/null
+++ b/pcp/pcp_promote_node.c
@@ -0,0 +1,185 @@
+/*
+ * $Header$
+ *
+ * pgpool: a language independent connection pool server for PostgreSQL
+ * written by Tatsuo Ishii
+ *
+ * Copyright (c) 2003-2011 PgPool Global Development Group
+ *
+ * Permission to use, copy, modify, and distribute this software and
+ * its documentation for any purpose and without fee is hereby
+ * granted, provided that the above copyright notice appear in all
+ * copies and that both that copyright notice and this permission
+ * notice appear in supporting documentation, and that the name of the
+ * author not be used in advertising or publicity pertaining to
+ * distribution of the software without specific, written prior
+ * permission. The author makes no representations about the
+ * suitability of this software for any purpose. It is provided "as
+ * is" without express or implied warranty.
+ *
+ * Client program to send "promote node" command.
+ */
+
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <unistd.h>
+#ifdef HAVE_GETOPT_H
+#include <getopt.h>
+#else
+#include "getopt_long.h"
+#endif
+
+#include "pcp.h"
+
+static void usage(void);
+static void myexit(ErrorCode e);
+
+int
+main(int argc, char **argv)
+{
+ long timeout;
+ char host[MAX_DB_HOST_NAMELEN];
+ int port;
+ char user[MAX_USER_PASSWD_LEN];
+ char pass[MAX_USER_PASSWD_LEN];
+ 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, "hdg", long_options, &optindex)) != -1) {
+ switch (ch) {
+ case 'd':
+ pcp_enable_debug();
+ break;
+
+ case 'g':
+ gracefully = true;
+ break;
+
+ case 'h':
+ case '?':
+ default:
+ usage();
+ exit(0);
+ }
+ }
+ argc -= optind;
+ argv += optind;
+
+ if (argc != 6)
+ {
+ errorcode = INVALERR;
+ pcp_errorstr(errorcode);
+ myexit(errorcode);
+ }
+
+ timeout = atol(argv[0]);
+ if (timeout < 0) {
+ errorcode = INVALERR;
+ pcp_errorstr(errorcode);
+ myexit(errorcode);
+ }
+
+ if (strlen(argv[1]) >= MAX_DB_HOST_NAMELEN)
+ {
+ errorcode = INVALERR;
+ pcp_errorstr(errorcode);
+ myexit(errorcode);
+ }
+ strcpy(host, argv[1]);
+
+ port = atoi(argv[2]);
+ if (port <= 1024 || port > 65535)
+ {
+ errorcode = INVALERR;
+ pcp_errorstr(errorcode);
+ myexit(errorcode);
+ }
+
+ if (strlen(argv[3]) >= MAX_USER_PASSWD_LEN)
+ {
+ errorcode = INVALERR;
+ pcp_errorstr(errorcode);
+ myexit(errorcode);
+ }
+ strcpy(user, argv[3]);
+
+ if (strlen(argv[4]) >= MAX_USER_PASSWD_LEN)
+ {
+ errorcode = INVALERR;
+ pcp_errorstr(errorcode);
+ myexit(errorcode);
+ }
+ strcpy(pass, argv[4]);
+
+ nodeID = atoi(argv[5]);
+ if (nodeID < 0 || nodeID > MAX_NUM_BACKENDS)
+ {
+ errorcode = INVALERR;
+ pcp_errorstr(errorcode);
+ myexit(errorcode);
+ }
+
+ pcp_set_timeout(timeout);
+
+ if (pcp_connect(host, port, user, pass))
+ {
+ pcp_errorstr(errorcode);
+ myexit(errorcode);
+ }
+
+ if (gracefully)
+ sts = pcp_promote_node_gracefully(nodeID);
+ else
+ sts = pcp_promote_node(nodeID);
+
+ if (sts)
+ {
+ pcp_errorstr(errorcode);
+ pcp_disconnect();
+ myexit(errorcode);
+ }
+
+ pcp_disconnect();
+
+ return 0;
+}
+
+static void
+usage(void)
+{
+ fprintf(stderr, "pcp_promote_node - promote a node as new master from pgpool-II\n\n");
+ fprintf(stderr, "Usage: pcp_promote_node [-d][-g] timeout hostname port# username password nodeID\n");
+ fprintf(stderr, "Usage: pcp_promote_node -h\n\n");
+ fprintf(stderr, " -d, --debug : enable debug message (optional)\n");
+ fprintf(stderr, " -g, --gracefully : promote 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");
+ fprintf(stderr, " username : username for PCP authentication\n");
+ fprintf(stderr, " password : password for PCP authentication\n");
+ fprintf(stderr, " nodeID : ID of a node to be promoted\n");
+ fprintf(stderr, " -h, --help : print this help\n");
+}
+
+static void
+myexit(ErrorCode e)
+{
+ if (e == INVALERR)
+ {
+ usage();
+ exit(e);
+ }
+
+ exit(e);
+}
diff --git a/pcp_child.c b/pcp_child.c
index 768a2213b..58ae7e54e 100644
--- a/pcp_child.c
+++ b/pcp_child.c
@@ -69,6 +69,7 @@ static int user_authenticate(char *buf, char *passwd_file, char *salt, int salt_
static RETSIGTYPE wakeup_handler(int sig);
static RETSIGTYPE reload_config_handler(int sig);
static int pool_detach_node(int node_id, bool gracefully);
+static int pool_promote_node(int node_id, bool gracefully);
extern int myargc;
extern char **myargv;
@@ -826,6 +827,83 @@ pcp_do_child(int unix_fd, int inet_fd, char *pcp_conf_file)
}
break;
+ case 'J': /* promote node */
+ case 'j': /* promote node gracefully */
+ {
+ int node_id;
+ int wsize;
+ char code[] = "CommandComplete";
+ bool gracefully;
+
+ if (tos == 'J')
+ gracefully = false;
+ else
+ gracefully = true;
+
+ node_id = atoi(buf);
+ if ( (node_id < 0) || (node_id >= pool_config->backend_desc->num_backends) )
+ {
+ char code[] = "NodeIdOutOfRange";
+ pool_error("pcp_child: node id %d is not valid", node_id);
+ pcp_write(frontend, "e", 1);
+ wsize = htonl(sizeof(code) + sizeof(int));
+ pcp_write(frontend, &wsize, sizeof(int));
+ pcp_write(frontend, code, sizeof(code));
+ if (pcp_flush(frontend) < 0)
+ {
+ pool_error("pcp_child: pcp_flush() failed. reason: %s", strerror(errno));
+ exit(1);
+ }
+ exit(1);
+ }
+ /* promoting node is reserved to Streaming Replication */
+ if (!MASTER_SLAVE || (strcmp(pool_config->master_slave_sub_mode, MODE_STREAMREP) != 0))
+ {
+ char code[] = "NotInStreamingReplication";
+ pool_error("pcp_child: not in streaming replication mode, can't promote node id %d", node_id);
+ pcp_write(frontend, "e", 1);
+ wsize = htonl(sizeof(code) + sizeof(int));
+ pcp_write(frontend, &wsize, sizeof(int));
+ pcp_write(frontend, code, sizeof(code));
+ if (pcp_flush(frontend) < 0)
+ {
+ pool_error("pcp_child: pcp_flush() failed. reason: %s", strerror(errno));
+ exit(1);
+ }
+ exit(1);
+ }
+
+ if (node_id == PRIMARY_NODE_ID)
+ {
+ char code[] = "NodeIdAlreadyPrimary";
+ pool_error("pcp_child: specified node is already primary node, can't promote node id %d", node_id);
+ pcp_write(frontend, "e", 1);
+ wsize = htonl(sizeof(code) + sizeof(int));
+ pcp_write(frontend, &wsize, sizeof(int));
+ pcp_write(frontend, code, sizeof(code));
+ if (pcp_flush(frontend) < 0)
+ {
+ pool_error("pcp_child: pcp_flush() failed. reason: %s", strerror(errno));
+ exit(1);
+ }
+ exit(1);
+ }
+
+ pool_debug("pcp_child: promoting Node ID %d", node_id);
+ pool_promote_node(node_id, gracefully);
+
+ pcp_write(frontend, "d", 1);
+ wsize = htonl(sizeof(code) + sizeof(int));
+ pcp_write(frontend, &wsize, sizeof(int));
+ pcp_write(frontend, code, sizeof(code));
+ if (pcp_flush(frontend) < 0)
+ {
+ pool_error("pcp_child: pcp_flush() failed. reason: %s", strerror(errno));
+ exit(1);
+ }
+ break;
+ }
+
case 'F':
pool_debug("pcp_child: stop online recovery");
break;
@@ -1146,3 +1224,51 @@ static int pool_detach_node(int node_id, bool gracefully)
return 0;
}
+
+/* Promote a node */
+static int pool_promote_node(int node_id, bool gracefully)
+{
+ if (!gracefully)
+ {
+ promote_backend(node_id); /* send promote 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.
+ */
+ promote_backend(node_id); /* send promote 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 01f7982a3..c04b5ce0f 100644
--- a/pool.h
+++ b/pool.h
@@ -349,7 +349,8 @@ typedef enum {
NODE_UP_REQUEST = 0,
NODE_DOWN_REQUEST,
NODE_RECOVERY_REQUEST,
- CLOSE_IDLE_REQUEST
+ CLOSE_IDLE_REQUEST,
+ PROMOTE_NODE_REQUEST
} POOL_REQUEST_KIND;
typedef struct {
@@ -448,6 +449,7 @@ extern POOL_STATUS NoticeResponse(POOL_CONNECTION *frontend,
extern void notice_backend_error(int node_id);
extern void degenerate_backend_set(int *node_id_set, int count);
+extern void promote_backend(int node_id);
extern void send_failback_request(int node_id);
[parent: 52f3e7204875]