Hi,

Here is the patch allowing any node in the pgpool line to be promoted
manually as the new master.

It include a new file pcp/pcp_promote_node.c

Automatic promoting of the less lagging node will be implemented later
when this first patch will be reviewed and committed.

Regards,

-- 
Gilles Darold
http://dalibo.com - http://dalibo.org

diff -rNu pgpool-II/main.c pgpool-II-promote/main.c
--- pgpool-II/main.c	2011-01-11 01:43:30.000000000 +0100
+++ pgpool-II-promote/main.c	2011-01-25 17:50:25.000000000 +0100
@@ -75,6 +75,11 @@
 			failover(); \
 			failover_request = 0; \
 		} \
+		if (promote_request) \
+		{ \
+			failover(); \
+			promote_request = 0; \
+		} \
 		if (sigchld_request) \
 		{ \
 			reaper(); \
@@ -160,6 +165,7 @@
 volatile sig_atomic_t *InRecovery; /* non 0 if recovery is started */
 volatile sig_atomic_t reload_config_request = 0;
 static volatile sig_atomic_t failover_request = 0;
+static volatile sig_atomic_t promote_request = 0;
 static volatile sig_atomic_t sigchld_request = 0;
 static volatile sig_atomic_t wakeup_request = 0;
 
@@ -1367,6 +1373,13 @@
 {
 	int i;
 
+	/* When pcp_promote_node is called we must force the new master node */
+	if (PREFERED_PRIMARY_NODE_ID > -1)
+	{
+		if (VALID_BACKEND(PREFERED_PRIMARY_NODE_ID))
+			return PREFERED_PRIMARY_NODE_ID;
+	}
+
 	for (i=0;i<pool_config->backend_desc->num_backends;i++)
 	{
 		/*
@@ -1518,7 +1531,6 @@
 			return;
 		}
 	}
-
 	new_master = get_next_master_node();
 
 	if (new_master < 0)
@@ -1591,12 +1603,6 @@
 			trigger_failover_command(i, pool_config->failover_command);
 	}
 
-	if (new_master >= 0)
-	{
-		pool_log("failover_handler: set new master node: %d", new_master);
-		Req_info->master_node_id = new_master;
-	}
-
 /* no need to wait since it will be done in reap_handler */
 #ifdef NOT_USED
 	while (wait(NULL) > 0)
@@ -1609,6 +1615,12 @@
 	memset(Req_info->node_id, -1, sizeof(int) * MAX_NUM_BACKENDS);
 	pool_semaphore_unlock(REQUEST_INFO_SEM);
 
+	/* Save primary node id */
+	Req_info->primary_node_id = find_primary_node();
+	Req_info->master_node_id = Req_info->primary_node_id;
+	pool_log("Primary node id saved: %d", Req_info->primary_node_id);
+	Req_info->prefered_primary_node_id = -1;
+
 	/* fork the children */
 	for (i=0;i<pool_config->num_init_children;i++)
 	{
@@ -1629,9 +1641,6 @@
 				 BACKEND_INFO(node_id).backend_port);
 	}
 
-	/* Save primary node id */
-	Req_info->primary_node_id = find_primary_node();
-
 	switching = 0;
 
 	/* kick wakeup_handler in pcp_child to notice that
@@ -2299,6 +2308,7 @@
 	{
 		if (!VALID_BACKEND(i))
 			continue;
+
 		/*
 		 * Check to see if this is a standby node or not
 		 */
@@ -2312,13 +2322,13 @@
 										  "");
 		if (!s)
 		{
-			pool_error("find_primary_node: make_persistent_connetcion failed");
+			pool_error("find_primary_node: make_persistent_connection failed");
 			break;
 		}
 		con = s->con;
 
-		status = do_query(con, "SELECT pg_is_in_recovery() AND pgpool_walrecrunning()",
-						  &res, PROTO_MAJOR_V3);
+		status = do_query(con, "SELECT not pg_is_in_recovery() AND not pgpool_walrecrunning();",
+					 &res, PROTO_MAJOR_V3);
 		if (res->numrows <= 0)
 		{
 			pool_log("find_primary_node: do_query returns no rows");
@@ -2331,7 +2341,7 @@
 		{
 			pool_log("find_primary_node: do_query returns NULL");
 		}
-		if (res->data[0] && !strcmp(res->data[0], "t"))
+		if (res->data[0] && !strcmp(res->data[0], "f"))
 		{
 			is_standby = true;
 		}   
@@ -2360,3 +2370,15 @@
 	pool_log("find_primary_node: primary node id is %d", i);
 	return i;
 }
+
+void notice_backend_promote(int node_id)
+{
+	int n = find_primary_node();
+
+	Req_info->prefered_primary_node_id = node_id;
+
+	pool_log("notice_backend_promote: primary node id %d will be degenerated. Node %d will be promoted as new master.", n, node_id);
+
+	degenerate_backend_set(&n, 1);
+}
+
diff -rNu pgpool-II/pcp/Makefile.am pgpool-II-promote/pcp/Makefile.am
--- pgpool-II/pcp/Makefile.am	2007-11-01 11:11:25.000000000 +0100
+++ pgpool-II-promote/pcp/Makefile.am	2011-01-25 17:50:25.000000000 +0100
@@ -11,7 +11,7 @@
 	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_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 -rNu pgpool-II/pcp/Makefile.in pgpool-II-promote/pcp/Makefile.in
--- pgpool-II/pcp/Makefile.in	2010-11-10 02:53:56.000000000 +0100
+++ pgpool-II-promote/pcp/Makefile.in	2011-01-25 17:50:25.000000000 +0100
@@ -38,7 +38,7 @@
 	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 @@
 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 @@
 	$(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_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_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 @@
 @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 -rNu pgpool-II/pcp/pcp.c pgpool-II-promote/pcp/pcp.c
--- pgpool-II/pcp/pcp.c	2010-08-06 01:37:43.000000000 +0200
+++ pgpool-II-promote/pcp/pcp.c	2011-01-25 17:50:25.000000000 +0100
@@ -50,6 +50,7 @@
 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 @@
 {
 	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 = "e";
+	else
+	  sendchar = "E";
+
+	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 -rNu pgpool-II/pcp/pcp.h pgpool-II-promote/pcp/pcp.h
--- pgpool-II/pcp/pcp.h	2010-08-05 10:08:44.000000000 +0200
+++ pgpool-II-promote/pcp/pcp.h	2011-01-25 17:50:25.000000000 +0100
@@ -65,6 +65,8 @@
 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 -rNu pgpool-II/pcp/pcp_promote_node.c pgpool-II-promote/pcp/pcp_promote_node.c
--- pgpool-II/pcp/pcp_promote_node.c	1970-01-01 01:00:00.000000000 +0100
+++ pgpool-II-promote/pcp/pcp_promote_node.c	2011-01-25 17:53:29.000000000 +0100
@@ -0,0 +1,185 @@
+/*
+ * $Header$
+ *
+ * pgpool: a language independent connection pool server for PostgreSQL 
+ * written by Tatsuo Ishii
+ *
+ * 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
+ * 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 -rNu pgpool-II/pcp_child.c pgpool-II-promote/pcp_child.c
--- pgpool-II/pcp_child.c	2010-08-06 01:37:43.000000000 +0200
+++ pgpool-II-promote/pcp_child.c	2011-01-25 17:50:25.000000000 +0100
@@ -69,6 +69,7 @@
 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,53 @@
 			}
 				break;
 
+			case 'E':			/* promote node */
+			case 'e':			/* promote node gracefully */
+			{
+				int node_id;
+				int wsize;
+				char code[] = "CommandComplete";
+				bool gracefully;
+
+				if (tos == 'E')
+					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);
+				}
+
+				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 +1194,52 @@
 
 	return 0;
 }
+
+/* Promote a node */
+static int pool_promote_node(int node_id, bool gracefully)
+{
+	if (!gracefully)
+	{
+		notice_backend_promote(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.
+	 */
+	notice_backend_promote(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 -rNu pgpool-II/pool_auth.c pgpool-II-promote/pool_auth.c
--- pgpool-II/pool_auth.c	2010-12-30 01:47:05.000000000 +0100
+++ pgpool-II-promote/pool_auth.c	2011-01-25 17:50:25.000000000 +0100
@@ -1304,7 +1304,7 @@
 		}
 		else
 		{
-			if (kind != kind0)
+			if ( (kind != kind0) && ((kind == 'E') || (kind0 == 'E')) )
 			{
 				char *message;
 
diff -rNu pgpool-II/pool.h pgpool-II-promote/pool.h
--- pgpool-II/pool.h	2010-12-30 01:47:05.000000000 +0100
+++ pgpool-II-promote/pool.h	2011-01-25 17:50:25.000000000 +0100
@@ -296,6 +296,12 @@
 #define REAL_PRIMARY_NODE_ID (Req_info->primary_node_id)
 
 /*
+ * The prefered primary node id in streaming replication mode after a failover. If not in the
+ * mode or there's no prefered primary node, this macro returns -1
+ */
+#define PREFERED_PRIMARY_NODE_ID (Req_info->prefered_primary_node_id)
+
+/*
  * "Virtual" master node id. It's same as REAL_MASTER_NODE_ID if not
  * in load balance mode. If in load balance, it's the first load
  * balance node.
@@ -348,7 +354,8 @@
 	NODE_UP_REQUEST = 0,
 	NODE_DOWN_REQUEST,
 	NODE_RECOVERY_REQUEST,
-	CLOSE_IDLE_REQUEST
+	CLOSE_IDLE_REQUEST,
+	NODE_PROMOTE_REQUEST
 } POOL_REQUEST_KIND;
 
 typedef struct {
@@ -356,6 +363,7 @@
 	int node_id[MAX_NUM_BACKENDS];		/* request node id */
 	int master_node_id;	/* the youngest node id which is not in down status */
 	int primary_node_id;	/* the primary node id in streaming replication mode */
+	int prefered_primary_node_id;	/* the prefered next primary node id in streaming replication mode */
 	int conn_counter;
 } POOL_REQUEST_INFO;
 
@@ -448,6 +456,7 @@
 extern void notice_backend_error(int node_id);
 extern void degenerate_backend_set(int *node_id_set, int count);
 extern void send_failback_request(int node_id);
+extern void notice_backend_promote(int node_id);
 
 
 extern void pool_set_timeout(int timeoutval);
diff -rNu pgpool-II/pool_query_context.c pgpool-II-promote/pool_query_context.c
--- pgpool-II/pool_query_context.c	2010-10-20 03:08:55.000000000 +0200
+++ pgpool-II-promote/pool_query_context.c	2011-01-25 17:50:25.000000000 +0100
@@ -260,13 +260,22 @@
 	sc = pool_get_session_context();
 	if (!sc)
 	{
+	    if (PREFERED_PRIMARY_NODE_ID == -1)
 		return REAL_MASTER_NODE_ID;
+	    else
+		return PREFERED_PRIMARY_NODE_ID;
 	}
 
 	if (sc->query_context)
 	{
+	    if (PREFERED_PRIMARY_NODE_ID == -1)
 		return sc->query_context->virtual_master_node_id;
+	    else
+		return PREFERED_PRIMARY_NODE_ID;
 	}
+	if (PREFERED_PRIMARY_NODE_ID >= 0)
+		return PREFERED_PRIMARY_NODE_ID;
+
 	return REAL_MASTER_NODE_ID;
 }
 
_______________________________________________
Pgpool-hackers mailing list
[email protected]
http://pgfoundry.org/mailman/listinfo/pgpool-hackers

Reply via email to